2018-05-29 04:55 AM
Hi All,
I am working on STM32F413 Disco kit and trying to read/write into SD card using DMA mode.
My requirement is - i have to call single function which will read/write into SD card in 1ms timer callback function.
It is working fine in debug mode but not in normal mode.
Is there any delay issue ? Because when we run in debug mode, automatically delay is getting added.
Our project requirement is very rigid that we should not use HAL_Delay().
Please provide your suggestions.
My code:-
/********************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{ // TIM1 is configured for 1ms if(htim->Instance == TIM1) { SDtest(); }}/********************************************/
void SDtest(void){
LastWriteAddr = SD_WriteBlocks_DMA(Tx,TEMP_RAW_DATA_START_ADDR,1); LastReadAddr = SD_ReadBlocks_DMA(Rx,TEMP_RAW_DATA_START_ADDR,1);}/********************************************/
/*** Function To write into SD card via DMA***/
uint32_t SD_WriteBlocks_DMA(uint8_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks){ if(SDOperationState == SDWriteOperation) { printf('\n SD_WriteBlocks_DMA SDWriteOperation\n'); SDState = SDCardAvailable; return 0; } if(SDState == SDCardAvailable) { printf('\n SD_WriteBlocks_DMA\n'); HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t *)pData, WriteAddr, NumOfBlocks); SDState = SDCardBusy; return 0; } if(txDone == true) { WriteAddr += EACH_BLOCK_SIZE; SDOperationState = SDWriteOperation; printf('\n SD_WriteBlocks_DMA txDone\n'); txDone = false; return WriteAddr; } }/********************************************/
/*** Function To read from SD card via DMA***/
uint32_t SD_ReadBlocks_DMA(uint8_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks){ if(SDOperationState == SDReadOperation) { SDState = SDCardAvailable; return 0; } if(SDState == SDCardAvailable) { HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t *)pData, ReadAddr, NumOfBlocks); SDState = SDCardBusy; return 0; } if(rxDone == true) { ReadAddr += EACH_BLOCK_SIZE; SDOperationState = SDReadOperation; printf('SD card Read Done \n'); printf('Rx is %s \n',Rx); rxDone = false; return ReadAddr ; }}/********************************************/
enum SDStateEnum{
SDCardAvailable, SDCardBusy};enum SDOperationStateEnum{
SDIdle, SDWriteOperation, SDReadOperation};enum SDStateEnum SDState = SDCardAvailable;
enum SDOperationStateEnum SDOperationState = SDIdle;/********************************************/
Thanks,
Poonam
Solved! Go to Solution.
2018-06-05 01:20 AM
I have created few volatile flags for Read and write.
volatile bool SDWRITE = 0;
volatile bool SDREAD = 0;Also the card status must be checked after read/write operations.
Used these flags at proper place as shown in below code.
Called below code in 1ms timer callback function.
if(SDWRITE == 0)
{ HAL_SD_WriteBlocks_DMA(&hsd, buff, write_addr, 1); SDWRITE = 1; } if(SDWRITE == 1) { if(HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER) { if(SDREAD == 0) { //printf('\n SDREAD 0 \n'); HAL_SD_ReadBlocks_DMA(&hsd,read_buff,read_addr,1); SDREAD = 1; } if(SDREAD == 1) { //printf('\n SDREAD 1 \n'); if(HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER) { //printf('\n SDREAD HAL_SD_CARD_TRANSFER\n'); SDWRITE = 0; write_addr +=0x200; SDREAD = 0; read_addr += 0x200; //printf('\n read_buff is %s write_addr = 0x%x \n',read_buff,write_addr); //printf('\n read_addr is 0x%x\n',read_addr); //printf('\n write_addr is 0x%x\n',write_addr); }2018-05-29 05:49 AM
It is working fine in debug mode but not in normal mode.
You can safely assume that both configurations (debug and release) have different settings.
Please provide your suggestions.
I don't do any Cube/HAL code, but I would start to either compare the settings for both configurations, or the emitted build commands. Per
#define
's in your code, the actual source code might be different.2018-05-29 07:23 AM
Make sure SDState and anything that is touched under interrupt is declared volatile.
Make sure to set the new SDState immediately so as not to create race conditions with the likes of printf, HAL_SD_Read/WriteBlocks_DMA, and reentry of the 1ms ticker.
If you are not doing this with an RTOS, I'd probably lean to pumping the SD activity in a foreground task.
2018-05-29 07:39 AM
Like
Turvey.Clive
hinted, I would suggest that don't print in an interrupt,just set a flag, maybe write to a table, and let the foreground do all the printing.
feel free to use globals for flags and permanent buffers linking interrupts to the foreground process.
is that the opposite of volatile ?
2018-05-29 09:58 AM
I have used enum for flags[as you can see in my code above] and volatile for variables which are getting called in interrupt.
I am not using RTOS. Its a bare metal project.
Is ENUM is creating problem but then its working fine in debug mode.
In debug mode also , if I step in very fast, it doesn't work .
I have to step in slow then only it works.
Thanks,
Poonam
2018-05-29 10:24 AM
Your code creates race conditions
if(SDState == SDCardAvailable)
{ printf('\n SD_WriteBlocks_DMA\n'); HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t *)pData, WriteAddr, NumOfBlocks); SDState = SDCardBusy; // Far too late to do this return 0; }2018-05-30 03:34 AM
Hi Clive,
I have changed my code to get rid of race condition but still facing problem that it is not working in normal mode .
if(sd_card_status == SDCARDAVAILABLE)
{sd_card_status = SDCARDBUSY;
status = HAL_SD_WriteBlocks_DMA(&hsd, pData, WriteAddr, NumOfBlocks); printf('\n status is %d \n',status); //here value is coming 1 means [HAL_ERROR = 0x01U]}
I tried to add prints , and observed that it is going inside below loop of HAL_SD_WriteBlocks_DMA().
/* Set Block Size for Card */
errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); if(errorstate != HAL_SD_ERROR_NONE) { /* Clear all the static flags */ __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); hsd->ErrorCode |= errorstate; hsd->State = HAL_SD_STATE_READY; printf('\n errorstate != HAL_SD_ERROR_NONE\n'); return HAL_ERROR; }2018-05-30 04:25 AM
As said before, printf() are a bad way of debugging. It will distort the timing, or throw it off completely, creating phantom problems.
Write a normal integer variable instead, and set a data watchpoint on said variable. Or so.
2018-06-05 12:29 AM
The problem is solved with proper utilization of flags in timer callback function.
Thanks.
2018-06-05 01:20 AM
I have created few volatile flags for Read and write.
volatile bool SDWRITE = 0;
volatile bool SDREAD = 0;Also the card status must be checked after read/write operations.
Used these flags at proper place as shown in below code.
Called below code in 1ms timer callback function.
if(SDWRITE == 0)
{ HAL_SD_WriteBlocks_DMA(&hsd, buff, write_addr, 1); SDWRITE = 1; } if(SDWRITE == 1) { if(HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER) { if(SDREAD == 0) { //printf('\n SDREAD 0 \n'); HAL_SD_ReadBlocks_DMA(&hsd,read_buff,read_addr,1); SDREAD = 1; } if(SDREAD == 1) { //printf('\n SDREAD 1 \n'); if(HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER) { //printf('\n SDREAD HAL_SD_CARD_TRANSFER\n'); SDWRITE = 0; write_addr +=0x200; SDREAD = 0; read_addr += 0x200; //printf('\n read_buff is %s write_addr = 0x%x \n',read_buff,write_addr); //printf('\n read_addr is 0x%x\n',read_addr); //printf('\n write_addr is 0x%x\n',write_addr); }