0
\$\begingroup\$

Back at it again, however this time not sure what the problem is.

I have a PMODI2S2 device that is an Audio codec. It interfaces with the STM32H753ZI Microcontroller VIA SPI/I2S.

The problem that is currently occurring is the DMA transfers aren't doing anything.

The way I know this is I setup a UART3 with DMA to send values to the MAC terminal using the "Screen" command. Nothing gets sent, and the live expressions within the IDE says the array is empty.

The list of probable cause is:

  • The IRQHandler never triggers so the code to transer from Rx -> Tx never happens
  • The DATA size to send between the MCU and hardware could be set up wrong and doesnt know when to request the DMA to Tx (to Fill up) or Rx (To Empty).
  • I clearly messed up on the setup for I2S and/or DMA for this.

What works thus far:

  • MCLK is present @ ~24.576MHz is the Green Signal
  • FWS is present @ ~96kHz is the Yellow Signal
  • SCLK is present @ ~6.144MHz is the Blue Signal
  • UART3 DMA does send messages. Tested it by just sending random data. It was shown in terminal.

PICTURES: enter image description here enter image description here

CODE:

void init_I2S(){

    //Setting Clock for 98.304MHz
    //N = 122
    //P = 8
    //M = 10
    //FRACT = 7209

    // RCC_PLL2DIVR
    // MASKING:
    RCC -> PLL2DIVR &= ~RCC_PLL2DIVR_P2;
    RCC -> PLL2DIVR &= ~RCC_PLL2DIVR_N2;
    // WRITING:
    RCC -> PLL2DIVR |= RCC_PLL2DIVR_P2_DIV8;
    RCC -> PLL2DIVR |= RCC_PLL2DIVR_N2_MULT122;

    // RCC_PLLCKSELR
    // MASKING:
    RCC -> PLLCKSELR &= ~RCC_PLLCKSELR_DIVM2;
    // WRITING:
    RCC -> PLLCKSELR |= RCC_PLLCKSELR_DIVM2_DIV10;

    // RCC_PLL2FRACR
    // MASKING:
    RCC -> PLL2FRACR &= ~RCC_PLL2FRACR_FRACN2;
    // WRITING:
    RCC -> PLL2FRACR |= RCC_PLL2FRACR_FRACN_7209;

    // RCC_PLLCFGR
    // MASKING:
    RCC -> PLLCFGR &= ~RCC_PLLCFGR_DIVP2EN;
    RCC -> PLLCFGR &= ~RCC_PLLCFGR_PLL2RGE;
    RCC -> PLLCFGR &= ~RCC_PLLCFGR_PLL2VCOSEL;
    RCC -> PLLCFGR &= ~RCC_PLLCFGR_PLL2FRACEN;
    // WRITING:
    RCC -> PLLCFGR |= RCC_PLLCFGR_DIVP2EN;
    RCC -> PLLCFGR |= RCC_PLLCFGR_PLL2RGE_4_8;
    RCC -> PLLCFGR |= RCC_PLLCFGR_PLL2VCOSEL_192_836;
    RCC -> PLLCFGR |= RCC_PLLCFGR_PLL2FRACEN;

    // RCC_CR
    // MASKING:
    RCC -> CR &= ~RCC_CR_PLL2ON;
    // WRITING:
    RCC -> CR |= RCC_CR_PLL2ON;
    // WAITING:
    while (((RCC -> CR) & (RCC_CR_PLL2RDY)) == 0){};

    // ENALBING CLOCKS

    // RCC_AHB4ENR
    // MASKING:
    RCC -> AHB4ENR &= ~ RCC_AHB4ENR_GPIOAEN;
    RCC -> AHB4ENR &= ~ RCC_AHB4ENR_GPIOCEN;
    // WRITING:
    RCC -> AHB4ENR |= RCC_AHB4ENR_GPIOAEN;
    RCC -> AHB4ENR |= RCC_AHB4ENR_GPIOCEN;

    // RCC_APB2ENR
    // MASKING:
    RCC -> APB2ENR &= ~RCC_APB2ENR_SPI1EN;
    // WRITING:
    RCC -> APB2ENR |= RCC_APB2ENR_SPI1EN;

    // CHANGING CLOCKS OF PERIPHERALS
    // RCC_D2CCIP1R
    // MASKING;
    RCC -> D2CCIP1R &= ~RCC_D2CCIP1R_SPI123SEL;
    // WRITING:
    RCC -> D2CCIP1R |=  RCC_D2CCIP1R_SPI123SEL_PLL2_P_CK;

    // CHANGING GPIO PINS TO ALETERNATIVE
    // GPIOx_MODER
    // MASKING
    GPIOA -> MODER &= ~GPIO_MODER_MODE4;
    GPIOA -> MODER &= ~GPIO_MODER_MODE5;
    GPIOA -> MODER &= ~GPIO_MODER_MODE6;
    GPIOA -> MODER &= ~GPIO_MODER_MODE7;
    GPIOC -> MODER &= ~GPIO_MODER_MODE4;
    // WRITING:
    GPIOA -> MODER |= GPIO_MODER_MODE4_ALT;
    GPIOA -> MODER |= GPIO_MODER_MODE5_ALT;
    GPIOA -> MODER |= GPIO_MODER_MODE6_ALT;
    GPIOA -> MODER |= GPIO_MODER_MODE7_ALT;
    GPIOC -> MODER |= GPIO_MODER_MODE4_ALT;

    //SETTING ALT FUNCTIONS TO PINS
    // GPIOx_AFRL
    // MASKING:
    GPIOA -> AFR[0] &= ~GPIO_AFRL_AFSEL4;
    GPIOA -> AFR[0] &= ~GPIO_AFRL_AFSEL5;
    GPIOA -> AFR[0] &= ~GPIO_AFRL_AFSEL6;
    GPIOA -> AFR[0] &= ~GPIO_AFRL_AFSEL7;
    GPIOC -> AFR[0] &= ~GPIO_AFRL_AFSEL4;
    // WRITING;
    GPIOA -> AFR[0] |= GPIO_AFRL_AFSEL4_AF5;
    GPIOA -> AFR[0] |= GPIO_AFRL_AFSEL5_AF5;
    GPIOA -> AFR[0] |= GPIO_AFRL_AFSEL6_AF5;
    GPIOA -> AFR[0] |= GPIO_AFRL_AFSEL7_AF5;
    GPIOC -> AFR[0] |= GPIO_AFRL_AFSEL4_AF5;

    // ENABLING DMA1
    // RCC_AHB1ENR
    // MASKING:
    RCC -> AHB1ENR &= ~RCC_AHB1ENR_DMA1EN;
    // WRITING:
    RCC -> AHB1ENR |= RCC_AHB1ENR_DMA1EN;

    // SETTING UP DMA FOR I2S
    // DMAMUX1_Channel0_CCR
    // DMAMUX1_Channel1_CCR
    // NOTE: Using DMAMUX1 -> DMA1_Channel 0 & 1
    // 0x25 = Rx | 0x26 = Tx
    // MASKING:
    DMAMUX1_Channel0 -> CCR &= ~DMAMUX_CxCR_DMAREQ_ID;
    DMAMUX1_Channel1 -> CCR &= ~DMAMUX_CxCR_DMAREQ_ID;
    // WRITING:
    DMAMUX1_Channel0 -> CCR |= DMAMUX_CxCR_DMAREQ_ID_SPI1_Rx; //Rx
    DMAMUX1_Channel1 -> CCR |= DMAMUX_CxCR_DMAREQ_ID_SPI1_Tx; //Tx

    // DMA1_Stream0_CR
    // DMA1_Stream1_CR
    // MASKING:
    DMA1_Stream0 -> CR &= ~DMA_SxCR_CT;
    DMA1_Stream0 -> CR &= ~DMA_SxCR_PL;
    DMA1_Stream0 -> CR &= ~DMA_SxCR_MSIZE;
    DMA1_Stream0 -> CR &= ~DMA_SxCR_PSIZE;
    DMA1_Stream0 -> CR &= ~DMA_SxCR_MINC;
    DMA1_Stream0 -> CR &= ~DMA_SxCR_CIRC;
    DMA1_Stream0 -> CR &= ~DMA_SxCR_DIR;
    DMA1_Stream0 -> CR &= ~DMA_SxCR_PFCTRL;
    DMA1_Stream0 -> CR &= ~DMA_SxCR_TCIE;
    DMA1_Stream0 -> CR &= ~DMA_SxCR_HTIE;

    DMA1_Stream1 -> CR &= ~DMA_SxCR_CT;
    DMA1_Stream1 -> CR &= ~DMA_SxCR_PL;
    DMA1_Stream1 -> CR &= ~DMA_SxCR_MSIZE;
    DMA1_Stream1 -> CR &= ~DMA_SxCR_PSIZE;
    DMA1_Stream1 -> CR &= ~DMA_SxCR_MINC;
    DMA1_Stream1 -> CR &= ~DMA_SxCR_CIRC;
    DMA1_Stream1 -> CR &= ~DMA_SxCR_DIR;
    DMA1_Stream1 -> CR &= ~DMA_SxCR_PFCTRL;
    // WRITING:
    DMA1_Stream0 -> CR |= DMA_SxCR_CT_MEM0;
    DMA1_Stream0 -> CR |= DMA_SxCR_PL_Very_High;
    DMA1_Stream0 -> CR |= DMA_SxCR_MSIZE_32BIT;
    DMA1_Stream0 -> CR |= DMA_SxCR_PSIZE_32BIT;
    DMA1_Stream0 -> CR |= DMA_SxCR_MINC;
    DMA1_Stream0 -> CR |= DMA_SxCR_CIRC;
    DMA1_Stream0 -> CR |= DMA_SxCR_DIR_P_TO_M;
    DMA1_Stream0 -> CR |= DMA_SxCR_PFCTRL_DMAFLOW;
    DMA1_Stream0 -> CR |= DMA_SxCR_TCIE;
    DMA1_Stream0 -> CR |= DMA_SxCR_HTIE;

    DMA1_Stream1 -> CR |= DMA_SxCR_CT_MEM0;
    DMA1_Stream1 -> CR |= DMA_SxCR_PL_Very_High;
    DMA1_Stream1 -> CR |= DMA_SxCR_MSIZE_32BIT;
    DMA1_Stream1 -> CR |= DMA_SxCR_PSIZE_32BIT;
    DMA1_Stream1 -> CR |= DMA_SxCR_MINC;
    DMA1_Stream1 -> CR |= DMA_SxCR_CIRC;
    DMA1_Stream1 -> CR |= DMA_SxCR_DIR_M_TO_P;
    DMA1_Stream1 -> CR |= DMA_SxCR_PFCTRL_DMAFLOW;

    // DMA_SxNDTR
    // WRITING:
    DMA1_Stream0 -> NDTR = 0x08;
    DMA1_Stream1 -> NDTR = 0x08;

    // DMA_SxPAR
    // WRITING:
    DMA1_Stream0 -> PAR = (uint32_t)&SPI1->RXDR;
    DMA1_Stream1 -> PAR = (uint32_t)&SPI1->TXDR;

    // DMA_SxM0AR
    // WRITING:
    DMA1_Stream0 -> M0AR = (uint32_t)RxBuff;
    DMA1_Stream1 -> M0AR = (uint32_t)TxBuff;

    // DMA_SxCR
    // WRITING:
    DMA1_Stream0 ->CR |= DMA_SxCR_EN;
    DMA1_Stream1 ->CR |= DMA_SxCR_EN;

    // Setting up the SPI/I2S Peripheral
    // MASKING:
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_MCKOE;
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_ODD;
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_I2SDIV;
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_DATFMT;
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_WSINV;
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_DATLEN;
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_CHLEN;
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_CKPOL;
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_I2SSTD;
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_I2SCFG;
    SPI1 -> I2SCFGR &= ~SPI_I2SCFGR_I2SMOD;
    SPI1 -> CFG1    &= ~SPI_CFG1_RXDMAEN;
    SPI1 -> CFG1    &= ~SPI_CFG1_TXDMAEN;
    SPI1 -> CFG1    &= ~SPI_CFG1_FTHLV;
    // WRITING:
    SPI1 -> I2SCFGR |= SPI_I2SCFGR_MCKOE;
    SPI1 -> I2SCFGR |= SPI_I2SCFGR_ODD_MULT2;
    SPI1 -> I2SCFGR |= SPI_I2SCFGR_I2SDIV_2;
    SPI1 -> I2SCFGR |= SPI_I2SCFGR_DATFMT_RAlign;
    SPI1 -> I2SCFGR |= SPI_I2SCFGR_WSINV_I2S;
    SPI1 -> I2SCFGR |= SPI_I2SCFGR_DATALEN_24BIT;
    SPI1 -> I2SCFGR |= SPI_I2SCFGR_CKPOL_FALL_RISE;
    SPI1 -> I2SCFGR |= SPI_I2SCFGR_I2SSTD_I2STAND;
    SPI1 -> I2SCFGR |= SPI_I2SCFGR_I2SCFG_MASTER_TRANSMIT;
    SPI1 -> I2SCFGR |= SPI_I2SCFGR_I2SMOD_I2S_PCM_MODE;
    SPI1 -> CFG1 |= SPI_CFG1_RXDMAEN;
    SPI1 -> CFG1 |= SPI_CFG1_TXDMAEN;
    SPI1 ->  CR1 |= SPI_CR1_SPE;
    SPI1 ->  CR1 |= SPI_CR1_CSTART;

}

Main:

uint16_t RxBuff[8];
uint16_t TxBuff[8];
uint8_t TC_Callback = 0;
uint8_t HC_Callback = 0;
char uartBuff[8];

void DMA1_Stream0_IRQHandler(void) {

    if ((DMA1 -> LISR & DMA_LISR_TCIF0) == 1){
        DMA1 -> LIFCR |= DMA_LIFCR_CTCIF0;
        TC_Callback = 1;
    }

    if ((DMA1 -> LISR & DMA_LISR_HTIF0) == 1){
         DMA1 -> LIFCR |= DMA_LIFCR_CHTIF0;
         HC_Callback = 1;
    }
}

int main(void) {

    init_Clock();
    init_I2S();
    init_Debugging();

  while (1)
  {



      if (HC_Callback == 1){

          for (int i = 0; i < 4; i++){
              TxBuff[i] = RxBuff[i];
              uartBuff[0] = i;
          }
          HC_Callback = 0;

      } else if (TC_Callback == 1){

          for (int i = 4; i < 8; i++){
               TxBuff[i] = RxBuff[i];
          }
          TC_Callback = 0;

      }
  }

}

UPDATE 1:

Looks like I forgot to enable the Interrupt that goes into the handler. Added to code. Same thing is happening. Its not triggering the interrupt.

void init_Interrupt(){

    NVIC_EnableIRQ(DMA1_Stream0_IRQn);
    NVIC_SetPriority(DMA1_Stream0_IRQn,0);
}

UPDATE 2:

Tried re-writing the driver for the SPI/I2S but this time using the example in the reference manual. Nothing.

Working backwards, I have taken out the DMA interrupts, nothing. Then I took out the DMA entirely still doesnt work. I have notice in every case scenario the SPI->RxDR register doesnt fill up what so ever.

UPDATE 3:

Tried setting it up with HAL drivers. stuck in the exactly same place as Bare metal. Looks like the Rx buffer doesnt want to retrieve anything.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

The solution was changing

SPI1 -> I2SCFGR |= SPI_I2SCFGR_I2SCFG_MASTER_TRANSMIT;

to

SPI1 -> I2SCFGR |= SPI_I2SCFGR_I2SCFG_MASTER_FULL_DUPLEX

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.