stm32f103zet6移植标准库的sdio驱动

sdio移植

st官网给的标准库有给一个用于st出的评估板的sdio外设实现,但一是文件结构有点复杂,二是相比于国内正点原子和野火的板子也有点不同,因此还是需要移植下才能使用。当然也可以直接使用正点原子或野火提供的实例,但为了熟悉下sdio的一些知识,本人还是决定从st标准库移植一次。下面就是移植的过程。

硬件差异

st官方提供的10E评估板和本人使用的野火stm32f103zet6开发板可以兼容。但在TF卡插入检测有所不同。st官方的stm3210e评估板使用PF11用于卡插入检测,而stm32f103zet6开发板没有提供此检测引脚功能。

移植内容

  1. 复制STM32F10x_StdPeriph_Lib_V3.5.0/Utilities/STM32_EVAL/Common/stm32_eval_sdio_sd.cSTM32F10x_StdPeriph_Lib_V3.5.0/Utilities/STM32_EVAL/Common/stm32_eval_sdio_sd.h到自己的项目中
  2. 自己项目中新建一个sdio_gpio.csdio_gpio.h。复制STM32F10x_StdPeriph_Lib_V3.5.0/Utilities/STM32_EVAL/STM3210E_EVAL/stm3210e_eval.c中的几个函数实现到sdio_gpio.c文件中。这里就列出sdio_gpio.h头文件,具体函数就自己复制了。
#ifndef __SDIO_GPIO_H
#define __SDIO_GPIO_H#include "stm32f10x_conf.h"// 这里的3个宏是驱动中会使用到的,都是官方实例中复制出来的
#define SDIO_FIFO_ADDRESS                ((uint32_t)0x40018080)
/*** @brief  SDIO Intialization Frequency (400KHz max)*/
#define SDIO_INIT_CLK_DIV                ((uint8_t)0xB2)
/*** @brief  SDIO Data Transfer Frequency (25MHz max)*/
#define SDIO_TRANSFER_CLK_DIV            ((uint8_t)0x00)// 头文件中只是这几个函数的声明,函数的具体内容要复制到sd_gpio.c文件中
void SD_LowLevel_DeInit(void);
void SD_LowLevel_Init(void);
void SD_LowLevel_DMA_TxConfig(uint32_t *BufferSRC, uint32_t BufferSize);
void SD_LowLevel_DMA_RxConfig(uint32_t *BufferDST, uint32_t BufferSize);
uint32_t SD_DMAEndOfTransferStatus(void);
// 这里中断初始化改了一个名字,防止和别的外设中断初始化重名
void sdio_NVIC_Configuration(void)#endif
  1. 复制好函数体后,删除sdio_gpio.c文件中出现"DETECT"的地方,原因就是因为官方评估板中有DETECT引脚,而本人板子实际没有DETECT引脚
  2. 更改一些stm32_eval_sdio_sd.c文件中的内容
static SD_Error CmdResp2Error(void);
//这里注释了,因为在sd_gpio.c中定义了,不再是私有函数
//static uint32_t SD_DMAEndOfTransferStatus(void);
static SD_Error CmdResp6Error(uint8_t cmd, uint16_t *prca);// SD_Init()函数中加入中断初始化
SD_Error SD_Init(void)
{SD_Error errorstatus = SD_OK;/* SDIO Peripheral gpio 初始化 */SD_LowLevel_Init();SDIO_DeInit();// 中断初始化sdio_NVIC_Configuration();errorstatus = SD_PowerON();...
}// SD_GetState()删除detect内容
/*** @brief  Returns the current card's state.* @brief  因为采用data3信号线作为插入检测,因此此处不能使用SD_Detect()函数* @param  None* @retval SDCardState: SD Card Error or SD Card Current State.*/
SDCardState SD_GetState(void)
{uint32_t resp1 = 0;/*if(SD_Detect()== SD_PRESENT)*//*{*/if (SD_SendStatus(&resp1) != SD_OK){return SD_CARD_ERROR;}else{return (SDCardState)((resp1 >> 9) & 0x0F);}/*}*//*else*//*{*//*return SD_CARD_ERROR;*//*}*/
}// SD_Detect()函数全部注释了
/*** @brief  Detect if SD card is correctly plugged in the memory slot.* @brief  因为没有单独的插入检测,因此不使用此函数* @param  None* @retval Return if SD is detected or not*/
/*uint8_t SD_Detect(void)*/
/*{*//*__IO uint8_t status = SD_PRESENT;*//*[>!< Check GPIO to detect SD <]*//*if (GPIO_ReadInputDataBit(SD_DETECT_GPIO_PORT, SD_DETECT_PIN) != Bit_RESET)*//*{*//*status = SD_NOT_PRESENT;*//*}*//*return status;*/
/*}*///  SD_WriteMultiBlocks()中加入一个命令,书中说加入有用,具体不清楚
SD_Error SD_WriteMultiBlocks(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize, uint32_t NumberOfBlocks)
{SD_Error errorstatus = SD_OK;__IO uint32_t count = 0;TransferError = SD_OK;TransferEnd = 0;StopCondition = 1;SDIO->DCTRL = 0x0;if (CardType == SDIO_HIGH_CAPACITY_SD_CARD){BlockSize = 512;WriteAddr /= 512;}/*!< 根据正点原子代码加入,说明是为了防止DMA检测卡死 */SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);if (errorstatus != SD_OK){return(errorstatus);}...
}
  1. 还有一个sdio的中断函数还要忘记了,放在stm32f10x_it.c或main.c都一样的。
/** 函数名:SDIO_IRQHandler* 描述  :在SDIO_ITConfig()这个函数开启了sdio中断 ,数据传输结束时产生中断* 输入  :无* 输出  :无*/
void SDIO_IRQHandler(void)
{/* Process All SDIO Interrupt Sources */SD_ProcessIRQSrc();
}
  1. 改好后项目中加入sdio_gpio.hstm32_eval_sdio_sd.h头文件。就可以试着编译下了

加入测试代码

因为本人之前的项目中使用的freertos,且已经调通uart0串口。st官方实例是使用几个LED灯指示测试结果,本人开发板上没有这么多的灯,就直接使用串口的printf显示了,一样的方便。下面就是main.c文件。

#include "stm32f10x_conf.h"//extern __IO uint16_t ADCConvertedValue;
extern __IO uint16_t ADC_DualConvertedValueTab[4];
extern QueueHandle_t command_buf;typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
#define BLOCK_SIZE            512 /* Block Size in Bytes */#define NUMBER_OF_BLOCKS      32  /* For Multi Blocks operation (Read/Write) */
#define MULTI_BUFFER_SIZE    (BLOCK_SIZE * NUMBER_OF_BLOCKS)#define SD_OPERATION_ERASE          0
#define SD_OPERATION_BLOCK          1
#define SD_OPERATION_MULTI_BLOCK    2
#define SD_OPERATION_END            3uint8_t Buffer_Block_Tx[BLOCK_SIZE], Buffer_Block_Rx[BLOCK_SIZE];
uint8_t Buffer_MultiBlock_Tx[MULTI_BUFFER_SIZE], Buffer_MultiBlock_Rx[MULTI_BUFFER_SIZE];void SD_EraseTest(void);
void SD_SingleBlockTest(void);
void SD_MultiBlockTest(void);
void Fill_Buffer(uint8_t *pBuffer, uint32_t BufferLength, uint32_t Offset);
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint32_t BufferLength);
TestStatus eBuffercmp(uint8_t* pBuffer, uint32_t BufferLength);
SD_Error Status = SD_OK;
volatile TestStatus EraseStatus = FAILED, TransferStatus1 = FAILED, TransferStatus2 = FAILED;
__IO uint32_t SDCardOperation = SD_OPERATION_ERASE;void sdio_test_task(void *pvParameter)
{if((Status = SD_Init()) != SD_OK)printf("sdio init error");while(Status == SD_OK && SDCardOperation != SD_OPERATION_END){switch(SDCardOperation){case SD_OPERATION_ERASE:SD_EraseTest();SDCardOperation = SD_OPERATION_BLOCK;break;case SD_OPERATION_BLOCK:SD_SingleBlockTest();SDCardOperation = SD_OPERATION_MULTI_BLOCK;break;case SD_OPERATION_MULTI_BLOCK:SD_MultiBlockTest();SDCardOperation = SD_OPERATION_END;break;}}while(1){}
}void dac_task(void *pvParameter){static unsigned short num = 0xffff;for(;;){DAC_SetChannel1Data(DAC_Align_12b_L, num);DAC_SoftwareTriggerCmd(DAC_Channel_1, ENABLE);num -= 0x2;if(num < 0xff)num = 0xffff;vTaskDelay(2);}
}void system_init(void *pvParameter){SystemInit();dac_init();serial_init();//single_adc_init();muiltichannel_adc_init();command_buf = xQueueCreate(100, sizeof(struct command_t));vTaskDelete(NULL);
}void print_test_task(void *pvParameter){for(;;){printf("This just test for uart\r\n");vTaskDelay(500);}
}//void adc_task(void *pvParameter){
//	// 软件开启ADC1转换
//  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
//  for(;;){
//    printf("Current ADC voltage is %f\r\n", ADCConvertedValue * 3.3/4096);
//    vTaskDelay(5);
//  }
//}void muiltichannel_adc_task(void *pvParameter){muiltichannel_adc_enable();for(;;){printf("PA1 voltage is %.2f\r\n", ADC_DualConvertedValueTab[0] * 3.3 / 4096);printf("PA2 voltage is %.2f\r\n", ADC_DualConvertedValueTab[1] * 3.3 / 4096);printf("PA3 voltage is %.2f\r\n", ADC_DualConvertedValueTab[2] * 3.3 / 4096);printf("PA5 voltage is %.2f\r\n", ADC_DualConvertedValueTab[3] * 3.3 / 4096);vTaskDelay(2);}
}int main(void)
{xTaskCreate(system_init, "system init task", 500, NULL, 2, NULL);//xTaskCreate(print_test_task, "uart print test", 200, NULL, 1, NULL);/*xTaskCreate(dac_task, "dac task for led breath", 1000, NULL, 1, NULL);*///xTaskCreate(adc_task, "adc test task", 1000, NULL, 1, NULL);/*xTaskCreate(muiltichannel_adc_task, "mNuiltichannel adc test task", 1000, NULL, 1, NULL);*/xTaskCreate(sdio_test_task, "sdio test", 200, NULL, 1, NULL);vTaskStartScheduler();
}#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{while (1){printf("Assert error in %s, line %d\r\n",file, line);}
}
#endifvoid vApplicationStackOverflowHook( TaskHandle_t xTask,char * pcTaskName ){while (1){printf("Malloc error for %s\r\n",pcTaskName);}
}void SD_EraseTest(void)
{if (Status == SD_OK){/* Erase NumberOfBlocks Blocks of WRITE_BL_LEN(512 Bytes) */Status = SD_Erase(0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));}if (Status == SD_OK){Status = SD_ReadMultiBlocks(Buffer_MultiBlock_Rx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);/* Check if the Transfer is finished */Status = SD_WaitReadOperation();/* Wait until end of DMA transfer */while(SD_GetStatus() != SD_TRANSFER_OK);}/* Check the correctness of erased blocks */if (Status == SD_OK){EraseStatus = eBuffercmp(Buffer_MultiBlock_Rx, MULTI_BUFFER_SIZE);}if(EraseStatus == PASSED){printf("sdio erase test passed\r\n");}else{printf("sdio erase test failed\r\n");}
}void SD_SingleBlockTest(void)
{/* Fill the buffer to send */Fill_Buffer(Buffer_Block_Tx, BLOCK_SIZE, 0x320F);if (Status == SD_OK){/* Write block of 512 bytes on address 0 */Status = SD_WriteBlock(Buffer_Block_Tx, 0x00, BLOCK_SIZE);/* Check if the Transfer is finished */Status = SD_WaitWriteOperation();while(SD_GetStatus() != SD_TRANSFER_OK);}if (Status == SD_OK){/* Read block of 512 bytes from address 0 */Status = SD_ReadBlock(Buffer_Block_Rx, 0x00, BLOCK_SIZE);/* Check if the Transfer is finished */Status = SD_WaitReadOperation();while(SD_GetStatus() != SD_TRANSFER_OK);}/* Check the correctness of written data */if (Status == SD_OK){TransferStatus1 = Buffercmp(Buffer_Block_Tx, Buffer_Block_Rx, BLOCK_SIZE);}if(TransferStatus1 == PASSED){printf("sdio single block test passed\r\n");}else{printf("sdio single block test failed\r\n");}
}void SD_MultiBlockTest(void)
{/*--------------- Multiple Block Read/Write ---------------------*//* Fill the buffer to send */Fill_Buffer(Buffer_MultiBlock_Tx, MULTI_BUFFER_SIZE, 0x0);if (Status == SD_OK){/* Write multiple block of many bytes on address 0 */Status = SD_WriteMultiBlocks(Buffer_MultiBlock_Tx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);/* Check if the Transfer is finished */Status = SD_WaitWriteOperation();while(SD_GetStatus() != SD_TRANSFER_OK);}if (Status == SD_OK){/* Read block of many bytes from address 0 */Status = SD_ReadMultiBlocks(Buffer_MultiBlock_Rx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);/* Check if the Transfer is finished */Status = SD_WaitReadOperation();while(SD_GetStatus() != SD_TRANSFER_OK);}/* Check the correctness of written data */if (Status == SD_OK){TransferStatus2 = Buffercmp(Buffer_MultiBlock_Tx, Buffer_MultiBlock_Rx, MULTI_BUFFER_SIZE);}if(TransferStatus2 == PASSED){printf("sdio muilti block test passed\r\n");}else{printf("sdio muilti block test error\r\n");}
}TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint32_t BufferLength)
{while (BufferLength--){if (*pBuffer1 != *pBuffer2){return FAILED;}pBuffer1++;pBuffer2++;}return PASSED;
}void Fill_Buffer(uint8_t *pBuffer, uint32_t BufferLength, uint32_t Offset)
{uint16_t index = 0;/* Put in global buffer same values */for (index = 0; index < BufferLength; index++){pBuffer[index] = index + Offset;}
}TestStatus eBuffercmp(uint8_t* pBuffer, uint32_t BufferLength)
{while (BufferLength--){/* In some SD Cards the erased state is 0xFF, in others it's 0x00 */if ((*pBuffer != 0xFF) && (*pBuffer != 0x00)){return FAILED;}pBuffer++;}return PASSED;
}

以上的大部分内容都是复制的STM32F10x_StdPeriph_Lib_V3.5.0/Project/STM32F10x_StdPeriph_Examples/SDIO/uSDCard/main.c的内容。只是在此基础上加入了freertos的格式,将测试最后通过和出错的提示方式全部使用串口打印出来。
下面是串口显示的打印结果:

sdio erase test passed
sdio single block test passed
sdio muilti block test passed

至此sdio基本驱动移植成功,可以移植fatfs了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/72978.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高频golang面试题:简单聊聊内存逃逸?

文章目录 问题怎么答举例 问题 知道golang的内存逃逸吗&#xff1f;什么情况下会发生内存逃逸&#xff1f; 怎么答 golang程序变量会携带有一组校验数据&#xff0c;用来证明它的整个生命周期是否在运行时完全可知。如果变量通过了这些校验&#xff0c;它就可以在栈上分配。…

【力扣】96. 不同的二叉搜索树 <动态规划>

【力扣】96. 不同的二叉搜索树 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5 示例 2&#xff1a; 输入&am…

Java并发编程AQS

AQS AQS 是多线程同步器&#xff0c;它是 J.U.C 包中多个组件的底层实现&#xff0c;如 Lock、 CountDownLatch、Semaphore 等都用到了 AQS. 锁机制 从本质上来说&#xff0c;AQS 提供了两种锁机制&#xff0c;分别是排它锁&#xff0c;和共享锁。 排他锁 排它锁&#xff…

MYSQL学习之——管理用户

MYSQL学习之——管理用户&#xff08;DCL&#xff09; 用户这个东西其实是一个和TABLE DATABASE 这种东西一样的并列关键字。 用户的管理无外乎几个操作 查看用户 添加用户 删除用户 更新用户名或密码 改变用户对数据库的操作权限。 MYSQL语句功能备注USE mysql; select * FR…

代码随想录算法训练营第38天 | ● 理论基础 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯

文章目录 前言一、理论基础二、509. 斐波那契数三、70. 爬楼梯四、746. 使用最小花费爬楼梯总结 前言 动态规划 一、理论基础 1.基础 2.背包问题 3.打家劫舍 4.股票问题 5.子序列问题 动态规划&#xff0c;英文&#xff1a;Dynamic Programming&#xff0c;简称DP&#xff0c;…

【美团3.18校招真题1】

大厂笔试真题网址&#xff1a;https://codefun2000.com/ 塔子哥刷题网站博客&#xff1a;https://blog.codefun2000.com/ 小美剪彩带 提交网址&#xff1a;https://codefun2000.com/p/P1088 题意&#xff1a;找出区间内不超过k种数字子数组的最大长度 使用双指针的方式&…

@Builder注解有什么用?怎么用?

在Java中&#xff0c;Builder注解通常与项目构建工具Lombok一起使用&#xff0c;用于自动生成一个建造者&#xff08;Builder&#xff09;模式相关的代码&#xff0c;以简化对象的创建和初始化过程。 使用Builder注解的类会自动生成一个内部静态的建造者类&#xff0c;该建造者…

小程序的使用

微信小程序开发 外部链接别人的总结查看&#xff08;超详细保姆式教程&#xff09; 基础语法 1.数据绑定 1.1 初始化数据 页面.js的data选项中Page({data: {motto: Hello World,id:18} })使用数据 单项数据流&#xff1a;Mustache 语法 a)模板结构中使用双大括号 {{data}} …

安装程序报错“E: Sub-process /usr/bin/dpkg returned an error code (1)”的解决办法

今天在终端使用命令安装程序时出现了如下的报错信息。 E: Sub-process /usr/bin/dpkg returned an error code (1) 这种情况下安装什么程序最终都会报这个错&#xff0c;具体的报错截图如下图所示。 要解决这个问题&#xff0c;首先使用下面的命令进到相应的目录下。 cd /var/…

Java“牵手”唯品会商品列表数据,关键词搜索唯品会商品数据接口,唯品会API申请指南

唯品会商城是一个网上购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取唯品会商品列表和商品详情页面数据&#xff0c;您可以通过开放平台的接口或者直接访问唯品会商城的网页来获取商品详情信息。以下是两种常用方法的介…

Python bug: TypeError: unhashable type: ‘dict‘ or ‘list‘

Python bug: TypeError: unhashable type: ‘dict‘ or ‘list’ 经过排除&#xff0c;发现我遇到的错误是由于字典的键使用了【字典】或【列表】变量。 由于有时候会将一些变量赋值给字典&#xff0c;通常键的名称直接使用变量名称&#xff0c;但有时不小心键的名称没有变成字…

IDEA快捷键第二版

1、选择当前行和上一行 按住 Shift键 再按两下向上键&#xff08; ↑ &#xff09;&#xff0c;按两下选两行&#xff0c;以此类推 2、将整个方法上移动 文本光标应放在方法的标头处&#xff0c;按住Ctrl Shift 向上键&#xff08; ↑ &#xff09;&#xff0c; 3、解包 …

RabbitMQ的Confirm机制

1.消息的可靠性 RabbitMQ提供了Confirm的确认机制。 Confirm机制用于确认消息是否已经发送给了交换机 2.Java的实现 1.导入依赖 <dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.6.0</v…

MVCC究竟是什么?

&#xff11;.MVCC概念 MVCC&#xff0c;全称多版本并发控制 MVCC究竟是什么&#xff1f; 通俗的来说MVCC就是为了在读取数据时不加锁来提高读取效率的一种办法&#xff0c;MVCC解决的是读写时线程安全问题&#xff0c;线程不用去抢占读写锁。MVCC中的读就是快照读&#xff0c…

初识计算机和命令行操作

文章目录 计算机基础知识计算机是什么计算机的组成计算机的使用方式Windows的命令行环境变量&#xff08;Environment Variable&#xff09;PATH环境变量进制文本文件和字符集纯文本和富文本字符集乱码 python专栏推荐&#xff1a;python基础知识&#xff08;0基础入门&#xf…

无涯教程-JavaScript - DELTA函数

描述 DELTA函数测试两个值是否相等。如果number1 number2,则返回1&#xff1b;否则返回1。否则返回0。 您可以使用此功能来过滤一组值。如,通过合计几个DELTA函数,您可以计算相等对的计数。此功能也称为Kronecker Delta功能。 语法 DELTA (number1, [number2])争论 Argum…

window mysql-8.0.34 zip解压包安装

window系统上安装mysql8 解压版 下载压缩包 https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.34-winx64.zip安装 用解压软件解压刚下载的mysql-8.0.34-winx64.zip 的文件至d:\devs路径下。 创建配置文件my.ini到路径d:\devs\mysql-8.0.34-winx64下 [mysqld] # 设置…

Postman接口测试之Mock快速入门

一、Mock简介 1.Mock定义 Mock是一种比较特殊的测试技巧&#xff0c;可以在没有依赖项的情况下进行接口或单元测试。通常情况下&#xff0c;Mock与其他方法的区别是&#xff0c;用于模拟代码依赖对象&#xff0c;并允许设置对应的期望值。简单一点来讲&#xff0c;就是Mock创建…

CSS 滚动驱动动画 scroll()

CSS 滚动驱动动画 scroll() animation-timeline 通过 scroll() 指定可滚动元素与滚动轴来为容器动画提供一个匿名的 scroll progress timeline. 通过元素在顶部和底部(或左边和右边)的滚动推进 scroll progress timeline. 并且元素滚动的位置会被转换为百分比, 滚动开始被转化为…

Vue3中快速简单使用CKEditor 5富文本编辑器

Vue3简单使用CKEditor 5 前言准备定制基础配置富文本配置目录当前文章demo目录结构 快速使用demo 前言 CKEditor 5就是内嵌在网页中的一个富文本编辑器工具 CKEditor 5开发文档&#xff08;英文&#xff09;&#xff1a;https://ckeditor.com/docs/ckeditor5/latest/index.htm…