美文网首页我爱编程
运动控制器26:STM32如何读写一张SD卡

运动控制器26:STM32如何读写一张SD卡

作者: 吴松乾 | 来源:发表于2018-01-29 14:15 被阅读0次

    如何描述一张物理SD卡

    描述SD卡的结构体

    我们用4个结构体来完整描述一张物理的SD卡

    struct   SD_CardInfo  // SD_GetCardInfo用到,获取SD卡的信息
        uint32_t  CardBlockSize 
        uint32_t  CardCapacity 
        uint8_t  CardType 
        uint16_t  RCA 
    struct   SD_CardStatus 
        __IO uint8_t  AU_SIZE 
        __IO uint8_t  DAT_BUS_WIDTH 
        __IO uint8_t  ERASE_OFFSET 
        __IO uint16_t  ERASE_SIZE 
        __IO uint8_t  ERASE_TIMEOUT 
        __IO uint8_t  PERFORMANCE_MOVE 
        __IO uint16_t  SD_CARD_TYPE 
        __IO uint8_t  SECURED_MODE 
        __IO uint32_t  SIZE_OF_PROTECTED_AREA 
        __IO uint8_t  SPEED_CLASS 
    struct   SD_CID 
        __IO uint8_t  CID_CRC 
        __IO uint16_t  ManufactDate 
        __IO uint8_t  ManufacturerID 
        __IO uint16_t  OEM_AppliID 
        __IO uint32_t  ProdName1 
        __IO uint8_t  ProdName2 
        __IO uint8_t  ProdRev 
        __IO uint32_t  ProdSN 
        __IO uint8_t  Reserved1 
        __IO uint8_t  Reserved2 
    
    struct   SD_CSD 
        //这个描述比较多,只截取了一部分
        __IO uint16_t  CardComdClasses 
        __IO uint8_t  ContentProtectAppli 
        __IO uint8_t  CopyFlag 
        __IO uint8_t  CSD_CRC 
    
    

    所有的SD卡操作命令

    初始化卡的时候,我们需要所有的SD卡发送CID,我们用到了下面的结构体生成一条命令:

    00673     /*!< Send CMD2 ALL_SEND_CID */
    00674     SDIO_CmdInitStructure.SDIO_Argument = 0x0;
    00675     SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ALL_SEND_CID;
    00676     SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;
    00677     SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    00678     SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    00679     SDIO_SendCommand(&SDIO_CmdInitStructure);
    
    

    而SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ALL_SEND_CID;则指示这条命令的功能,这样的命令对于SD卡还有很多,下面的三条命令是最通用的命令,三条命令的功能显而易见,比如设置总线宽度的命令,在SDEnWideBus().就用到
    如下:

    #define  SD_CMD_ALL_SEND_CID   ((uint8_t)2) 
    #define  SD_CMD_APP_CMD   ((uint8_t)55) 
    #define  SD_CMD_APP_SD_SET_BUSWIDTH   ((uint8_t)6) 
    
    

    下面的7条命令,主要针对的是SD卡的特殊操作,比如清写的端口,以及3条擦除命令,最后一条命令很常用,用于SD_GoIdleState(), and SD_PowerON().两个函数中。

    #define  SD_CMD_CLR_WRITE_PROT   ((uint8_t)29) 
    #define  SD_CMD_ERASE   ((uint8_t)38) 
    #define  SD_CMD_ERASE_GRP_END   ((uint8_t)36) 
    #define  SD_CMD_ERASE_GRP_START   ((uint8_t)35) 
    #define  SD_CMD_FAST_IO   ((uint8_t)39) 
    #define  SD_CMD_GEN_CMD   ((uint8_t)56) 
    #define  SD_CMD_GO_IDLE_STATE   ((uint8_t)0) 
    
    

    下面是SD卡的APP命令,主要针对特殊安全命令:

    #define  SD_CMD_SD_APP_OP_COND   ((uint8_t)41) 
    #define  SD_CMD_SD_APP_SECURE_ERASE   ((uint8_t)38) 
    #define  SD_CMD_SD_APP_SECURE_READ_MULTIPLE_BLOCK   ((uint8_t)18) 
    #define  SD_CMD_SD_APP_SECURE_WRITE_MKB   ((uint8_t)48) 
    #define  SD_CMD_SD_APP_SECURE_WRITE_MULTIPLE_BLOCK   ((uint8_t)25) 
    #define  SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS   ((uint8_t)22) 
    #define  SD_CMD_SD_APP_SEND_SCR   ((uint8_t)51) 
    #define  SD_CMD_SD_APP_SET_CER_RES2   ((uint8_t)47) 
    #define  SD_CMD_SD_APP_SET_CER_RN1   ((uint8_t)45) 
    #define  SD_CMD_SD_APP_SET_CLR_CARD_DETECT   ((uint8_t)42) 
    #define  SD_CMD_SD_APP_STAUS   ((uint8_t)13) 
    #define  SD_CMD_SD_ERASE_GRP_END   ((uint8_t)33) 
    #define  SD_CMD_SD_ERASE_GRP_START   ((uint8_t)32) 
    #define  SD_CMD_SDIO_RW_DIRECT   ((uint8_t)52) 
    #define  SD_CMD_SDIO_RW_EXTENDED   ((uint8_t)53) 
    #define  SD_CMD_SDIO_SEN_OP_COND   ((uint8_t)5) 
    #define  SD_CMD_SEL_DESEL_CARD   ((uint8_t)7) 
    #define  SD_CMD_SEND_CID   ((uint8_t)10) 
    #define  SD_CMD_SEND_CSD   ((uint8_t)9) 
    #define  SD_CMD_SEND_OP_COND   ((uint8_t)1) 
    #define  SD_CMD_SEND_STATUS   ((uint8_t)13) 
    #define  SD_CMD_SEND_WRITE_PROT   ((uint8_t)30) 
    #define  SD_CMD_SET_BLOCK_COUNT   ((uint8_t)23) 
    #define  SD_CMD_SET_BLOCKLEN   ((uint8_t)16) 
    #define  SD_CMD_SET_DSR   ((uint8_t)4) 
    #define  SD_CMD_SET_REL_ADDR   ((uint8_t)3) 
    #define  SD_CMD_SET_WRITE_PROT   ((uint8_t)28) 
    #define  SD_CMD_STOP_TRANSMISSION   ((uint8_t)12) 
    #define  SD_CMD_WRITE_DAT_UNTIL_STOP   ((uint8_t)20) 
    #define  SD_CMD_WRITE_MULT_BLOCK   ((uint8_t)25) 
    #define  SD_CMD_WRITE_SINGLE_BLOCK   ((uint8_t)24) 
    #define  SD_DMA_MODE   ((uint32_t)0x00000000) 
    #define  SD_NOT_PRESENT   ((uint8_t)0x00) 
    #define  SD_PRESENT   ((uint8_t)0x01) 
    
    

    SD卡初始化和配置

    初始化用到SD_Init() 函数,函数调用以后,SD卡进入待机模式,可以进行读写,初始化的流程如下:

    1. 设置时钟,检查卡型号(标准还是大容量),频率的公式如下:SDIO_CK = SDIOCLK / (SDIO_INIT_CLK_DIV + 2),标准卡不要超过400KHZ。
    2. 获取CID和CSD数据,这些数据我们保存在SDCardInfo的结构体中。
    3. 配置数据传输频率,一般设置为24MHZ,通过配置SDIO_TRANSFER_CLK_DIV
    4. 选中发回响应的SD卡,见第二步的操作。
    5. 配置SD卡的总线宽度为4位。

    SD卡读操作

    1. SD_ReadBlock()和SD_ReadMultiBlocks() 函数可以用于读512字节长度的数据。
    2. SD_ReadBlock可以读取512字节的数据,可以通过DMA或者轮询模式读取,默认为DMA模式
    3. SD_ReadMultiBlocks可以读取512的倍数。
    4. 每一次读操作都需要调用两个函数SD_ReadWaitOperation获取DMA状态和SD_GetStatus获取SD卡状态,确保数据传输完成后再进行下一步。
    5. DMA数据完成后中断,调用SD_ProcessIRQ()函数进入中断函数,记得使能中断SDIO_IRQn 。

    SD卡写操作

    1. 同样有两个函数可以执行写操作:WriteBlock和WriteMultiBlocks,长度也是512s
    2. 同上支持512,支持DMA或者轮询。
    3. 以及支持512的倍数
    4. 和读操作一样,我们也需要在每次通信时查询SD模块和SD卡的状态。
    5. 以及设置好中断。

    SD卡状态获取

    1. 任何时候我们都可以获取SD卡的状态通过GetStatus,我们只需要确保SD硬件连接即可调用此函数。
    2. 也可以直接查寄存器用SendSDStatus函数。

    SD卡编程示范

        Status = SD_Init(); // Initialization Step as described in section A
        // SDIO Interrupt ENABLE
        NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    
        // Write operation as described in Section C
        Status = SD_WriteBlock(buffer, address, 512);
        Status = SD_WaitWriteOperation();
        while(SD_GetStatus() != SD_TRANSFER_OK); 
                
        Status = SD_WriteMultiBlocks(buffer, address, 512, NUMBEROFBLOCKS);
        Status = SD_WaitWriteOperation();
        while(SD_GetStatus() != SD_TRANSFER_OK);     
    
        Read operation as described in Section B
        Status = SD_ReadBlock(buffer, address, 512);
        Status = SD_WaitReadOperation();
        while(SD_GetStatus() != SD_TRANSFER_OK);
    
        Status = SD_ReadMultiBlocks(buffer, address, 512, NUMBEROFBLOCKS);
        Status = SD_WaitReadOperation();
        while(SD_GetStatus() != SD_TRANSFER_OK);    
    

    SD卡引脚分配

    引脚 功能
    D2 总线
    D3 总线
    CMD 命令
    VCC 3.3V
    CLK 时钟
    GND 0
    D0 总线
    D1 总线

    相关文章

      网友评论

        本文标题:运动控制器26:STM32如何读写一张SD卡

        本文链接:https://www.haomeiwen.com/subject/xnpxzxtx.html