其实STM32CubeMX这款软件本身只是一个工具,它可以让我们更方便地去开发STM32,让我们更少地去关注硬件底层的关联,但这并不代表着底层硬件就不再重要了。一个优秀的嵌入式工程师往往不仅仅是关注着自己的程序是否实现基本功能,而是从硬件层面去理解整个工程或项目,这样才能尽可能地讲程序优化,用更少的资源,实现功能要求。
同样的,我的文章一般也不会仅仅去告诉大家实现某个功能需要什么操作,因为如果只是这样的话,你看了前两章软件怎么用就可以了,其他部分和标准库无非是照葫芦画瓢罢了。我是在尽量地去给大家解释清楚STM32的外设及其可以用到的资源,让大
彻底地了解STM32的某个外设有什么功能。以下将以SD卡为例展开。
我们现在常用的是Micro SD卡,尺寸非常小的,其管脚图如下。
SD卡的接口可以支持SD卡模式和SPI模式两种操作模式。
SD模式:采用6线制,使用CLK、CMD、DAT0、DAT3。其中CLK为时钟线,CMD为命令控制线,DAT0~DAT3为数据线,允许4线的高速数据传输;
SPI模式:通用的SPI通道接口,使用CS、CLK、DI、DO进行数据通信。
SD模式的数据传输速度比SPI模块要快。
使用STM32的SDIO操作SD卡即为SD模式,但部分STM32是不带SDIO的,不过我们也可以使用SPI模式来操作SD卡,还是比较方便的,这里因为主要介绍的是STM32CubeMX的SDIO外设以及HAL库相关函数的用法,所以就不多介绍SPI模式了。
SDIO主要特点如下:
其他相关介绍我就不在此多费笔墨了,毕竟这些都不是重点,说白了只需要知道SDIO可以帮助我们操作SD卡即可
在STM32F4的原理图/开发板中,一般SD卡有两种形式,第一种是micro SD,也叫TF卡,即我们最常见到的微型SD卡,另一种是SD卡,就是大卡,这两种除了大小不同之外,在操作上没有任何区别,有些TF卡可以插入SD卡套变成大卡
正点原子开发板上的是SD大卡槽,原理图如下
而另外micro SD一般是这样的
在有SDIO的芯片上,优先将SD卡接到SDIO引脚,在没有SDIO外设的芯片上,如果使用SD接口,则应当接到SPI接口
这次做的是SD卡读写实验,时钟配置主时钟仍然是最高的168M,SDIO外设挂载在APB2上,最高只能是48M,这里需要注意
ps:先把SDIO使能后才能修改SDIO的时钟,这里时钟速度用48M
基本信息设置,与之前工程的配置完全一样,这里提前提醒一下,如果仅仅是像本工程一样简单读写一下SD卡,则不需要额外的设置,但是如果需要使用到文件系统FATFS,则需要修改堆栈大小,否则导致系统卡死!,当然本工程不需要纠结这些,我这里由于是从其他工程复制过来的就没有将这个值改回去了。
使能俩灯,不一定用得到,先配置好放着,这个不懂的看《STM32CubeMX实战教程(二)——按键点个灯》
使能串口,不懂的童鞋看《STM32CubeMX实战教程(六)——串口通信(为啥你的中文会乱码)》,使能指示灯和串口是每个工程开发必备的好习惯,调试时会方便很多,懂的都懂
本章重点要来了,打开外设使能的SDIO这一栏,只有一个选项框,点开,长这样。
如果你只想知道现在要选哪个,我告诉你选SD 4 bits Wide bus就行了,但如果你想知道原因以及其他选项的意思还是要好好看下去。
废话不多说,先来一段要用到的源码,添加位置: main.c下主函数之前
HAL_SD_CardInfoTypeDef SDCardInfo;
void show_sdcard_info(void)
{
uint64_t CardCap; //SD卡容量
HAL_SD_CardCIDTypeDef SDCard_CID;
HAL_SD_GetCardCID(&hsd,&SDCard_CID); //获取CID
HAL_SD_GetCardInfo(&hsd,&SDCardInfo); //获取SD卡信息
switch(SDCardInfo.CardType)
{
case CARD_SDSC:
{
if(SDCardInfo.CardVersion == CARD_V1_X)
printf("Card Type:SDSC V1\r\n");
else if(SDCardInfo.CardVersion == CARD_V2_X)
printf("Card Type:SDSC V2\r\n");
}
break;
case CARD_SDHC_SDXC:printf("Card Type:SDHC\r\n");break;
}
CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(SDCardInfo.LogBlockSize); //计算SD卡容量
printf("Card ManufacturerID:%d\r\n",SDCard_CID.ManufacturerID); //制造商ID
printf("Card RCA:%d\r\n",SDCardInfo.RelCardAdd); //卡相对地址
printf("LogBlockNbr:%d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr)); //显示逻辑块数量
printf("LogBlockSize:%d \r\n",(uint32_t)(SDCardInfo.LogBlockSize)); //显示逻辑块大小
printf("Card Capacity:%d MB\r\n",(uint32_t)(CardCap>>20)); //显示容量
printf("Card BlockSize:%d\r\n\r\n",SDCardInfo.BlockSize); //显示块大小
}
HAL_SD_CardInfoTypeDef是获取SD卡基本信息的结构体,另外每行的作用都已经注释清楚了,用来打印SD卡的基本信息,也就是作为观察SD卡初始化是否成功的标志,PS:别忘了将串口重定向好,否则打印了个寂寞
在各外设初始化后,while循环前调用上述函数,另外在while循环中加入LED灯的闪烁以指示系统的正常运转,具体如下
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SDIO_SD_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
show_sdcard_info();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
至此,SD实验的工作已经全部完成,需先将SD卡插入开发板后下载,先后顺序不能错,因为本次实验尚未涉及SD卡插拔的检测问题,开发板也没有设计支持插拔检测的电路,需要此功能得先修改一下电路,其实也不难,就飞一条线而已,下载后串口调试助手就会打印如下字样(不同型号SD卡会有所区别)
另外由于SD卡读写往往先跟文件系统和内存管理结合,这里暂时先不提供SD卡读写的代码了
具体下载方法这里不再重复,可查看《STM32CubeMX实战教程(一)——软件入门》,工程源文件我已经上传,有串口测试版本《基于STM32CubeMX和F407的SD卡初始化实验(串口打印)》及液晶测试版本在《基于STM32CubeMX和STM32F4的SD卡初始化实验》
非常抱歉由于CSDN官网上传的资源必须要设定积分,否则几乎无法通过审核,这里就没有办法免费开发给大家,不过源码在教程里已经非常详细了。
SD卡也是开发过程中常用到的功能,同时会涉及到文件系统和内存管理等知识,使其变得比较复杂,所以本章也只是SD卡学习的第一步,大家继续加油呀!
非常感谢大家的阅读,如有不当或者错误的地方,欢迎指正,谢谢支持。
一个字一个字敲出来不容易,如果觉得有帮助,点个赞再走呗
祝大家事业蒸蒸日上!
奥里给~