2014-05-20 09:44 AM
I'm trying to test out and utilize the STM32Cube configuration / code generation system to help get things on a new project started. The project is using an SD card, to which I want FatFS access internally. Ideally, I also want to get a dual-access system where the SD card is also mounted as a mass storage device over USB. I'll save that for later, though.
To try this out, I started with the STM32F4-Discovery board and the -BB base board with SD Card connector. I started with the base STM32Cube configuration using the new project dialog, then added the SDIO interface (disabling the conflicting interfaces), and FatFS. I left the default settings on there (no DMA or other interrupts). It did not work first time. I used the test function from the FatFS_USBDisk example application from the STM32Cube_FW_F4_V1.1.0 folders, MSC_Application(), just modified to use the FatFS SD Driver's path (SD_Path) from the generated code. I put a single call to this in the USER CODE 3 section in main() with a while(1); after it to catch everything. The default settings for FatFS, though are to use the _DMA functions for transfer, even if you have DMA disabled. And, if they have DMA enabled, they don't function correctly. 1) Here's how I got it working without DMA: I modified the calls in SD_read() within sd_diskio.c from BSP_SD_[Read/Write]Blocks_DMA() toBSP_SD_[Read/Write]Blocks(). Literally, just remove the ''_DMA''. Then, the FatFS system was failing to create files, etc. Tracking this down, I found the heap insufficient by default (0x0200). Raising this to 0x0300 fixed the problem. I would recommend making this higher, though. Both of these problems need to be fixed in the code generation tools: It shouldn't use the _DMA functions when DMA is disabled / not configured. The non-DMA functions are even completely written and available. Also, and the heap size should increase if using FatFS. 2) Now, how to get it working with DMA? First problem I've run into is that the DMA and SDIO interrupts were not configured, so it hung on the while loop in HAL_SD_CheckReadOperation():while ((tmp1 == 0) && (tmp2 == 0) && (tmp3 == SD_OK) && (timeout > 0))
{
tmp1 = hsd->DmaTransferCplt;
tmp2 = hsd->SdTransferCplt;
tmp3 = (HAL_SD_ErrorTypedef)hsd->SdTransferErr;
timeout--;
}
This made me realize that the DMA / SDIO interrupts weren't enabled, nor the DMA configured. So, I enabled them, regenerated the code, and now it hangs on this while loop in the same function:
/* Wait until the Rx transfer is no longer active */
while((__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXACT)) && (timeout > 0))
{
timeout--;
}
This is where I'm stuck. In researching further, looking at [DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/SDIO%20and%20SD%20fat%20access%20example&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=8757]Clive's FATFS-DBG example, it looks like it's re-configuring the DMA each transfer, which makes sense - using the same stream for each direction. However, I think this has something to do with the fact that with the code generation, it configures it once in MX_DMA_Init() and then links the DMA handle to two different ''handles''. This would imply that it would be reconfiguring the DMA as appropriate. However, within the HAL_SD_[Read/Write]Blocks_DMA() functions, the references tohsd->hdma[rx/tx] don't seem to ever reconfigure the *.Init structure, nor reinitialize the DMA like Clive's SD_LowLevel_DMA_[Rx/Tx]Config() functions do.
I think this needs to be fixed in the STM32Cube generator as well. I will proceed with trying to fix it, but I think that the Cube initiative was to prevent you having to edit the generated code.
This was to serve as both a PSA / information about getting it to worth without DMA and also a request for other thoughts about what might be wrong getting it to work with DMA.
Comments / thoughts welcome!
#stm32-fat-fatfs-sdio-dma
2014-05-23 12:00 PM
Ok, so I have the DMA version working now with this new information.
I changed the DMA initialization code in HAL_SD_MspInit() to be pretty much everything in the working example above./*##-3- Configure the DMA streams ##########################################*/''
to
''
HAL_DMA_Init(&dmaTxHandle);
''into this function under the nominal '''' section, before the peripheral NVIC configuration.
I
changed the interrupt priority of the peripheral to match.Then, I placed the DMA NVIC interrupt configuration parts of the above example within the MX_DMA_Init() function in main.c.
I placed the required #defines at the top of the _msp.c file so that the function would compile.Finally, I had to modify the interrupts:Once this compiled, everything seemed to work just fine.
So, what does this mean for suggestions for CubeMX to implement / fix?2014-06-06 10:13 AM
Hi elaske
,
thank you so much for posting your findings. After many days of trying to get SD working with F4 I discovered your post and have started following your recommendations. I now have SDIO+FatFs working without DMA mode which is a huge step forward from not working at all. I can now build on the working version and try to get it working with DMA, again following your recommendations. They are invaluable.It's a real shame that CubeMX isn't tested more before release or at least updated to fix issues reported by users more regularly. It will eventually be a great tool but currently is frustratingly buggy and may be causing users to waste more time tracking down bugs instead of saving them the time it's meant to by configuring the peripherals reliably.2014-06-09 07:36 AM
2014-06-10 04:03 AM
static void SD_DMA_TxCplt(DMA_HandleTypeDef *hdma)
{
SD_HandleTypeDef *hsd = (SD_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent;
/* DMA transfer is complete */
hsd->DmaTransferCplt = 1;
while( 0 == NVIC_GetPendingIRQ(SDIO_IRQn) )
{
}
HAL_NVIC_ClearPendingIRQ(SDIO_IRQn);
HAL_SD_IRQHandler(hsd);
/* Wait until SD transfer is complete */
while(hsd->SdTransferCplt == 0)
{
}
/* Transfer complete user callback */
HAL_SD_DMA_TxCpltCallback(hsd->hdmatx);
}
I added:
while( 0 == NVIC_GetPendingIRQ(SDIO_IRQn) )
{
}
HAL_NVIC_ClearPendingIRQ(SDIO_IRQn);
HAL_SD_IRQHandler(hsd);
just before thewhile(hsd->SdTransferCplt == 0) so the functions get called even if the interrupt handler doesn't get called automatically ( I did the same for the SD_DMA_RxCplt function ). The code now works and reading/writing using FatFs is working fine. I'm still not entirely happy that the interrupt is not firing as expected and will probably stick with the non-DMA code for now.
2014-06-10 08:36 AM
void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* Sets the priority grouping field */
/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_NVIC_SetPriority(SD_DMAx_Rx_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(SD_DMAx_Rx_IRQn);
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(SD_DMAx_Tx_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(SD_DMAx_Tx_IRQn);
}
for the DMA channels
and for the SDIO inside HAL_SD_MspInit function:
/* Peripheral interrupt init*/
/* Sets the priority grouping field */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_NVIC_SetPriority(SDIO_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SDIO_IRQn);
All systems go now with DMA...Thanks again elaske for your invaluable information and detailed explanation.
2014-09-24 07:32 AM
Hello,
This implementation will be available in STM32CubeMX 4.4 release. Best Regards