1 前言
本章测试spi tf卡示例,实现txt文件的读写。
2 源码
源码路径:
https://gitee.com/CMIOT-XinShengTech/CMIOT.CM32M4xxR_Library/tree/main/Projects/CM32M4xxR_LQFP128_STB/Examples/SPI/SPI_SD_CARD
注意一下,这里用的是CM32M4xxR_LQFP128_STB,而开发板是CM32M433R-START,对比了一下两者代码,差异不大,其中uart串口打印log使用不同口,START用的是uart4,而LQFP128_STB是uart5。
如果你在创建项目使用的是CM32M433R-START,则可以忽略这个串口差异。如果你用CM32M4xxR_LQFP128_STB,那需要使用uart5,对应的口是pin8、9。
详见https://gitee.com/CMIOT-XinShengTech/CMIOT.CM32M4xxR_Library/blob/main/Projects/CM32M4xxR_LQFP128_STB/BSP/Include/log.h。
使用CM32M4xxR_LQFP128_STB创建时可以选择spi相关的示例,然后将sdcard的main文件内容复制过去即可。
此外还要复制一下FatFs_User和FatFs文件夹到Application同级目录下。
3 添加头文件
根据上图添加头文件,即可完成编译,否则会报h文件找不到。
4 硬件
spi sdcard示例使用的是spi1。
注意不要将线接错了,如果接错了f_open会返回错误状态,比如返回3则是The physical drive cannot work。
详见ff.h中的FRESULT。
5 代码
代码就是spi sdcard示例,只是加了两个返回值判断便于分析错误。
main.c
#include <main.h>
#include <stdio.h>
#include "log.h"
#include "fatfs.h"
#include "user_diskio.h" /* defines USER_Driver as external */
/** @addtogroup CM32M4xxR_StdPeriph_Examples
* @{
*/
/** @addtogroup SPI_CRC
* @{
*/
#define BufferSize (32)
#define SPICRC
volatile SPI_InitType SPI_InitStructure;
void RCC_Configuration(void);
void GPIO_Configuration(void);
volatile FATFS fs;
volatile FATFS *pfs;
volatile FIL fil;
volatile FRESULT fres;
volatile DWORD fre_clust;
volatile uint32_t totalSpace, freeSpace;
volatile char buffer[100];
volatile char USERPath[4]; /* USER logical drive path */
/**
* @brief Main function.
*/
int main(void)
{
/*!< At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
file (startup_cm32m4xxr.s) before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_cm32m4xxr.c file
*/
log_init();
log_info("This is a SPI_SD_CARD demo-----------------------------------\r\n");
SysTick_Config(144000000/100);
/* System clocks configuration ---------------------------------------------*/
RCC_Configuration();
/* GPIO configuration ------------------------------------------------------*/
GPIO_Configuration();
/* SPI1 configuration ------------------------------------------------------*/
SPI_InitStructure.DataDirection = SPI_DIR_DOUBLELINE_FULLDUPLEX;
SPI_InitStructure.SpiMode = SPI_MODE_MASTER;
SPI_InitStructure.DataLen = SPI_DATA_SIZE_8BITS;
SPI_InitStructure.CLKPOL = SPI_CLKPOL_LOW;
SPI_InitStructure.CLKPHA = SPI_CLKPHA_FIRST_EDGE;
SPI_InitStructure.NSS = SPI_NSS_SOFT;
SPI_InitStructure.BaudRatePres = SPI_BR_PRESCALER_16;
SPI_InitStructure.FirstBit = SPI_FB_MSB;
SPI_InitStructure.CRCPoly = 0x0007;
SPI_Init(SPI1, (SPI_InitType*)&SPI_InitStructure);
/* Enable SPI1 */
SPI_Enable(SPI1, ENABLE);
uint8_t ret = 1;
ret = FATFS_LinkDriver((Diskio_drvTypeDef*)&USER_Driver, (char*)USERPath);
if(ret == 0)
printf("fatfs init ok\r\n");
else
printf("fatfs init error\r\n");
delay_ms(500);
ret = f_mount((FATFS*)&fs, "", 0);
printf("mount = %d\r\n",ret);
if( ret != FR_OK)
{
printf("error %s,line %d\r\n",__FILE__, __LINE__);
}
/* Open file to write */
ret = f_open((FIL*)&fil, "first.txt", FA_OPEN_APPEND | FA_READ | FA_WRITE);
printf("open = %d\r\n",ret);
if(ret != FR_OK)
{
printf("error %s,line %d\r\n",__FILE__, __LINE__);
}
/* Check freeSpace space */
if(f_getfree("", (DWORD*)&fre_clust, (FATFS **)&pfs) != FR_OK)
{
printf("error %s,line %d\r\n",__FILE__, __LINE__);
}
totalSpace = (uint32_t)((pfs->n_fatent - 2) * pfs->csize * 0.5);
freeSpace = (uint32_t)(fre_clust * pfs->csize * 0.5);
/* free space is less than 1kb */
if(freeSpace < 1)
{
printf("error %s,line %d\r\n",__FILE__, __LINE__);
}
/* Writing text */
f_puts("XinSheng Tech SD Card I/O Example via SPI\n", (FIL*)&fil);
f_puts("test!!!\n", (FIL*)&fil);
/* Close file */
if(f_close((FIL*)&fil) != FR_OK)
{
printf("error %s,line %d\r\n",__FILE__, __LINE__);
}
/* Open file to read */
if(f_open((FIL*)&fil, "first.txt", FA_READ) != FR_OK)
{
printf("error %s,line %d\r\n",__FILE__, __LINE__);
}
while(f_gets((char*)buffer, sizeof(buffer), (FIL*)&fil))
{
/* SWV output */
printf("%s", buffer);
fflush(stdout);
}
/* Close file */
if(f_close((FIL*)&fil) != FR_OK)
{
printf("error %s,line %d\r\n",__FILE__, __LINE__);
}
/* Unmount SDCARD */
if(f_mount(NULL, "", 1) != FR_OK)
{
printf("error %s,line %d\r\n",__FILE__, __LINE__);
}
while (1)
{
}
}
/**
* @brief Configures the different system clocks.
*/
void RCC_Configuration(void)
{
/* Enable peripheral clocks --------------------------------------------------*/
/* GPIOA, GPIOB and SPI1 clock enable */
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB | RCC_APB2_PERIPH_SPI1, ENABLE);
/* SPI2 Periph clock enable */
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_SPI2, ENABLE);
}
/**
* @brief Configures the different GPIO ports.
*/
void GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
/* Configure SPI1 pins: SCK, MISO and MOSI ---------------------------------*/
/* Confugure SCK and MOSI pins as Alternate Function Push Pull */
GPIO_InitStructure.Pin = GPIO_PIN_5 | GPIO_PIN_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Confugure MISO pin as Input Floating */
GPIO_InitStructure.Pin = GPIO_PIN_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Confugure NSS pin as Output Push Pull */
GPIO_InitStructure.Pin = GPIO_PIN_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
6 结果
从log来看文件读取成功,从sd卡中读取到确认写入成功。