工程创建
Resc进行可视化配置工程
选定芯片型号
配置SDIO底层驱动(SD card)![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/1bab6c83188abb75e4923c67552ae4d9.png)
跳到对应GPIO,进行复用
将Operation Mode配置 SD_MMC 4Bit,系统会自动配置
会到stacks
根据上面提示,解决错误。
解决第一个error
SDHI配置
SD配置信息
以上SD卡底层配置完成
使用串口作为Debug 日志输出
SCI/UART
UART复用
uart配置
最后构建工程,工程构建完成。
debug 日志输出编写
/* 调试串口 UART0 初始化 */
void Debug_UART0_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_SCI_UART_Open (&g_uart0_ctrl, &g_uart0_cfg);
assert(FSP_SUCCESS == err);
}
/* 发送完成标志 */
volatile bool uart_send_complete_flag = false;
void debug_uart0_callback(uart_callback_args_t * p_args)
{
switch (p_args->event)
{
case UART_EVENT_RX_CHAR:
{
/* 把串口接收到的数据发送回去 */
R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)&(p_args->data), 1);
break;
}
case UART_EVENT_TX_COMPLETE:
{
uart_send_complete_flag = true;
break;
}
default:
break;
}
}
/* 重定向 printf 输出 */
#if defined __GNUC__ && !defined __clang__
int _write(int fd, char *pBuffer, int size); //防止编译警告
int _write(int fd, char *pBuffer, int size)
{
(void)fd;
R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)pBuffer, (uint32_t)size);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return size;
}
#else
int fputc(int ch, FILE *f)
{
(void)f;
R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)&ch, 1);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return ch;
}
#endif
验证输出
void hal_entry(void)
{
/* TODO: add your own code here */
Debug_UART0_Init();
while(1)
{
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
printf("小昭debug\r\n");
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
SD card 初始化
FSPy已经写好了接口 直接调用就行
初始化SD card
void SDCard_Init(void)
{
fsp_err_t err;
/* 打开SDHI */
err = g_sdmmc_on_sdhi.open(&g_sdmmc0_ctrl, &g_sdmmc0_cfg);
assert(FSP_SUCCESS == err);
}
中断回调函数
__IO uint32_t g_transfer_complete = 0;
__IO uint32_t g_card_erase_complete = 0;
__IO bool g_card_inserted = false;
void g_sdnnc0_back(sdmmc_callback_args_t *p_args)
{
if (SDMMC_EVENT_TRANSFER_COMPLETE == p_args->event) //读取或写入完成
{
g_transfer_complete = 1;
}
if (SDMMC_EVENT_CARD_INSERTED == p_args->event) //卡插入中断
{
g_card_inserted = true;
}
if (SDMMC_EVENT_CARD_REMOVED == p_args->event) //卡拔出中断
{
g_card_inserted = false;
}
if (SDMMC_EVENT_ERASE_COMPLETE == p_args->event) //擦除完成
{
g_card_erase_complete = 1;
}
if (SDMMC_EVENT_ERASE_BUSY == p_args->event) //擦除超时
{
g_card_erase_complete = 2;
}
}
SDMMC事件
测试验证读写SD卡功能
g_sdmmc_on_sdhi.statusGet(&g_sdmmc0_ctrl, &status); //先判断SD卡是否被插上
g_sdmmc_on_sdhi.mediaInit(&g_sdmmc0_ctrl, &my_sdmmc_device);//确保sd卡被插上时,在初始化
g_sdmmc_on_sdhi.write(&g_sdmmc0_ctrl, g_src, 1, 1); //写数据 前面设置了,写入512字节,512为一块 在第一个sector地址写入一个块大小的数据
g_sdmmc_on_sdhi.read(&g_sdmmc0_ctrl, g_dest, 1, 1); //读数据
移植FAT32文件系统
FatFs 官网
FatFs 源码下载连接
下载源代码
document 介绍FAT32介绍、使用和移植,非常友好。
可以支持64位寻址
FAT限制
• 文件系统类型: FAT、 FAT32(rev0.0)和 exFAT(rev1.0)。
• 打开的文件数量:无限制。(取决于可用内存)
• 卷数:最多 10 个。
• 扇区大小: 512、 1024、 2048 和 4096 字节。
• 最小卷大小: 128 个扇区。
• 最大卷大小: 32 位 LBA 中的 2^32 - 1 扇区,在带有 exFAT 的 64 位 LBA 中几乎不受限制。
• 最大文件大小: FAT 卷上为 2^32 - 1 字节, exFAT 卷上几乎不受限制。
• 群集大小: FAT 卷上最多 128 个扇区, exFAT 卷上最多 16 MB。
目标:
简单实现文件读写和创建
会涉及到IO层中diskio.c/.h,以及配置文件 ffconf.h。
diskio.c
/* 为每个设备定义一个物理编号 */
#define ATA 0 // SD 卡
#define QSPI_FLASH 1 // 外部 QSPI Flash
// SD 卡块大小
#define SD_BLOCKSIZE 512
//
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat = 0;
switch (pdrv) {
case ATA : /* SD CARD */
stat = RES_OK;
return stat;
case QSPI_FLASH : /* QSPI FLASH */
break;
}
return STA_NOINIT;
}
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
fsp_err_t err;
switch (pdrv) {
case ATA : /* SD CARD */
/* Open the SDHI driver. */
err = g_sdmmc_on_sdhi.open(&g_sdmmc0_ctrl, &g_sdmmc0_cfg);
assert(FSP_SUCCESS == err);
/* 设备应在检测到VDD最小值后1ms内准备好接受第一个命令。参考SD物理层简化规范6.00版第6.4.1.1节“卡的通电时间”。 */
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
/* Initialize the SD card. This should not be done until the card is plugged in for SD devices. */
err = g_sdmmc_on_sdhi.mediaInit(&g_sdmmc0_ctrl, &my_sdmmc_device);
assert(FSP_SUCCESS == err);
stat = RES_OK;
return stat;
case QSPI_FLASH : /* QSPI FLASH */
break;
}
return STA_NOINIT;
}
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
DRESULT res = RES_PARERR;
fsp_err_t err;
switch (pdrv) {
case ATA : /* SD CARD */
err = g_sdmmc_on_sdhi.read(&g_sdmmc0_ctrl, buff, sector, count);
assert(FSP_SUCCESS == err);
while (g_transfer_complete == 0);
g_transfer_complete = 0;
res = RES_OK;
return res;
case QSPI_FLASH : /* QSPI FLASH */
break;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
DRESULT res = RES_PARERR;
fsp_err_t err;
switch (pdrv) {
case ATA : /* SD CARD */
err = g_sdmmc_on_sdhi.write(&g_sdmmc0_ctrl, buff, sector, count);
assert(FSP_SUCCESS == err);
while (g_transfer_complete == 0);
g_transfer_complete = 0;
res = RES_OK;
return res;
case QSPI_FLASH : /* QSPI FLASH */
break;
}
return RES_PARERR;
}
#endif
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
switch (pdrv) {
case ATA : /* SD CARD */
switch (cmd)
{
// 扇区大小。仅当FF_MAX_SS > FF_MIN_SS时,才需要此命令。
case GET_SECTOR_SIZE :
*(WORD * )buff = (WORD)my_sdmmc_device.sector_size_bytes;
break;
// 擦除块大小(以扇区为单位)
case GET_BLOCK_SIZE :
*(DWORD * )buff = my_sdmmc_device.erase_sector_count;
break;
//可用扇区数
case GET_SECTOR_COUNT:
*(DWORD * )buff = my_sdmmc_device.sector_count;
break;
case CTRL_SYNC :
break;
}
res = RES_OK;
return res;
case QSPI_FLASH : /* QSPI FLASH */
break;
}
return RES_PARERR;
}
//ffconf.h
#define FF_VOLUMES 2
#define FF_FS_NORTC 1 //关闭时间戳
测试验证
g_sdmmc_on_sdhi.statusGet(&g_sdmmc0_ctrl, &status);
g_sdmmc_on_sdhi.mediaInit(&g_sdmmc0_ctrl, &my_sdmmc_device);
f_mount(&fs, "0:", 1); //挂载
f_mkfs("0:", NULL, work, sizeof(work)); f_setlabel()//没有文件系统,进行格式化 设置盘符名称
f_open(&fnew, "0:FatFs_debug.txt", FA_CREATE_ALWAYS | FA_WRITE);
f_close(&fnew);
f_open(&fnew, "0:FatFs_debug.txt", FA_OPEN_EXISTING | FA_READ);
f_close(&fnew);
f_mount(NULL, "0:", 1);