2024-02-05 06:25 PM
I am writing to an SD card using the Adafruit_Shield BSP library on the STM32L4R5ZI Nucleo board.
I had it writing 10 values, from 0x00 to 0x09 but the second byte (with a value of 0x01) was getting corrupted as set to 0x00. I changed the array so it was set to start at 0x01 and end with 0x0A and instead of it being the second byte that was corrupted, it was the first byte, which was now 0x01. I reran the same test starting at 0x02 and all the data came through correct. My takeaway was there's an issue if value 0x01 is used within the first x number of bytes (not sure what that number is or the reason for it).
To test this further, I made the buffer 512 bytes starting with 0x00 but changed the array location 216 (arbitrary) to 0x01 to see if it would be corrupted there as well. Byte 2 (0x01) was changed to 0x00 but byte 216 was still 0x01.
I was feeling more confident that that might've been the problem and then got confused even more. I used the same 512 byte array, still had byte 216 as 0x01 but changes the second byte from 0x01 to 0x26 (arbitrary). To my surprise, byte 1 was changed from 0x26 to 0x00, so now it doesn't seem to have an issue with only 0x01 and I have no idea what's going on.
I think I need to understand what's going on first before I can go too much further. To determine the cause of the issue, I stepped altered the f_write command a bit so I'm copying the buffer that's getting corrupted and seeing exactly where it's being corrupted. There's probably a better way to do it but this is how I did it. below is f_write_test (the same as f_write but I could change the code without accidently breaking the library) in ff.c:
FRESULT f_write_test (
FIL* fp, /* Pointer to the file object */
const void* buff, /* Pointer to the data to be written */
UINT btw, /* Number of bytes to write */
UINT* bw /* Pointer to number of bytes written */
)
{
FRESULT res;
FATFS *fs;
DWORD clst, sect;
UINT wcnt, cc, csect;
char test_array[512] = {0};
const BYTE *wbuff = (const BYTE*)test_array;
memcpy(test_array, buff, 512); /* Data is correct at this point */
*bw = 0; /* Clear write byte counter */
memcpy(test_array, buff, 512); /* Data is corrupted at this point */
res = validate(&fp->obj, &fs); /* Check validity of the file object */
For reference, my main code looks like this:
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_LPUART1_UART_Init();
MX_USART3_UART_Init();
MX_USB_OTG_FS_PCD_Init();
MX_SPI1_Init();
MX_FATFS_Init();
char test_file_fn[244] ="";
uint16_t count = 0;
sprintf(test_file_fn, "test_%i.txt", count);
char UART_Buffer[100];
uint8_t buf_len = 0;
FATFS FatFs; //Fatfs handle
FRESULT fres; //Result after operations
FIL test_file;
uint16_t bytes_read = 0;
uint16_t numBytes = 4096;
char test_array[512];
for(uint16_t i = 0; i < 512; i++)
{
test_array[i] = i;
}
test_array[1] = 0x26;
test_array[216] = 0x01;
uint16_t byteswritten = 0;
char in_byte_array[4096] = {0};
fres = BSP_SD_Init();
HAL_Delay(5000);
fres = f_mount(&SD_FatFs, (TCHAR const*)SD_Path, 0);
fres = f_open(&test_file, test_file_fn, FA_CREATE_NEW | FA_WRITE);
while(fres == FR_EXIST)
{
count += 1;
sprintf(test_file_fn, "test_%i.txt", count);
fres = f_open(&test_file, test_file_fn, FA_CREATE_NEW | FA_WRITE);
}
fres = f_write_test(&test_file, &test_array[2], 512, (void *)&byteswritten);
fres = f_close(&test_file);
while (1)
{
}
}
This is a standard library so I'm a bit confused as to what's happening at this point. I don't see the correlation of clearing the pointer to bw and issues with the input buffer.
I thought I'd check in here to see if anyone else had any ideas of what's going on? I'm legitimately stumped on this one (though it's been a long day, so maybe it makes more sense tomorrow? I have no idea). Any suggestions of what to try next would be greatly appreciated. I'm not entirely sure what to even try at this point. Thanks!
Solved! Go to Solution.
2024-02-05 07:15 PM
I do not like the cast you do to byteswritten when you call f_write_test
fres = f_write_test(&test_file, &test_array[2], 512, (void *)&byteswritten);
You are supplying a pointer to a uint16_t variable, but the function expects a pointer to a UINT.
If UINT is larger than 16 bits (and I would expect it to be on a 32-bit processor) then the function will write back e.g. FOUR bytes, clobbering the two bytes beyond byteswritten - whatever variable(s) happen to sit there. Your compiler is free to put variables in any order it chooses - nnot just the order you declared them. So I wouldn’t want to guess what gets clobbered; it could be the first two bytes of test_array.
What error/warning do you get if you omit the “(void *)” cast in that line?
2024-02-05 07:04 PM
Watch the number/size of auto/local variables
Clear this one for sure
FATFS FatFs = {0}; //Fatfs handle
2024-02-05 07:15 PM
I do not like the cast you do to byteswritten when you call f_write_test
fres = f_write_test(&test_file, &test_array[2], 512, (void *)&byteswritten);
You are supplying a pointer to a uint16_t variable, but the function expects a pointer to a UINT.
If UINT is larger than 16 bits (and I would expect it to be on a 32-bit processor) then the function will write back e.g. FOUR bytes, clobbering the two bytes beyond byteswritten - whatever variable(s) happen to sit there. Your compiler is free to put variables in any order it chooses - nnot just the order you declared them. So I wouldn’t want to guess what gets clobbered; it could be the first two bytes of test_array.
What error/warning do you get if you omit the “(void *)” cast in that line?
2024-02-06 04:47 PM
I did one better and deleted it altogether. Turns out there's an instance in fatfs.c so I just used that one (apparently, I was creating an unnecessary second instance). It doesn't look like that one is initialized though so I can do that.
Is the concern that an instance will be created with incorrect existing data from memory that could cause issues?
2024-02-06 04:50 PM - edited 2024-02-06 04:52 PM
I didn't even think about that . . . it makes sense, if it's sending a pointer rather than sending an actual data type. I changed byteswritten from a unit16_t to a uint32_t and that seemed to resolve the issue. I assume this is the correct way to resolve the issue rather than changing the cast I'm sending it (the void* was to resolve the warning I was getting about argument 4, unless I'm resolving that issue incorrectly). Without the casting, I'm getting the warning:
warning: passing argument 4 of 'f_write_test' from incompatible pointer type
Thanks so much for the insight, that was driving me crazy!