本帖最后由 cc1989summer 于 2024-10-1 21:31 编辑
本篇分享SD卡的读写(基于FatFS)
为什么要基于FatFS呢。
理论上把SD当作EEPROM做存储用不就可以了吗。事实上这样存在的最大问题是:不兼容,单片机能识别,但因为没有文件系统,电脑、数码相机等无法识别。
用在嵌入式系统中的常用文件系统就是FatFS。(事实上还有款轻量版 Petit-FatFS:Petit FatFs 是FatFs的精简版,比较适用于低端8位/16位 单片机 中。 可以用在小RAM的单片机中,RAM可以小于扇区的RAM(512bytes)中)
详见我很早以前移植到MSP430的帖子:https://bbs.eeworld.com.cn/thread-322657-1-1.html
FatFs 是面向小型嵌入式系统的一种通用的 FAT 文件系统。它完全是由 AISI C 语言编写并且完全独立于底层的 I/O 介质。因此它可以很容易地不加修改地移植到其他的处理器当中,如 8051、 PIC、 AVR、 SH、 Z80、 H8、 ARM 等。 FatFs 支持 FAT12、 FAT16、FAT32 等格式利用文件系统的各种函数, 所以可以利用FatFs对 SPI Flash 芯片以“文件”格式进行读写操作。
FATFS优点:免费开源,专门为小型嵌入式系统设计,c编写,支持FAT12, FAT16 与 FAT32,支持多种存储媒介,有独立的缓冲区,可对多个文件进行读写,可裁剪的文件系统(极为重要)。
官方网址:
http://elm-chan.org/fsw/ff/00index_e.html
下面是FATFS的常见函数,有文件操作、目录操作、磁盘管理等。
与MCU底层紧密相关的是下图中的绿色部分:mmc.c/spi.c/device.h
言归正传:
STM32H7S78-DK使用的是SDMMC1模块(STM32H7S7L8具有两个SD模块:SDMMC1、SDMMC2)
microSD对应的接口:支持4位数据端口(SDMMC1_D0、SDMMC1_D1、SDMMC1_D2、SDMMC1_D3,很多低端MCU仅支持1位数据端口,速度较慢)
回到CubeMX,我们设置SDMMC1为4位数据:SD 4 bit wide bus
对应的GPIO就自动设置好了
在middleware and softpacks中启用FATFS,选中SD,并进行进一步参数配置,开启DMA等。
同时启用Free-RTOS,进行相关任务配置。
设置字符集为简体中文:
生成的代码中SD卡已经设置好了:
在Fatfs.c中定义两个字符串。
我们将写入到SD卡。
const static uint8_t wtext[] = "The STM32H7S78-DK Discovery kit is a complete demonstration and development platform for the Arm® Cortex®‑M7 core‑based STM32H7S7L8H6H microcontroller."; /* File write buffer */
const static uint8_t wtext1[] = "大江东去,浪淘尽,千古风流人物。故垒西边,人道是,三国周郎赤壁。乱石穿空,惊涛拍岸,卷起千堆雪。江山如画,一时多少豪杰。遥想公瑾当年,小乔初嫁了(liǎo),雄姿英(yīng)发。羽扇纶(guān)巾,谈笑间,樯橹灰飞烟灭。故国神游,多情应笑我,早生华(huā)发。人生如梦,一尊还酹(lèi)江月。"; /* File write buffer */
最为关键的FatFs 操作函数。
static void FS_FileOperations(void)
{
FRESULT res; /* FatFs function common result code */
uint32_t byteswritten, bytesread; /* File write/read counts */
//挂载SD卡到文件系统
/* Register the file system object to the FatFs module */
if(f_mount(&SDFatFs, (TCHAR const*)SDPath, 0) == FR_OK)
{
/* check whether the FS has been already created */
if (isFsCreated == 0)
{
if(f_mkfs(SDPath, &OptParm, workBuffer, sizeof(workBuffer)) != FR_OK)
{
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
return;
}
isFsCreated = 1;
}
//在SD卡上新建一个文件,把字符串1写入到文件中。
/* Create and Open a new text file object with write access */
if(f_open(&SDFile, "STM32.TXT", FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
{
/* Write data to the text file */
res = f_write(&SDFile, (const void *)wtext, sizeof(wtext), (void *)&byteswritten);
if((byteswritten > 0) && (res == FR_OK))
{
/* Close the open text file */
f_close(&SDFile);
/* Open the text file object with read access */
if(f_open(&SDFile, "STM32.TXT", FA_READ) == FR_OK)
{
/* Read data from the text file */
res = f_read(&SDFile, ( void *)rtext, sizeof(rtext), (void *)&bytesread);
if((bytesread > 0) && (res == FR_OK))
{
/* Close the open text file */
f_close(&SDFile);
/* Compare read data with the expected data */
if(bytesread == byteswritten)
{
/* Success of the demo: no error occurrence */
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
return;
}
}
}
}
}
//在SD卡上新建一个文件,把字符串2写入到文件中。
/* Create and Open a new text file object with write access */
if(f_open(&SDFile, "POEM.TXT", FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
{
/* Write data to the text file */
res = f_write(&SDFile, (const void *)wtext1, sizeof(wtext1), (void *)&byteswritten);
if((byteswritten > 0) && (res == FR_OK))
{
/* Close the open text file */
f_close(&SDFile);
/* Open the text file object with read access */
if(f_open(&SDFile, "POEM.TXT", FA_READ) == FR_OK)
{
/* Read data from the text file */
res = f_read(&SDFile, ( void *)rtext, sizeof(rtext), (void *)&bytesread);
if((bytesread > 0) && (res == FR_OK))
{
/* Close the open text file */
f_close(&SDFile);
/* Compare read data with the expected data */
if(bytesread == byteswritten)
{
/* Success of the demo: no error occurrence */
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
return;
}
}
}
}
}
我们将随开发板赠送的micro-SD安装至卡槽,运行程序。
将SD卡插入读卡器连接电脑:
发现个问题:新创建的文件没有修改日期,待后面再折腾RTC解决了。
打开文件,正是我们写入的两个字符串,可以看见中文正常显示,甚至连汉语拼音都没问题。
本次分享就到这里。