2015-03-01 04:47 PM
My issue is with fatfs in the following code:
retSD = FATFS_LinkDriver(&SD_Driver, SD_Path);if(retSD == 0) { if(f_mount(&sdcard,(TCHAR const*)SD_Path,1) != FR_OK) //works great { Error_Handler(); } else { //HAL_SD_WideBusOperation_Config(&hsd,SDIO_BUS_WIDE_4B); retSD = f_mkfs((TCHAR const*)SD_Path,0,0); //formats just fine, i even took the SD card out and put it in my laptop, formatted 100% ok if(retSD != FR_OK) { Error_Handler(); } else { retSD = f_open(&file,''0:test.bin'',(FA_CREATE_ALWAYS | FA_WRITE)); //trying to just create a file, i tried with and without 0:, in debug I found that is what SD_Path ends up being, I also tried with and without a / at the end. I always get error 11!!! if(retSD != FR_OK) { Error_Handler(); } } } }After stepping through my code for a few hours, I have also found a strange error that occurs in the middle of the f_open below:if (res == FR_OK) { INIT_BUF(dj); res = follow_path(&dj, path); /* Follow the file path */ dir = dj.dir;INIT_BUF(dj) simply calls malloc(size) where size is about 514 (2*some buffer size in ffconf.h)I certainly have this much memory available...but when it returns the function f_open jumps to the end with a return code error (optimization is off so I can see every step, but this still happens...)Any pointers? #stm32-fatfs-f_open2015-03-01 09:39 PM
2015-03-02 08:49 AM
ST has a long history of broken SDIO and FATFS implementations because they try to access a Block device with Byte offsets. This historically has been compounded with the use of 32-bit variables, and their implicit 4GB limitations. In later versions they used 64-bit Byte offsets, which will work as long as all the variables and math along the way don't lose precision. It's a lot of unnecessary work, I built 32-bit Block addressing versions, which are good to 2TB.
If you are using FatFs to format you'd need to be very sure that you are reading the appropriate size structures from the card, and passing them back up to FatFs. I suspect this would be via IOCTL calls in diskio.c. I personally would avoid letting FatFs format SD cards, as they are very sensitive to structural alignment requirements, and will be very slow if done incorrectly.2015-03-02 10:48 AM
What do you suggest I do to get around the block addressing problem, just wrap more than 512 byte accesses in a for loop?
egI need to get a 512,000 byte file and load it into external memory (say for image processing)readwritecount = 1;FR = FR_OK;for(int i = 0; i < 1000, FR == FR_OK, readwritecount != 0 ; ++i){ FR = f_read(&file, buff*i, 512*2 /*I have to double it as said earlier*/, &readwritecount);}2015-03-02 12:12 PM
If you handle it properly it will be transparent to the top level FatFs code.
With the ST code bases I work from (SPL, not HAL/Cube), the SD_ReadMultiBlocks(), SD_WriteMultiBlocks(), and the disk_read(), disk_write() are when this is all handled. FatFs, and every rational block file system on the planet, use Block (Sector) level addressing for block storage devices. The CCM memory of the F4 is not usable for DMA based memory operations.2015-03-02 12:18 PM
Small f_read's are very inefficient, you want to use large transfers, ideally block or cluster aligned, and of block/cluster sizes. You might want to benchmark your own situation, but 32KB is a sweet spot. Depends a lot on the memory available and your allocation strategy.
External memory on the F4 is significantly slower than internal memory. If you can decompose your processing into smaller blocks that will fit internally this will significantly improve overall performance.2015-03-02 01:39 PM
I'm using an SDHC card, and from what I can tell, the block size is always 512 on those, the only problem is that when I try to read from them, it seems to half the read size and never does more than one block. It sends the command to the SDIO controller as 2*512 but the fifo just stops at 512 and then it sends the stop command.
I looked at your driver, but its a little over my head, could you take a look at the command from HAL/STM32CUBE and let me know what the differences are or what I should change to get it working? It seems to read in blocks to me.HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks)
{
SDIO_CmdInitTypeDef sdio_cmdinitstructure;
SDIO_DataInitTypeDef sdio_datainitstructure;
HAL_SD_ErrorTypedef errorstate = SD_OK;
uint32_t count = 0, *tempbuff = (uint32_t *)pReadBuffer;
/* Initialize data control register */
hsd->Instance->DCTRL = 0;
if (hsd->CardType == HIGH_CAPACITY_SD_CARD)
{
BlockSize = 512;
ReadAddr /= 512;
}
/* Set Block Size for Card */
sdio_cmdinitstructure.Argument = (uint32_t) BlockSize;
sdio_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN;
sdio_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
sdio_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
sdio_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
SDIO_SendCommand(hsd->Instance, &sdio_cmdinitstructure);
/* Check for error conditions */
errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN);
if (errorstate != SD_OK)
{
return errorstate;
}
/* Configure the SD DPSM (Data Path State Machine) */
sdio_datainitstructure.DataTimeOut = SD_DATATIMEOUT;
sdio_datainitstructure.DataLength = NumberOfBlocks * BlockSize;
sdio_datainitstructure.DataBlockSize = (uint32_t)(9 <<
4
);
sdio_datainitstructure.TransferDir
=
SDIO_TRANSFER_DIR_TO_SDIO
;
sdio_datainitstructure.TransferMode
=
SDIO_TRANSFER_MODE_BLOCK
;
sdio_datainitstructure.DPSM
=
SDIO_DPSM_ENABLE
;
SDIO_DataConfig(hsd->Instance, &sdio_datainitstructure);
if(NumberOfBlocks > 1)
{
/* Send CMD18 READ_MULT_BLOCK with argument data address */
sdio_cmdinitstructure.CmdIndex = SD_CMD_READ_MULT_BLOCK;
}
else
{
/* Send CMD17 READ_SINGLE_BLOCK */
sdio_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK;
}
sdio_cmdinitstructure.Argument = (uint32_t)ReadAddr;
SDIO_SendCommand(hsd->Instance, &sdio_cmdinitstructure);
/* Read block(s) in polling mode */
if(NumberOfBlocks > 1)
{
/* Check for error conditions */
errorstate = SD_CmdResp1Error(hsd, SD_CMD_READ_MULT_BLOCK);
if (errorstate != SD_OK)
{
return errorstate;
}
/* Poll on SDIO flags */
while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_FLAG_STBITERR))
{
if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF))
{
/* Read data from SDIO Rx FIFO */
for (count = 0; count <
8
; count++)
{
*(tempbuff + count) = SDIO_ReadFIFO(hsd->Instance);
}
tempbuff += 8;
}
}
}
else
{
/* Check for error conditions */
errorstate = SD_CmdResp1Error(hsd, SD_CMD_READ_SINGLE_BLOCK);
if (errorstate != SD_OK)
{
return errorstate;
}
/* In case of single block transfer, no need of stop transfer at all */
while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR))
{
if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF))
{
/* Read data from SDIO Rx FIFO */
for (count = 0; count <
8
; count++)
{
*(tempbuff + count) = SDIO_ReadFIFO(hsd->Instance);
}
tempbuff += 8;
}
}
}
/* Send stop transmission command in case of multiblock read */
if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DATAEND) && (NumberOfBlocks > 1))
{
if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) ||\
(hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\
(hsd->CardType == HIGH_CAPACITY_SD_CARD))
{
/* Send stop transmission command */
errorstate = HAL_SD_StopTransfer(hsd);
}
}
/* Get error state */
if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT))
{
__HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT);
errorstate = SD_DATA_TIMEOUT;
return errorstate;
}
else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL))
{
__HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL);
errorstate = SD_DATA_CRC_FAIL;
return errorstate;
}
else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR))
{
__HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR);
errorstate = SD_RX_OVERRUN;
return errorstate;
}
else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_STBITERR))
{
__HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_STBITERR);
errorstate = SD_START_BIT_ERR;
return errorstate;
}
else
{
/* No error flag set */
}
count = SD_DATATIMEOUT;
/* Empty FIFO if there is still any data */
while ((__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)) && (count > 0))
{
*tempbuff = SDIO_ReadFIFO(hsd->Instance);
tempbuff++;
count--;
}
/* Clear all the static flags */
__HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
return errorstate;
}
2015-03-02 02:09 PM
I understand the blocks are 512 bytes in size, what I'm saying is for the interaction with the card to be remotely efficient (command overhead vs transfer size), you'd read/write more than one at a time, ideally something like
The code uses 64-bit byte addressing, I could change this to 32-bit block addressing, but it won't address the functional issues you are having. The size passed to the formatter is some place else. Probably related to CARDINFOcardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) ;
cardinfo->CardCapacity *= (1 << (cardinfo->SD_csd.DeviceSizeMul + 2));
cardinfo->CardBlockSize = 1 << (cardinfo->SD_csd.RdBlockLen);
cardinfo->CardCapacity *= cardinfo->CardBlockSize;
The HAL code also doesn't seem to be using DMA. This is far too deep of a rabbit hole for me. Perhaps you can find someone at ST, or an FAE, that can delve into this and get it working.
2015-03-02 03:50 PM
Clive, thanks so much for helping me look into this, I'm not using the DMA functions because I want to get it working with regular polling (I've yet to use DMA at all on the MCU, it is a can of worms I will explore later on). I'll try to call ST and see what they can offer.