cancel
Showing results for 
Search instead for 
Did you mean: 

Failed to use STM32CubeMX+H743+SDMMC+DMA+FATFS

wjiac.1
Associate II

Hello.

I am using CubeMX to generate project and code. Without using DMA I can write SD card successfully, while I enable DMA f_open will wait for 30 seconds ( timeout) and fail with an Error 1 output.

The CubeMX project is in the attachment.

I need your advice to solve this problem, thanks.

3 REPLIES 3
Curtis B.
Senior

I assume that you have enabled the cache? Using cache and DMA is a bit tricky. CubeMx generated code provides some cache maintenance functions to handle this, but I read some threads here in the community, that this code does not work properly due to wrong alignment of the buffers with the cache lines. I solved this problem by placing all the neccessary buffers in a RAM region which is not cached (cache was disabled in this region by using the MPU).

At first I defined a structure in the following way:

typedef struct
{
	FATFS FileSystem;
	FIL	File_1;
	uint8_t Buffer[512];
}CB_RIC_FILE_t;

Nex I defined a variable in main.c

__attribute__((section(".FileIO"))) CB_RIC_FILE_t RICFilePackage;

By means of __attribute__ I tell the linker to place the variable in a dedicated area in the RAM that I define in the linkerscript. Thus I added following section (FileIO) in the linkerscript between the data section and the heap/stack section:

  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)
 
    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM_D1
  
    .FileIO :
	{
	. = . + 0x400;
	  . = ALIGN(2048);
	*(.FileIO*);
	. = . + 0x400;
	} >RAM_D1
 
  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM_D1

The +0x400 are some safety-distances to the rest of the data (that might not be neccessary). The Align(2048) command is inserted due to the demand that the memory, that is protected by the MPU, must be aligned according to the size of the protected area (I struggled a long time with this one until I finally found out how to do it correctly. This is one of the information which are absolutely important but not written down and only bequeathed from father to son).

Now the data structure is in the right position in the RAM. Next, the MPU is configured:

size = sizeof(RICFilePackage);
FilePackageBaseAdrr = (uint32_t) &RICFilePackage;
 
update_MPU(MPU_REGION_NUMBER4,FilePackageBaseAdrr,size);

with:

void update_MPU(uint8_t Region_Number,uint32_t BaseAdrr,uint32_t size)
{
	  MPU_Region_InitTypeDef MPU_InitStruct = {0};
 
	  uint8_t RegionSize;
 
	  RegionSize = 0x04;
	  while(size > 32)
	  {
		  size = size >> 1;
		  RegionSize++;
	  }
 
 
	  /* Disables the MPU */
	  HAL_MPU_Disable();
 
	  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
	  MPU_InitStruct.Number = Region_Number;
	  MPU_InitStruct.BaseAddress = BaseAdrr;
	  MPU_InitStruct.Size = RegionSize;
	  MPU_InitStruct.SubRegionDisable = 0x0;
	  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
	  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
	  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
	  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
 
	  HAL_MPU_ConfigRegion(&MPU_InitStruct);
 
 
	  /* Enables the MPU */
	  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

Now DMA operations should be no problem anymore. When you use fatfs you need to refer to this data structure like:

f_mount(&(RICFilePackage.FileSystem), (TCHAR const*)SDPath, 1)
 
or
 
f_open(&(FilePackage->File_1),(char*)path, FA_READ| FA_OPEN_EXISTING);
 
or
 
f_write(&(FilePackage->File_1),&DatObj.DataPackage[0],9,&testBytes);
 
or
 
f_read(&(FilePackage->File_1),&(FilePackage->Buffer[0]),45,&readBytes);

I hope this heps you with your problem.

Regards,

Daniel

wjiac.1
Associate II

Thanks so much for your detailed answer, Daniel. I tried your advise but it still could not work properly.

Finally, I updated the CubeMX (including the latest version of H7 Firmware packages), the problem solved!!!

So, besides my fault settings, the Bugs of the last version of CubeMX tortured me so much...��

Alright, I'm glad that it finally works for you :)

regards