• 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    1. 还有一个sdio的中断函数还要忘记了,放在stm32f10x_it.c或main.c都一样的。
    /*
     * 函数名:SDIO_IRQHandler
     * 描述  :在SDIO_ITConfig()这个函数开启了sdio中断 ,
          数据传输结束时产生中断
     * 输入  :无
     * 输出  :无
     */
    void SDIO_IRQHandler(void)
    {
      /* Process All SDIO Interrupt Sources */
      SD_ProcessIRQSrc();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293

    以上的大部分内容都是复制的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
    
    • 1
    • 2
    • 3

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

  • 相关阅读:
    ReACT介绍与llama_index ReActAgent实践
    git简介和指令
    React---路由
    2023-09-09力扣每日一题-补题
    【第92题】JAVA高级技术-网络编程11(简易聊天室6:使用Socket通信)
    CH552T可以这样接si24r1吗
    一次ES检索的性能优化经验记录
    Java面试题:什么是Java中的单元测试以及如何编写单元测试?
    华为OD机试 - 垃圾信息拦截(Java 2024 C卷 100分)
    简单的网页制作期末作业——HTML+CSS+JavaScript小礼品购物商城网站
  • 原文地址:https://blog.csdn.net/weixin_45850062/article/details/132768457