AnsweredAssumed Answered

DMA problems on SDIO from SRAM at 0x60040094

Question asked by wieser.anthony on Jul 17, 2014
Latest reply on Jul 18, 2014 by francescato.diego
I had our SDIO code working transferring from the SRAM on the STM32F405ZGT6 to an SD Card.

Yesterday, we started to use the SRAM on the board we've built, and it's all stopped working.

We've mapped the memory like this:
bool SRAM::SDRAM_Init(void)
{
  /**
   ===============================================================================
                      ##### NOR and SRAM Controller functions #####
   ===============================================================================
  
   [..] The following sequence should be followed to configure the FSMC to interface
        with SRAM, PSRAM, NOR or OneNAND memory connected to the NOR/SRAM Bank:
  
     (#) Enable the clock for the FSMC and associated GPIOs using the following functions:
            RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);
            RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOx, ENABLE);
  
  +-------------------+--------------------+------------------+--------------+
  +                       SRAM pins assignment                               +
  +-------------------+--------------------+------------------+--------------+
  | PD0  <-> FMC_D2  | PE0  <-> FMC_NBL0 | PF0  <-> FMC_A0 | PG0 <-> FMC_A10 |
  | PD1  <-> FMC_D3  | PE1  <-> FMC_NBL1 | PF1  <-> FMC_A1 | PG1 <-> FMC_A11 |
  | PD4  <-> FMC_NOE | PE3  <->          | PF2  <-> FMC_A2 | PG2 <-> FMC_A12 |
  | PD5  <-> FMC_NWE | PE4  <->          | PF3  <-> FMC_A3 | PG3 <-> FMC_A13 |
  | PD8  <-> FMC_D13 | PE7  <-> FMC_D4   | PF4  <-> FMC_A4 | PG4 <-> FMC_A14 |
  | PD9  <-> FMC_D14 | PE8  <-> FMC_D5   | PF5  <-> FMC_A5 | PG5 <-> FMC_A15 |
  | PD10 <-> FMC_D15 | PE9  <-> FMC_D6   | PF12 <-> FMC_A6 |                 |
  | PD11 <-> FMC_A16 | PE10 <-> FMC_D7   | PF13 <-> FMC_A7 |-----------------+
  | PD12 <-> FMC_A17 | PE11 <-> FMC_D8   | PF14 <-> FMC_A8 |
  | PD13 <->         | PE12 <-> FMC_D9   | PF15 <-> FMC_A9 |
  | PD14 <-> FMC_D0  | PE13 <-> FMC_D10  |-----------------+
  | PD15 <-> FMC_D1  | PE14 <-> FMC_D11  |
  |                  | PE15 <-> FMC_D12  |
  +------------------+------------------+
  */
  
  
//  RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);
  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
  
  /*(#) FSMC pins configuration
           (++) Connect the involved FSMC pins to AF12 using the following function
                GPIO_PinAFConfig(GPIOx, GPIO_PinSourcex, GPIO_AF_FSMC);
           (++) Configure these FSMC pins in alternate function mode by calling the function
                GPIO_Init();
           */
  
  GPIO_InitTypeDef GPIO_InitStructure;
  
  ClockAHB1Periph clk_gpiod(RCC_AHB1Periph_GPIOD, GPIOD);
  ClockAHB1Periph clk_gpioe(RCC_AHB1Periph_GPIOE, GPIOE);
  ClockAHB1Periph clk_gpiof(RCC_AHB1Periph_GPIOF, GPIOF);
  ClockAHB1Periph clk_gpiog(RCC_AHB1Periph_GPIOG, GPIOG);
  
  // Tried all pins as pull up, some example code had them as nopull
  Pin pd0(clk_gpiod, 0, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd1(clk_gpiod, 1, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd4(clk_gpiod, 4, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd5(clk_gpiod, 5, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd7(clk_gpiod, 7, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd8(clk_gpiod, 8, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd9(clk_gpiod, 9, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd10(clk_gpiod, 10, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd11(clk_gpiod, 11, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd12(clk_gpiod, 12, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd14(clk_gpiod, 14, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pd15(clk_gpiod, 15, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  
  Pin pe0(clk_gpioe, 0, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pe1(clk_gpioe, 1, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pe7(clk_gpioe, 7, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pe8(clk_gpioe, 8, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pe9(clk_gpioe, 9, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pe10(clk_gpioe, 10, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pe11(clk_gpioe, 11, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pe12(clk_gpioe, 12, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pe13(clk_gpioe, 13, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pe14(clk_gpioe, 14, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pe15(clk_gpioe, 15, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  
  Pin pf0(clk_gpiof, 0, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pf1(clk_gpiof, 1, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pf2(clk_gpiof, 2, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pf3(clk_gpiof, 3, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pf4(clk_gpiof, 4, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pf5(clk_gpiof, 5, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pf12(clk_gpiof, 12, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pf13(clk_gpiof, 13, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pf14(clk_gpiof, 14, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pf15(clk_gpiof, 15, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  
  Pin pg0(clk_gpiog, 0, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pg1(clk_gpiog, 1, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pg2(clk_gpiog, 2, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pg3(clk_gpiog, 3, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pg4(clk_gpiog, 4, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  Pin pg5(clk_gpiog, 5, GPIO_Mode_AF, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL, GPIO_AF_FSMC);
  
  /*
     (#) Declare a FSMC_NORSRAMInitTypeDef structure, for example:
            FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;
        and fill the FSMC_NORSRAMInitStructure variable with the allowed values of
        the structure member.
    */
  
  FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;
  FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1;
  FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
  FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM;
  FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
  FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
  FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
  FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
  FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
  FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
  FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
  FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
  FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
  FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
  
  FSMC_NORSRAMTimingInitTypeDef readWriteTimingStruct;
  readWriteTimingStruct.FSMC_AddressSetupTime = 0;
  readWriteTimingStruct.FSMC_AddressHoldTime = 0;
  readWriteTimingStruct.FSMC_DataSetupTime = 1;
  readWriteTimingStruct.FSMC_BusTurnAroundDuration = 1;
  readWriteTimingStruct.FSMC_CLKDivision = 0;
  readWriteTimingStruct.FSMC_DataLatency = 0;
  readWriteTimingStruct.FSMC_AccessMode = FSMC_AccessMode_A;
  
  FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTimingStruct;
  FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTimingStruct;
  
  FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
  
  RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);
  
  FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);
  
}

And this is the code we're using to start a block transfer:
void SDCard::StartBlockTransfer(uint8_t *buf, uint32_t cnt, uint32_t dir)
{
  //cnt must be integer multiple of 512!!! I will enforce this inside this function
  //Starts the actual data tranfer using the DMA.
  //Prior to calling this command. The SDCard must have been adjusted using commands
  uint32_t tempreg;
  
  //Make cnt an integer multiple of 512
  //Then mask it with the maximum value allowed (2^24)
  cnt = 0x01FFFFFF & ((cnt >> 8) << 8);
  
  /////PART I::::Adjust the DMA
  //Reset the control register (0x00 is the default value. this also disables the dma. When EN=0, it stops any ongoing DMA transfer)
  DMA2_Stream3->CR = 0;
  
  //Clear all the flags
  DMA2->LIFCR = DMA_LIFCR_CTCIF3 | DMA_LIFCR_CTEIF3 | DMA_LIFCR_CDMEIF3
      | DMA_LIFCR_CFEIF3 | DMA_LIFCR_CHTIF3;
  
  
  
  //Set the DMA Addresses
  DMA2_Stream3->PAR = ((uint32_t)&SDIO->FIFO); //SDIO FIFO Address (=SDIO Base+0x80)
   DMA2_Stream3->M0AR = (uint32_t) buf;    //Memory address
  
  //Set the number of data to transfer
  DMA2_Stream3->NDTR = 0; //Peripheral controls, therefore we don't need to indicate a size
  
  //Set the DMA CR
  tempreg = (((0x04 << 25) & DMA_SxCR_CHSEL)  //Select Channel 4
          | ((0x01 << 23) & DMA_SxCR_MBURST) //4 beat memory burst (memory is 32word. Therefore, each time dma access memory, it reads 4*32 bits) (FIFO size must be integer multiple of memory burst)(FIFO is 4byte. Therefore we can only use 4 beat in this case)
  //Note: Ref manual (p173 (the node at the end of 8.3.11) says that burst mode is not allowed when Pinc=0. However, it appears that this is not true at all. Furthermore. when I set pBurst=0, the SDIO's dma control does not work at all.)
          | ((0x01 << 21) & DMA_SxCR_PBURST) //4 beat memory burst Mode ([Burst Size*Psize] must be equal to [FIFO size] to prevent FIFO underrun and overrun errors) (burst also does not work in direct mode).
          | ((0x00 << 18) & DMA_SxCR_DBM) //Disable double buffer mode (when this is set, circluar mode is also automatically set. (the actual value is don't care)
          | ((0x03 << 16) & DMA_SxCR_PL)     //Priority is very_high
          | ((0x00 << 15) & DMA_SxCR_PINCOS) //Peripheral increment offset (if this is 1 and Pinc=1, then Peripheral will be incremented by 4 regardless of Psize)
          | ((0x02 << 13) & DMA_SxCR_MSIZE) //Memory data size is 32bit (word)
          | ((0x02 << 11) & DMA_SxCR_PSIZE) //Peripheral data size is 32bit (word)
          | ((0x01 << 10) & DMA_SxCR_MINC)  //Enable Memory Increment
          | ((0x00 << 9) & DMA_SxCR_MINC)  //Disable Peripheral Increment
          | ((0x00 << 8) & DMA_SxCR_CIRC)   //Disable Circular mode
      //  | ((0x00<<6) & DMA_SxCR_DIR)  //Direction 0:P2M, 1:M2P
          | ((0x01 << 5) & DMA_SxCR_PFCTRL)); //Peripheral controls the flow control. (The DMA tranfer ends when the data issues end of transfer signal regardless of ndtr value)
  //Bit [4..1] is for interupt mask. I don't use interrupts here
  //Bit 0 is EN. I will set it after I set the FIFO CR. (FIFO CR cannot be modified when EN=1)
  DMA2_Stream3->CR = tempreg;
  
  //Set the FIFO CR
  tempreg = 0x21 //Reset value
          | (0 << 7) //FEIE is disabled
          | (1 << 2) //Fifo is enabled (Direct mode is disabled);
          | 3;   //Full fifo (Fifo threshold selection)
  DMA2_Stream3->FCR = tempreg;
  
  //Set the Direction of transfer
  if (dir == WRITE_TO_CARD)
  {
    DMA2_Stream3->CR |= (0x01 << 6) & DMA_SxCR_DIR;
  }
  else if (dir == READ_FROM_CARD)
  {
    DMA2_Stream3->CR |= (0x00 << 6) & DMA_SxCR_DIR;
  }
  
  //Enable the DMA (When it is enabled, it starts to respond dma requests)
  DMA2_Stream3->CR |= DMA_SxCR_EN;
  //END of PART I
  
  ////PART II::::Adjust and enable SDIO Peripheral
  //Clear the Data status flags
  SDIO->ICR = (SDIO_STA_DCRCFAIL | SDIO_STA_DTIMEOUT | SDIO_STA_TXUNDERR
      | SDIO_STA_RXOVERR | SDIO_STA_DATAEND | SDIO_STA_STBITERR
      | SDIO_STA_DBCKEND);
  
  //First adjust the Dtimer and Data length
  SDIO->DTIMER = (uint32_t) DATATIMEOUT;
  SDIO->DLEN = cnt;
  
  //Now adjust DCTRL (and enable it at the same time)
  tempreg = (uint32_t) 9 << 4 //Block size is 512 Compute log2(BlockSize) and shift 4bit
          | 1 << 3 //Enable the DMA
          | 0 << 2 //DTMode=Block Transfer (Actualy this is the reset value. Just a remainder)
          | (dir & SDIO_DCTRL_DTDIR) //Direction. 0=Controller to card, 1=Card to Controller
          | 1; //DPSM is enabled
  //Keep the rest at 0 => OTher SDIO functions is disabled(we don't need them)
  SDIO->DCTRL = tempreg;
  //End of PART II
}

What I'm seeing is the write generate a FIFO error on the SDIO card:
Here's the Register Value's
"DMA2_Stream3"  0x40026458  
    CR  144921697   
    NDTR    65531   
    PAR 1073818752  
    M0AR    1610875028  
    M1AR    0   
    FCR 47
      
"DMA2_Stream3->M0AR"    0x60040094  
"DMA2->LISR"    0x400000    
"DMA2_Stream3->PAR" 0x40012c80  
"DMA2_Stream3->CR"  0x8a35461   
"DMA2_Stream3->FCR" 0x2f    
  
"SDIO"  0x40012c00  
    POWER   3   
    CLKCR   2304    
    ARG 2048    
    CMD 1112    
    RESPCMD 24  
    RESP1   2304    
    RESP2   1532559360  
    RESP3   993492864   
    RESP4   171983022   
    DTIMER  16777215    
    DLEN    512 
    DCTRL   153 
    DCOUNT  496 
    STA 80  
    ICR 0   
    MASK    1026    
    RESERVED0   0x40012c40  
    FIFOCNT 0   
    RESERVED1   0x40012c4c  
    FIFO    1297040219  

The value in the FIFO is
"SDIO->FIFO" 0x4d4f435b 
which is exactly what's at our memory location 60040094, which is where the transfer began.



Outcomes