cancel
Showing results for 
Search instead for 
Did you mean: 

Why can I not get past f_open with SD card

GreenGuy
Lead
Posted on March 05, 2018 at 05:51

I am working with STM32F746G-Disco board to prove out the use of the SD card.  I am at a point where I cannot get the code to write data to the card using the fs calls.  First, I have setup the board in CubeMX with all the peripherals for the disco board initialized although I am only working with the FATfs, SD card and the screen for debug. The Cube project file is attached.  The code is working up to the point where f_open is called but f_open does not seem to return.  The code looks like this:

  /* USER CODE BEGIN 5 */

  sdres = BSP_SD_Init();

  if (sdres == FR_OK) BSP_LCD_DisplayStringAt(0, 94, (uint8_t *)'SD Init status Pass', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, 94, (uint8_t *)'SD Init status Fail', LEFT_MODE);

  sdres = f_mount(&sdFatfs, '', 0);

  if (sdres == FR_OK) BSP_LCD_DisplayStringAt(0, 124, (uint8_t *)'SD mount Pass', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, 124, (uint8_t *)'SD mount Failed', LEFT_MODE);

  sdres = f_open(&sdFile, 'test.txt', FA_OPEN_ALWAYS|FA_WRITE|FA_READ);

  if (sdres == FR_OK) BSP_LCD_DisplayStringAt(0, 124, (uint8_t *)'SD open Pass', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, 124, (uint8_t *)'SD open Failed', LEFT_MODE);

  sdres = f_lseek(&sdFile, sizeof(&sdFile));

  if (sdres == FR_OK) BSP_LCD_DisplayStringAt(0, 124, (uint8_t *)'SD seek Pass', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, 124, (uint8_t *)'SD seek Failed', LEFT_MODE);

  sdres = f_printf(&sdFile, '%s', buffSDwr);

  if (sdres == FR_OK) BSP_LCD_DisplayStringAt(0, 124, (uint8_t *)'SD print Pass', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, 124, (uint8_t *)'SD print Failed', LEFT_MODE);

  sdres = f_close(&sdFile);

  if (sdres == FR_OK) BSP_LCD_DisplayStringAt(0, 124, (uint8_t *)'SD close Pass', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, 124, (uint8_t *)'SD close Failed', LEFT_MODE);

The sdFile, sdFatfs, sdres, and buff... variables are all global to main.c being declared in the USER PV area.

When this runs, the LCD screen prints

SD Init status Pass

SD mount Pass

after which nothing else appears.  It is also interesting to note that if I set break points at the f_open call and just after the call, the debugger stops at f_open but when I click run to go to the next break point the execution pointer simply stops at the f_open call again.  ODD!  If i place the cursor a couple of lines down and select run to cursor, the same thing happens.  If I try to step over the f_open line the debugger ends up at the first instruction in the tick handler.  I have exhausted all the posts, youtube tutorials, and blogs and nothing has settled the issue.

31 REPLIES 31
feuerwolf
Senior
Posted on March 05, 2018 at 11:27

I think your problem is DMA related. CubeMx generates wrong SDIO - DMA Code . There are plenty of discussions here.

https://community.st.com/0D50X00009XkXgUSAV

Just read throug the Forum.

In order to use Sd Card without DMA you have to config Cube Mx properly. I found that it integrates DMA even if you did not choose it, thats why your programm fails.

Here I postet the solution

https://community.st.com/0D70X000006Ss9JSAS

0690X00000604RKQAY.jpg

Posted on March 05, 2018 at 14:05

There is a significant possibility of an underrun error if DMA is not used.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
GreenGuy
Lead
Posted on March 05, 2018 at 22:35

I wondered if this is a timing issue so I used BSP_SD_GetCardState before all f_xxxx operations which results in FR_OK to be returned and the STM32 does not hang up in the execution trap.  However, I find that the file is never created on the SD device.  So much for the FR_OK flag.  This may be due to the DMA template missing.  I will let you know when I get back to it later today.

Thanks for the tip!

Posted on March 06, 2018 at 07:39

The CubeMX project has always had Use DMA Template Enabled.

DMA is not being used.

GreenGuy
Lead
Posted on March 06, 2018 at 09:43

I have tried several variations resulting in no gain.  Things I have tried:

1. Adding to DMA configuration in MemToMem a MDA2 stream 0

2. Also tried setting priority to Medium

3. Saw a post where someone showed setting RCC Global interupt so tried that.

Again all of the result returns are FR_OK but nothing appears on the SD Card when checked on another PC.

Any other ideas?

GreenGuy
Lead
Posted on March 06, 2018 at 11:02

So I have been fooling myself with errant code.  It appears that I have been stepping over all of the f_xxxxxx calls after f_mount due to missing curly braces on the statement, while(BSP_SD_GetCardState() != SD_TRANSFER_OK)

After fixing that the f_open does not return and the code winds up at:

 @brief  This is the code that gets called when the processor receives an

 *         unexpected interrupt.  This simply enters an infinite loop, preserving

 *         the system state for examination by a debugger.

 * @param  None     

 * @retval None       

*/

    .section  .text.Default_Handler,'ax',%progbits

Default_Handler:

Infinite_Loop:

  b  Infinite_Loop

  .size  Default_Handler, .-Default_Handler

I traced the execution all the way down to :

uint32_t SDMMC_CmdReadSingleBlock(SDMMC_TypeDef *SDMMCx, uint32_t ReadAdd)

{

  SDMMC_CmdInitTypeDef  sdmmc_cmdinit;

  uint32_t errorstate = SDMMC_ERROR_NONE;

 

  /* Set Block Size for Card */

  sdmmc_cmdinit.Argument         = (uint32_t)ReadAdd;

  sdmmc_cmdinit.CmdIndex         = SDMMC_CMD_READ_SINGLE_BLOCK;

  sdmmc_cmdinit.Response         = SDMMC_RESPONSE_SHORT;

  sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO;

  sdmmc_cmdinit.CPSM             = SDMMC_CPSM_ENABLE;

  SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit);

 

  /* Check for error conditions */

  errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_READ_SINGLE_BLOCK, SDMMC_CMDTIMEOUT);

  return errorstate;

}

in stm32f7xx_ll_sdmmc.c.  When I try to step into the next to last line that tries to the errorstate for SDMMC_GetCmdResp1() the debugger jumps right to the Default Handler infinite loop.

Any ideas?

GreenGuy
Lead
Posted on March 06, 2018 at 19:35

I think I may have found an issue.  Looking at the FatFs application for the F746G-disco I see a call to FATFS_LinkDriver before any of the other sd file operations and it lools like SDPath variable is being set by that instead of the user initializing SDPath.

GreenGuy
Lead
Posted on March 07, 2018 at 06:36

OK I have solved the interrupt error handler trap by using :

  sdres = BSP_SD_Init();

  if(sdres == FR_OK) BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD Init ok', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD Init Fail', LEFT_MODE);

  ypos += BSP_LCD_GetYSize()/24 + 6;

  sdres = FATFS_LinkDriver(&SD_Driver, SDPath);

  if(sdres == FR_OK) BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'FatFS Driver ok', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'FatFS Driver Fail', LEFT_MODE);

  ypos += BSP_LCD_GetYSize()/24 + 6;

  if(sdres == FR_OK) sdres = f_mount(&SDFatFs, (TCHAR const*)SDPath, 0);

  if(sdres == FR_OK) BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD Mount ok', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD Mount Fail', LEFT_MODE);

  ypos += BSP_LCD_GetYSize()/24 + 6;

  if(sdres == FR_OK) sdres = f_open(&MyFile, 'test.txt', FA_CREATE_ALWAYS|FA_WRITE|FA_READ);

  if(sdres == FR_OK) BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD Open ok', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD Open Fail', LEFT_MODE);

  ypos += BSP_LCD_GetYSize()/24 + 6;

  if(sdres == FR_OK) sdres = f_printf(&MyFile, '%s', wtext);

  if(sdres == FR_OK) BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD write ok', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD write Fail', LEFT_MODE);

  ypos += BSP_LCD_GetYSize()/24 + 6;

  if(sdres == FR_OK) sdres = f_close(&MyFile);

  if(sdres == FR_OK) BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD close ok', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD close Fail', LEFT_MODE);

  ypos += BSP_LCD_GetYSize()/24 + 6;

  if(sdres == FR_OK) sdres = f_mount(NULL, (TCHAR const*)SDPath, 0);

  if(sdres == FR_OK) BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD unmouted ok', LEFT_MODE);

  else BSP_LCD_DisplayStringAt(0, ypos, (uint8_t *)'SD unmount Fail', LEFT_MODE);

I have noticed that if I set  the FatFS physicFS Driver call fails, and 2 or above the open fails for FR_NOT_ENABLED.  The code steps are the same as the FATFS example project in the repo except that I am using f_printf instead of write.  that is rather moot since I not getting that far anyway.

GreenGuy
Lead
Posted on March 07, 2018 at 07:40

The more I look at this the more confusing it gets.

First of all the thread for 1.8.0 HAL is old and I am using 1.9.0 which has been corrected as stated in the tread Alexander mentioned.

Further I am not sure why I have to call FATFS_LinkDriver(&SD_Driver, SDPath); in my main as it has already been run as part of the init done in MX_FATFS_Init(); .  However if I do not call it then f_open hangs.  I have a feeling the reason I have to set Volumes >1 in CubeMX is due to FATFS_LinkDriver getting called twice.  ReadStatus is not a factor here since f_open does not end up calling SD_read.