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            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了。

你可能感兴趣的:(stm32,C/C++,freeRTOS,stm32,嵌入式硬件,单片机)