STM32 上的 SD 卡初始化

SD card initialization on STM32

提问人:Daniel 提问时间:9/30/2020 最后编辑:Daniel 更新时间:10/21/2020 访问量:893

问:

我尝试使用 SPI 和 FatFS 从 SD 卡读取文件,但 ACMD41 有问题。 以前,CMD0 和 CMD8 给了我正确的响应,我假设我有一个新的 v2 类型。 当我第一次发送 ACMD41 时,我得到了 CMD55 和 CMD41 的0x01响应,所以我下次发送它,除了 55 个 CLK 周期内0xff之外,我没有收到 CMD16 的其他响应,因此初始化最终返回错误。我尝试编写自己的文件来初始化卡并使用我在 Internet 上找到的现成库。我也认为SD卡没有问题,因为我已经尝试了其中的四个。

下面是代码,也许 sb 将能够找到解决方案或给我一些建议或链接到经过验证的来源。

/*
 * sd_spi.c
 *
 *  Created on: 26.11.2017
 *      Author: jaras
 */

#include "sd_spi.h"
#include <string.h>

uint8_t SDSPI_SendCMD(SPI_HandleTypeDef *phandle, uint8_t cmd, uint32_t arg, uint8_t crc) {
    uint8_t buf[6];
    buf[0] = cmd | 0x40;
    buf[1] = (arg >> 24) & 0xff;
    buf[2] = (arg >> 16) & 0xff;
    buf[3] = (arg >> 8) & 0xff;
    buf[4] = arg & 0xff;
    buf[5] = crc;

    if(HAL_SPI_Transmit(phandle, buf, 6, 1000) != HAL_OK) {
        return 1;
    }

    return 0;
}

uint8_t SDSPI_Response(SPI_HandleTypeDef *phandle, uint8_t *buf, uint16_t size) {
    uint8_t tx = 0xff;
    uint8_t rx = 0xff;
    uint8_t i = 0;

    while(rx == 0xff) {
        if(HAL_SPI_TransmitReceive(phandle, &tx, &rx, 1, 1000) != HAL_OK) {
            return 1;
        }
        i++;
        if(i > 8) {
            return 2;
        }
    }

    *buf = rx;

    for(uint16_t k = 1; k < size; k++) {
        if(HAL_SPI_TransmitReceive(phandle, &tx, &rx, 1, 1000) != HAL_OK) {
            return 1;
        }
        *(buf + k) = rx;
    }

    return 0;
}

uint8_t SDSPI_CMD(SPI_HandleTypeDef *phandle, uint8_t cmd, uint32_t arg, uint8_t crc,
                    uint8_t *response, uint8_t size) {

    HAL_GPIO_WritePin(SDSPI_CSPORT, SDSPI_CSPIN, GPIO_PIN_RESET);

    uint8_t res = SDSPI_SendCMD(phandle, cmd, arg, crc);
    if(res > 0) {
        HAL_GPIO_WritePin(SDSPI_CSPORT, SDSPI_CSPIN, GPIO_PIN_SET);
        return 1;
    }

    res = SDSPI_Response(phandle, response, size);
    if(res > 0) {
        HAL_GPIO_WritePin(SDSPI_CSPORT, SDSPI_CSPIN, GPIO_PIN_SET);
        return 2;
    }

    HAL_GPIO_WritePin(SDSPI_CSPORT, SDSPI_CSPIN, GPIO_PIN_SET);
    uint8_t tx = 0xff;
    if(HAL_SPI_Transmit(phandle, &tx, 1, 1000) != HAL_OK) {
        HAL_GPIO_WritePin(SDSPI_CSPORT, SDSPI_CSPIN, GPIO_PIN_SET);
        return 3;
    }

    return 0;
}

uint8_t SDSPI_ACMD(SPI_HandleTypeDef *phandle, uint8_t cmd, uint32_t arg, uint8_t crc,
                    uint8_t *response, uint8_t size) {
    uint8_t value0;

    uint8_t rx = 0;

    uint8_t res = SDSPI_CMD(phandle, 55, 0, 0x65, &rx, 1);
    value0=rx;
    if(res > 0) {
        return 1;
    }
    if((rx & 0xf4) > 0) {
        return 2;
    }

    res = SDSPI_CMD(phandle, cmd, arg, crc, response, size);
    if(res > 0) {
        return 3;
    }

    return 0;
}

uint8_t SDSPI_Init(SPI_HandleTypeDef *phandle) {
    uint8_t value0;
    uint8_t value1;
    uint8_t value2;
    uint8_t value3;
    uint8_t value4;

    HAL_GPIO_WritePin(SDSPI_CSPORT, SDSPI_CSPIN, GPIO_PIN_SET);
    HAL_Delay(10);
    uint8_t buf[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
    if(HAL_SPI_Transmit(phandle, buf, 10, 1000) != HAL_OK) {
        return 1; //spi error
    }

    uint8_t res = SDSPI_CMD(phandle, 0, 0, 0x95, buf, 1);
    value0 = buf[0];
    if(res > 0) {
        return 1; //command error
    }
    if(buf[0] != 1) {
        return 2; //not initialized
    }

    uint8_t type = 0;
    uint8_t block = 0;

    res = SDSPI_CMD(phandle, 8, 0x01aa, 0x87, buf, 5);
    value0 = buf[0];
    value1 = buf[1];
    value2 = buf[2];
    value3 = buf[3];
    value4 = buf[4];
    if(res > 0) {
        type = 1;
    }
    if(buf[0] != 1) {
        type = 1;
    }
    if((buf[3] & 0x0f) != 1 || buf[4] != 0xaa) {
        return 3; //initialization error
    }

    uint8_t stat = 0;
    uint32_t tickstart = 0;

    if(type == 0) {
        stat = 1;
        tickstart = HAL_GetTick();
        while(stat > 0) {
            if((HAL_GetTick()-tickstart) >= 1000) {
                HAL_GPIO_WritePin(SDSPI_CSPORT, SDSPI_CSPIN, GPIO_PIN_SET);
                return 4; //timeout
            }

            res = SDSPI_ACMD(phandle, 41, 0x40000000, 0x77, &stat, 1);
            if(res > 0) {
                return 5; //not supported
            }
        }

        res = SDSPI_CMD(phandle, 58, 0, 0x75, buf, 5);
        if(res > 0) {
            return 6; //not supported
        }
        if(buf[0] > 0) {
            return 7;
        }
        if((buf[1] & 0x04) > 0) {
            block = 1;
        }

    }
    if(type == 1) {
        stat = 1;
        tickstart = HAL_GetTick();
        while(stat > 0) {
            if((HAL_GetTick()-tickstart) >= 1000) {
                HAL_GPIO_WritePin(SDSPI_CSPORT, SDSPI_CSPIN, GPIO_PIN_SET);
                stat = 0;
                type = 2;
            }

            res = SDSPI_ACMD(phandle, 41, 0, 0xff, &stat, 1);
            if(res > 0) {
                stat = 0;
                type = 2;
            }
        }
    }
    if(type == 2) {
        stat = 1;
        tickstart = HAL_GetTick();
        while(stat > 0) {
            if((HAL_GetTick()-tickstart) >= 1000) {
                HAL_GPIO_WritePin(SDSPI_CSPORT, SDSPI_CSPIN, GPIO_PIN_SET);
                return 8; //timeout
            }

            res = SDSPI_CMD(phandle, 1, 0, 0xff, &stat, 1);
            if(res > 0) {
                return 9; //error
            }
        }
    }
    if(block == 0) {
        res = SDSPI_CMD(phandle, 16, 512, 0xff, buf, 1);
        if(res > 0) {
            return 10; //not supported
        }
        if(buf[0] > 0) {
            return 11; //error
        }
    }

    return 0;
}
  



/*
 * sd_spi.h
 *
 *  Created on: 26.11.2017
 *      Author: jaras
 */

#ifndef SD_SPI_H_
#define SD_SPI_H_

#include "stm32f3xx_hal.h"
#include "gpio.h"

#define SDSPI_CSPORT CS_PIN_GPIO_Port
#define SDSPI_CSPIN CS_PIN_Pin

uint8_t SDSPI_Init(SPI_HandleTypeDef *phandle);
uint8_t SDSPI_ReadInfo(SPI_HandleTypeDef *phandle, uint16_t *sector, uint32_t *capacity);
uint8_t SDSPI_ReadBlock(SPI_HandleTypeDef *phandle, uint32_t lba, uint8_t *buf, uint16_t size);
uint8_t SDSPI_WriteBlock(SPI_HandleTypeDef *phandle, uint32_t lba, uint8_t *buf, uint16_t size);


#endif /* SD_SPI_H_ */
C STM32 SPI 哈尔

评论

1赞 domen 9/30/2020
有人检查您的库并调试它的可能性相当低。但是,如果找到这样的人,他们将需要运行它,因此应该包含一个来证明您的问题。一般。。。注意命令顺序和时间(延迟和速度)。我认为硬件可能没问题,因为有些命令可以工作,但可能不起作用。你能检查一下,你能看到示波器上的预期内容吗?main
0赞 Daniel 10/1/2020
要运行,您只需要配置 SPI 和 CD 引脚,然后在 main 中运行SDSPI_Init。我已经添加了带有这些引脚的头文件,代码现在已经完成。很遗憾,我没有示波器
0赞 domen 10/1/2020
你正在对什么是正确的以及问题出在哪里做出许多假设。如果这是一些现有的库,那么问题很可能出在您的代码中 - 库使用、硬件配置(时钟、GPIO 等)或硬件本身。

答:

0赞 Daniel 10/21/2020 #1

问题出在SD卡上,它没有在SPI和SDIO上初始化,没有准备好FatFS库和CubeMX生成的SDIO文件。我买了一张新卡,现在它在SDIO上工作正常。我还没有在 SPI 上检查过它,但我怀疑格式有问题