cancel
Showing results for 
Search instead for 
Did you mean: 

Why does FatFS work sometimes, and sometimes not?

DMårt
Senior II

Hi!

I'm using FatFS R0.11 with STM32F373 and sometimes it works to use FATFS and sometimes not.

These are the issues I got and I don't know why.

Can it be something with NVIC interrupts that causing issues with the FatFS library?

Mount SD card:

Mount SD card -> Unmount SD card -> Unplug SD card -> Insert SD card -> Mount SD card. This will create an error for me. I cannot unmount the SD card and unplug it and then insert it back again and mount it. I get a FR_DISK_ERR then.

Notice if I re-flash the STM32 processor or go into debugging mode, then I don't get FR_DISK_ERR. But If I remove the card, plug it back, restart the STM32 processor, then I still got the FR_DISK_ERR.

Writing garbage values:

If I write a text string for example this

STM32_PLC_SD_Write_File("Hour,Minute,Second,Millisecond,");
STM32_PLC_SD_Write_File("ADC0,ADC1,ADC2,ADC3,ADC4,ADC5,ADC6,ADC7,ADC8,ADC9,ADC10,ADC11,");
	STM32_PLC_SD_Write_File("DADC0,DADC1,DADC2,DADC3,DADC4,");
	STM32_PLC_SD_Write_File("I0,I1,I2,I3,I4,I5,I6,I7,");
	STM32_PLC_SD_Write_File("E0,E1,");
	STM32_PLC_SD_Write_File("IC0,IC1,IC2,");
	STM32_PLC_SD_Write_File("DAC0,DAC1,DAC2,");
	STM32_PLC_SD_Write_File("PMW0,PWM1,PWM2,PWM3,PWM4,PWM5,PWM6,PWM7\n");
 
/* Return -1 with End of File (EOF) */
static FIL *fil;
int STM32_PLC_SD_Write_File(char text[]) {
	return f_puts(text, fil);
}

Then I got this

$� ADC ��� DADC4 I0 I1 I2 I3 I4 I5 I6 I7 E0 E1 IC0 IC1 IC2 DAC0 DAC1 DAC2 PMW0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7

Hard fault:

Sometimes I just get hard fault when I try to write this. From the beginning, it works OK. Then few seconds later, then I get hard fault. The text array is 200 bytes long.

This code loops every millisecond.

sprintf(text, "%i,%i,%i,%i,",
					hours,
					minutes,
					seconds,
					milliseconds);
			STM32_PLC_SD_Write_File(text);
 
			sprintf(text, "%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,",
					STM32_PLC_Analog_Input_ADC_Get(0),
					STM32_PLC_Analog_Input_ADC_Get(1),
					STM32_PLC_Analog_Input_ADC_Get(2),
					STM32_PLC_Analog_Input_ADC_Get(3),
					STM32_PLC_Analog_Input_ADC_Get(4),
					STM32_PLC_Analog_Input_ADC_Get(5),
					STM32_PLC_Analog_Input_ADC_Get(6),
					STM32_PLC_Analog_Input_ADC_Get(7),
					STM32_PLC_Analog_Input_ADC_Get(8),
					STM32_PLC_Analog_Input_ADC_Get(9),
					STM32_PLC_Analog_Input_ADC_Get(10),
					STM32_PLC_Analog_Input_ADC_Get(11));
			STM32_PLC_SD_Write_File(text);
 
			sprintf(text, "%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,",
					STM32_PLC_Analog_Input_DADC_Get(0),
					STM32_PLC_Analog_Input_DADC_Get(1),
					STM32_PLC_Analog_Input_DADC_Get(2),
					STM32_PLC_Analog_Input_DADC_Get(3),
					STM32_PLC_Analog_Input_DADC_Get(4));
			STM32_PLC_SD_Write_File(text);
 
			sprintf(text, "%i,%i,%i,%i,%i,%i,%i,%i,",
					STM32_PLC_Digital_Input_Get(0),
					STM32_PLC_Digital_Input_Get(1),
					STM32_PLC_Digital_Input_Get(2),
					STM32_PLC_Digital_Input_Get(3),
					STM32_PLC_Digital_Input_Get(4),
					STM32_PLC_Digital_Input_Get(5),
					STM32_PLC_Digital_Input_Get(6),
					STM32_PLC_Digital_Input_Get(7));
			STM32_PLC_SD_Write_File(text);
 
			sprintf(text, "%i,%i",
					STM32_PLC_Encoder_Get(0),
					STM32_PLC_Encoder_Get(1));
			STM32_PLC_SD_Write_File(text);
 
 
			sprintf(text, "%0.2f,%0.2f,%0.2f,",
					STM32_PLC_Input_Capture_Get(0),
					STM32_PLC_Input_Capture_Get(1),
					STM32_PLC_Input_Capture_Get(2));
			STM32_PLC_SD_Write_File(text);
 
 
			sprintf(text, "%i,%i,%i,",
					STM32_PLC_Analog_Output_Get(0),
					STM32_PLC_Analog_Output_Get(1),
					STM32_PLC_Analog_Output_Get(2));
			STM32_PLC_SD_Write_File(text);
 
			sprintf(text, "%i,%i,%i,%i,%i,%i,%i,%i\n",
					STM32_PLC_PWM_Get(0),
					STM32_PLC_PWM_Get(1),
					STM32_PLC_PWM_Get(2),
					STM32_PLC_PWM_Get(3),
					STM32_PLC_PWM_Get(4),
					STM32_PLC_PWM_Get(5),
					STM32_PLC_PWM_Get(6),
					STM32_PLC_PWM_Get(7));
			STM32_PLC_SD_Write_File(text);

This is a result when I do a "successful" logging process.

0693W00000D0tRxQAJ.png 

My SPI settings:

I'm using SPI for writing and reading to the SD card.

0693W00000D0tFIQAZ.pngThis is my FATFS configuration

/* USER CODE BEGIN Header *//** ******************************************* - Pastebin.com

Edit:

After using this library

kiwih/cubeide-sd-card: CubeIDE/CubeMX compatible MMC/SD memory card FatFs driver (github.com)

Things starting to get better now.

I don't get hard fault when I write. So that's good news.

But I get two error codes now. These two.

FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */

FR_NOT_READY, /* (3) The physical drive cannot work */

FR_DISK_ERR will I get when I unplug the SD card and plug it back again for mount.

FR_NOT_READY will I get if I turn of the power for my STM32 processor and then turn back the power again.

To "solve" FR_NOT_READY, i need to reflash the STM32 processor again. But the problems appear directly after I have replug the power (USB voltage) for my STM32 processor.

1 ACCEPTED SOLUTION

Accepted Solutions
DMårt
Senior II

I solved it now.

Step 1: Use EXACTLY the same code as the GitHub link provides.

Step 2: Use my code.

/*
 * SD_Card.c
 *
 *  Created on: Jun 15, 2021
 *      Author: Daniel Mårtensson
 */
#include "Functions.h"
#include "user_diskio_spi.h"
#include "fatfs.h"
 
/* These are extern inside fatfs.h */
FATFS USERFatFS;
FIL USERFile;
 
void STM32_PLC_Start_SD(SPI_HandleTypeDef *hspi, GPIO_TypeDef *SD_CS_PORT, uint16_t SD_CS_PIN) {
	SD_init(hspi, SD_CS_PORT, SD_CS_PIN);
}
 
FRESULT STM32_PLC_SD_Mont_Card() {
	FRESULT status;
	uint8_t attempt = 0;
	while(attempt < 255) {
		MX_FATFS_Init();
		status = f_mount(&USERFatFS, "", 1);
		if(status == FR_OK){
			break;
		} else {
			STM32_PLC_SD_Unmount_Card();
			attempt++;
		}
	}
	return status;
}
 
FRESULT STM32_PLC_SD_Unmount_Card() {
	FRESULT status = f_mount(NULL, "", 0);
	MX_FATFS_DeInit();
	return status;
}
 
FRESULT STM32_PLC_SD_Open_Existing_File_With_Read_Write(char filename[]) {
	return f_open(&USERFile, filename, FA_READ | FA_WRITE); /* Posix "r+" */
}
 
FRESULT STM32_PLC_SD_Create_New_File_With_Read_Write(char filename[], char initial_string[], bool overwrite) {
	FRESULT status;
	if(overwrite){
		/* Will always create a new file, so status will always be FR_OK */
		status = f_open(&USERFile, filename, FA_CREATE_ALWAYS | FA_READ | FA_WRITE); /* Posix "w+" */
	}else {
		/* If filename exist, then status will be FR_EXIST, else FR_OK if not exist */
		status = f_open(&USERFile, filename, FA_CREATE_NEW | FA_READ | FA_WRITE); /* Posix "w+x" */
	}
	/* If status is FR_OK, then write the initial string */
	if(status == FR_OK) {
		STM32_PLC_SD_Write_File(initial_string);
		STM32_PLC_SD_Close_File();
	}
	return status;
}
 
FRESULT STM32_PLC_SD_Close_File() {
	return f_close(&USERFile);
}
 
FRESULT STM32_PLC_SD_Check_Space(uint32_t *total_space, uint32_t *free_space) {
	FATFS *pfs;
	DWORD fre_clust;
	FRESULT status = f_getfree("", &fre_clust, &pfs);
	*total_space = (uint32_t) ((pfs->n_fatent - 2) * pfs->csize * 0.5);
	*free_space = (uint32_t) (fre_clust * pfs->csize * 0.5);
	return status;
}
 
/* Return text "error" or "eof" if it's end of file (eof) */
char* STM32_PLC_SD_Read_File(char text[], int len) {
	return f_gets(text, len, &USERFile);
}
 
/* Return -1 with End of File (EOF) */
int STM32_PLC_SD_Write_File(char text[]) {
	return f_puts(text, &USERFile);
}

Add this to user_diskio_spi.c file as well

static SPI_HandleTypeDef*   SD_SPI_HANDLE;
static GPIO_TypeDef*		SD_SPI_CS_Port;
static uint16_t 			SD_SPI_CS_Pin;
 
void SD_init(SPI_HandleTypeDef *hspi, GPIO_TypeDef *SD_CS_PORT, uint16_t SD_CS_PIN) {
	SD_SPI_HANDLE = hspi;
	SD_SPI_CS_Port = SD_CS_PORT;
	SD_SPI_CS_Pin = SD_CS_PIN;
}

Done!

Very robust. The key idea is to mount the SD card until its mounted.

View solution in original post

2 REPLIES 2
DMårt
Senior II

I solved it now.

Step 1: Use EXACTLY the same code as the GitHub link provides.

Step 2: Use my code.

/*
 * SD_Card.c
 *
 *  Created on: Jun 15, 2021
 *      Author: Daniel Mårtensson
 */
#include "Functions.h"
#include "user_diskio_spi.h"
#include "fatfs.h"
 
/* These are extern inside fatfs.h */
FATFS USERFatFS;
FIL USERFile;
 
void STM32_PLC_Start_SD(SPI_HandleTypeDef *hspi, GPIO_TypeDef *SD_CS_PORT, uint16_t SD_CS_PIN) {
	SD_init(hspi, SD_CS_PORT, SD_CS_PIN);
}
 
FRESULT STM32_PLC_SD_Mont_Card() {
	FRESULT status;
	uint8_t attempt = 0;
	while(attempt < 255) {
		MX_FATFS_Init();
		status = f_mount(&USERFatFS, "", 1);
		if(status == FR_OK){
			break;
		} else {
			STM32_PLC_SD_Unmount_Card();
			attempt++;
		}
	}
	return status;
}
 
FRESULT STM32_PLC_SD_Unmount_Card() {
	FRESULT status = f_mount(NULL, "", 0);
	MX_FATFS_DeInit();
	return status;
}
 
FRESULT STM32_PLC_SD_Open_Existing_File_With_Read_Write(char filename[]) {
	return f_open(&USERFile, filename, FA_READ | FA_WRITE); /* Posix "r+" */
}
 
FRESULT STM32_PLC_SD_Create_New_File_With_Read_Write(char filename[], char initial_string[], bool overwrite) {
	FRESULT status;
	if(overwrite){
		/* Will always create a new file, so status will always be FR_OK */
		status = f_open(&USERFile, filename, FA_CREATE_ALWAYS | FA_READ | FA_WRITE); /* Posix "w+" */
	}else {
		/* If filename exist, then status will be FR_EXIST, else FR_OK if not exist */
		status = f_open(&USERFile, filename, FA_CREATE_NEW | FA_READ | FA_WRITE); /* Posix "w+x" */
	}
	/* If status is FR_OK, then write the initial string */
	if(status == FR_OK) {
		STM32_PLC_SD_Write_File(initial_string);
		STM32_PLC_SD_Close_File();
	}
	return status;
}
 
FRESULT STM32_PLC_SD_Close_File() {
	return f_close(&USERFile);
}
 
FRESULT STM32_PLC_SD_Check_Space(uint32_t *total_space, uint32_t *free_space) {
	FATFS *pfs;
	DWORD fre_clust;
	FRESULT status = f_getfree("", &fre_clust, &pfs);
	*total_space = (uint32_t) ((pfs->n_fatent - 2) * pfs->csize * 0.5);
	*free_space = (uint32_t) (fre_clust * pfs->csize * 0.5);
	return status;
}
 
/* Return text "error" or "eof" if it's end of file (eof) */
char* STM32_PLC_SD_Read_File(char text[], int len) {
	return f_gets(text, len, &USERFile);
}
 
/* Return -1 with End of File (EOF) */
int STM32_PLC_SD_Write_File(char text[]) {
	return f_puts(text, &USERFile);
}

Add this to user_diskio_spi.c file as well

static SPI_HandleTypeDef*   SD_SPI_HANDLE;
static GPIO_TypeDef*		SD_SPI_CS_Port;
static uint16_t 			SD_SPI_CS_Pin;
 
void SD_init(SPI_HandleTypeDef *hspi, GPIO_TypeDef *SD_CS_PORT, uint16_t SD_CS_PIN) {
	SD_SPI_HANDLE = hspi;
	SD_SPI_CS_Port = SD_CS_PORT;
	SD_SPI_CS_Pin = SD_CS_PIN;
}

Done!

Very robust. The key idea is to mount the SD card until its mounted.

Thank you for sharing the solution