st官网给的标准库有给一个用于st出的评估板的sdio外设实现,但一是文件结构有点复杂,二是相比于国内正点原子和野火的板子也有点不同,因此还是需要移植下才能使用。当然也可以直接使用正点原子或野火提供的实例,但为了熟悉下sdio的一些知识,本人还是决定从st标准库移植一次。下面就是移植的过程。
st官方提供的10E评估板和本人使用的野火stm32f103zet6开发板可以兼容。但在TF卡插入检测有所不同。st官方的stm3210e评估板使用PF11用于卡插入检测,而stm32f103zet6开发板没有提供此检测引脚功能。
STM32F10x_StdPeriph_Lib_V3.5.0/Utilities/STM32_EVAL/Common/stm32_eval_sdio_sd.c
和STM32F10x_StdPeriph_Lib_V3.5.0/Utilities/STM32_EVAL/Common/stm32_eval_sdio_sd.h
到自己的项目中sdio_gpio.c
和sdio_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
sdio_gpio.c
文件中出现"DETECT"的地方,原因就是因为官方评估板中有DETECT引脚,而本人板子实际没有DETECT引脚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);
}
...
}
stm32f10x_it.c
或main.c都一样的。/*
* 函数名:SDIO_IRQHandler
* 描述 :在SDIO_ITConfig()这个函数开启了sdio中断 ,
数据传输结束时产生中断
* 输入 :无
* 输出 :无
*/
void SDIO_IRQHandler(void)
{
/* Process All SDIO Interrupt Sources */
SD_ProcessIRQSrc();
}
sdio_gpio.h
和stm32_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 3
uint8_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);
}
}
#endif
void 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了。