cancel
Showing results for 
Search instead for 
Did you mean: 

SD read/write with DMA mode working only in debug mode

Poonam Deoghare
Associate III
Posted on May 29, 2018 at 13:55

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

1 ACCEPTED SOLUTION

Accepted Solutions
Poonam Deoghare
Associate III
Posted on June 05, 2018 at 10:20

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);    

                    }   

View solution in original post

16 REPLIES 16
AvaTar
Lead
Posted on May 29, 2018 at 14:49

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.
Posted on May 29, 2018 at 16:23

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
T J
Lead
Posted on May 29, 2018 at 16:39

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 ?

Posted on May 29, 2018 at 16:58

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

Posted on May 29, 2018 at 17:24

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;

  }
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 30, 2018 at 10:34

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;

    }

   
Posted on May 30, 2018 at 11:25

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.

Poonam Deoghare
Associate III
Posted on June 05, 2018 at 09:29

The problem is solved with proper utilization of flags in timer callback function.

Thanks.

Poonam Deoghare
Associate III
Posted on June 05, 2018 at 10:20

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);    

                    }