cancel
Showing results for 
Search instead for 
Did you mean: 

Using SDMMC_TRANSFER_MODE_STREAM with SDMMC1 on STMH7

Hueli.1
Associate III

I am using the STMH7A3ZI-Q Nucleo Board together with the WFM200S Silicon Labs WiFi Board.

The example project of the WFM200S uses the deprecated SDIO library with an F4 Nucelo ( (https://github.com/SiliconLabs/wfx-fullMAC-tools/tree/wifi_examples_ssv4))

I would like to adapt the code to work with the STMH7. Currently the following works:

  • Data End Interrupt arrives and the SDMMC1_IRQHandler is called when interrupts are enabled
  • I can also read directly from the FIFO with some issues where I receive the same data several times.

My questions/issues:

  • DMA: I adapted the example code for the SDIO read of the original example to use the same method as the SD function HAL_SD_ReadBlocks_DMA() but this DMA transfer does not work somehow (the variable at defined adress SDMMC1->IDMABASE0 just remains unchanged)
    • Do I need to enable the MDMA or something similar like DMA Streams in the original example? (when MDMA was enabled as on image its callback was never called)
  • In general is using SDMMC_TRANSFER_MODE_STREAM even possible with SDMMC1? Or do I need to use BLOCK mode always?


_legacyfs_online_stmicro_images_0693W00000bi7yjQAA.png 

Original code:

sl_status_t sl_wfx_host_sdio_read_cmd53 (uint8_t function,
                                         uint32_t address,
                                         uint8_t* buffer,
                                         uint16_t buffer_length) {    
  SDIO_CmdInitTypeDef command;
  SDIO_DataInitTypeDef config;
  
  SDIO->DCTRL = 0U;  
  
  if(buffer_length >= SL_WFX_SDIO_BLOCK_MODE_THRESHOLD) {
    uint32_t block_count = ( buffer_length / SL_WFX_SDIO_BLOCK_SIZE ) + ( ( ( buffer_length % SL_WFX_SDIO_BLOCK_SIZE ) == 0 ) ? 0 : 1 );
    command.Argument = SDIO_CMD53_BLOCK_MODE | SDIO_CMD53_COUNT(block_count);
    config.TransferMode  = SDIO_TRANSFER_MODE_BLOCK;
    config.DataBlockSize = sdio_optimal_block_size(SL_WFX_SDIO_BLOCK_SIZE);
  } else {
    command.Argument = SDIO_CMD53_COUNT(buffer_length);
    config.TransferMode  = SDIO_TRANSFER_MODE_STREAM;
    config.DataBlockSize = sdio_optimal_block_size(buffer_length);
  }
  command.Argument |= SDIO_CMD53_FUNCTION( function ) | SDIO_CMD53_OPMODE_INCREASING_ADDRESS | SDIO_CMD53_ADDRESS( address );
  config.TransferDir   = SDIO_TRANSFER_DIR_TO_SDIO;
  
  SDIO->DCTRL |= SDIO_DCTRL_SDIOEN;
  /* Prepare Data */
  config.DataTimeOut   = SDMMC_DATATIMEOUT;
  config.DataLength    = buffer_length;
  config.DPSM          = SDIO_DPSM_ENABLE;
  SDIO_ConfigData(SDIO, &config);
  
  __SDIO_ENABLE_IT(SDIO, SDIO_IT_DATAEND);
  hdma_sdio_rx.XferCpltCallback = SDIO_receive_cplt;
  HAL_DMA_Start_IT(&hdma_sdio_rx, (uint32_t)&SDIO->FIFO, (uint32_t)buffer, (uint32_t)buffer_length/4);
  __SDIO_DMA_ENABLE(SDIO);
  
  /* Prepare SDIO command */ 
  command.CmdIndex         = SDMMC_CMD_SDMMC_RW_EXTENDED;
  command.Response         = SDIO_RESPONSE_SHORT;
  command.WaitForInterrupt = SDIO_WAIT_NO;
  command.CPSM             = SDIO_CPSM_ENABLE;
  SDIO_SendCommand(SDIO, &command);
  SDMMC_GetCmdResp(SDIO);
  uint32_t response_flags = SDIO_GetResponse(SDIO, SDIO_RESP1);
  if (((response_flags>> 😎 & 0xFF) != 0x20) {
    return SL_STATUS_FAIL;
  }
  return SL_STATUS_OK;
}
 
 
------------------------------ IRQ handler -----------------------------
void SDIO_IRQHandler (void) {
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  
  if (((SDIO->MASK & SDIO_IT_SDIOIT) == SDIO_IT_SDIOIT)
      && (__SDIO_GET_FLAG(SDIO, SDIO_FLAG_SDIOIT))) {
    /*Receive SDIO interrupt on SDIO_DAT1 from WF200*/
    __SDIO_CLEAR_FLAG(SDIO, SDIO_FLAG_SDIOIT);
    xSemaphoreGiveFromISR(sl_wfx_wake_up_sem, 
                          &xHigherPriorityTaskWoken);
    xEventGroupSetBitsFromISR(sl_wfx_event_group,
                              SL_WFX_RX_PACKET_AVAILABLE,
                              &xHigherPriorityTaskWoken);
  }
  
  if (((SDIO->MASK & SDIO_IT_DATAEND) == SDIO_IT_DATAEND)
      && (__SDIO_GET_FLAG(SDIO, SDIO_FLAG_DATAEND))) {
    /*SDIO transfer over*/
    __SDIO_CLEAR_FLAG(SDIO, SDIO_IT_DATAEND);
    xSemaphoreGiveFromISR(sdioDMASemaphore, &xHigherPriorityTaskWoken);
  }
  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
 
/**************************************************************************//**
 * Handle DMA2 stream3 global interrupt
 *****************************************************************************/
void DMA2_Stream3_IRQHandler (void) {
  HAL_DMA_IRQHandler(&hdma_sdio_rx);
}
 
/**************************************************************************//**
 * Handle DMA2 stream6 global interrupt
 *****************************************************************************/
void DMA2_Stream6_IRQHandler (void) {
  HAL_DMA_IRQHandler(&hdma_sdio_tx);
}
#endif /* SL_WFX_USE_SDIO */

My adapted code

sl_status_t sl_wfx_host_sdio_read_cmd53 (uint8_t function,
                                         uint32_t address,
                                         uint8_t* buffer,
                                         uint16_t buffer_length) {
	SDMMC_CmdInitTypeDef command;
	SDMMC_DataInitTypeDef config;
 
	SDMMC1->DCTRL = 0U;
 
  if(buffer_length >= SL_WFX_SDIO_BLOCK_MODE_THRESHOLD) {
    uint32_t block_count = ( buffer_length / SL_WFX_SDIO_BLOCK_SIZE ) + ( ( ( buffer_length % SL_WFX_SDIO_BLOCK_SIZE ) == 0 ) ? 0 : 1 );
    command.Argument = SDIO_CMD53_BLOCK_MODE | SDIO_CMD53_COUNT(block_count);
    config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
    config.DataBlockSize = sdio_optimal_block_size(SL_WFX_SDIO_BLOCK_SIZE);
  } else {
    command.Argument = SDIO_CMD53_COUNT(buffer_length);
    config.TransferMode  = SDMMC_TRANSFER_MODE_STREAM;
    config.DataBlockSize = sdio_optimal_block_size(buffer_length);
  }
  command.Argument |= SDIO_CMD53_FUNCTION( function ) | SDIO_CMD53_OPMODE_INCREASING_ADDRESS | SDIO_CMD53_ADDRESS( address );
  config.TransferDir   = SDMMC_TRANSFER_DIR_TO_SDMMC;
 
//  SDIO->DCTRL |= SDIO_DCTRL_SDIOEN;
 
  /* Prepare Data */
  config.DataTimeOut   = SDMMC_DATATIMEOUT;
  config.DataLength    = buffer_length;
  config.DPSM          = SDMMC_DPSM_DISABLE; //todo
  (void)SDMMC_ConfigData(SDMMC1, &config);
 
  __SDMMC_CMDTRANS_ENABLE(SDMMC1);
  SDMMC1->IDMABASE0 = (uint32_t) buffer;
  SDMMC1->IDMACTRL  = SDMMC_ENABLE_IDMA_SINGLE_BUFF;
 
//  __SDIO_ENABLE_IT(SDIO, SDIO_IT_DATAEND);
//  hdma_sdio_rx.XferCpltCallback = SDIO_receive_cplt;
//  HAL_DMA_Start_IT(&hdma_sdio_rx, (uint32_t)&SDIO->FIFO, (uint32_t)buffer, (uint32_t)buffer_length/4);
//  __SDIO_DMA_ENABLE(SDIO);
 
  /* Prepare SDIO command */
  //todo .Argument which is Block address from where data is to be read...
  command.CmdIndex         = SDMMC_CMD_SDMMC_RW_EXTENDED;
  command.Response         = SDMMC_RESPONSE_SHORT;
  command.WaitForInterrupt = SDMMC_WAIT_NO;
  command.CPSM             = SDMMC_CPSM_ENABLE;
  (void)SDMMC_SendCommand(SDMMC1, &command);
  SDMMC_GetCmdResp(SDMMC1);
  uint32_t response_flags = SDMMC_GetResponse(SDMMC1, SDMMC_RESP1);
  if (((response_flags>> 😎 & 0xFF) != 0x20) {
    return SL_STATUS_FAIL;
  }
 
  __SDMMC_ENABLE_IT(SDMMC1, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND));
//  __SDIO_ENABLE_IT(SDIO, SDIO_IT_DATAEND);
 
 
  return SL_STATUS_OK;
}
 
 
 
----------------------- Interrupt handler ----------------------
	  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 
	  if (((SDMMC1->MASK & SDMMC_IT_SDIOIT) == SDMMC_IT_SDIOIT)
	      && (__SDMMC_GET_FLAG(SDMMC1, SDMMC_FLAG_SDIOIT))) {
	    /*Receive SDMMC interrupt on SDMMC_DAT1 from WF200*/
	    __SDMMC_CLEAR_FLAG(SDMMC1, SDMMC_FLAG_SDIOIT);
	    xSemaphoreGiveFromISR(sl_wfx_wake_up_sem,
	                          &xHigherPriorityTaskWoken);
	    xEventGroupSetBitsFromISR(sl_wfx_event_group,
	                              SL_WFX_RX_PACKET_AVAILABLE,
	                              &xHigherPriorityTaskWoken);
	  }
 
	  /* DATA END interrupt */
	  if (((SDMMC1->MASK & SDMMC_IT_DATAEND) == SDMMC_IT_DATAEND)
	      && (__SDMMC_GET_FLAG(SDMMC1, SDMMC_FLAG_DATAEND))) {
 
 
	    //done in SD:
	    __SDMMC_CLEAR_FLAG(SDMMC1, SDMMC_FLAG_DATAEND);
	    __SDMMC_DISABLE_IT(SDMMC1, SDMMC_IT_DATAEND  | SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | \
	                        SDMMC_IT_TXUNDERR | SDMMC_IT_RXOVERR  | SDMMC_IT_TXFIFOHE | \
	                        SDMMC_IT_RXFIFOHF);
 
	    __SDMMC_DISABLE_IT(SDMMC1, SDMMC_IT_IDMABTC);
	    __SDMMC_CMDTRANS_DISABLE(SDMMC1);
 
 
	    /***********************************************************************/
 
	    //done in SD specifically for DMA
	    SDMMC1->DLEN = 0;
	    SDMMC1->DCTRL = 0;
	    SDMMC1->IDMACTRL = SDMMC_DISABLE_IDMA;
 
	    xSemaphoreGiveFromISR(sdioDMASemaphore, &xHigherPriorityTaskWoken);
	  }
 
	  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

3 REPLIES 3
Claydonkey
Senior

I am having exactly the same issue. It appears that the SDMMC_IT_DATAEND does not get set  when using config.TransferMode = SDMMC_TRANSFER_MODE_STREAM;

Has anyone got a solution to this?

solution for -- what ?

maybe better, you open new thread and tell, what you want and how you tried it... + cpu type.

ie. > file access on sd-card with fatfs not working . <

If you feel a post has answered your question, please click "Accept as Solution".

Yeah I realise I've been lazy... It was late at night and I felt desperate. I will post my problem into a new thread. It was just that the code I wrote was so similar to that posted here by Hueli.1