Can't get SPI working in nucleo stm32f446re and SD card

55 views Asked by At

I am trying to communicate a nucleo stm32f446re with an SD card module.

I am using SPI1, and I have configured PA4 to be CS with GPIO.

This is the code:

port_sd.c

SPI_HandleTypeDef hspi = {
        .Instance = SPI1,
        .Init = {   .Mode = SPI_MODE_MASTER,
                    .Direction = SPI_DIRECTION_2LINES,
                    .DataSize = SPI_DATASIZE_8BIT,
                    .CLKPolarity = SPI_POLARITY_LOW,
                    .CLKPhase = SPI_PHASE_1EDGE,
                    .NSS = SPI_NSS_SOFT,
                    .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256,
                    .FirstBit = SPI_FIRSTBIT_MSB,
                    .TIMode = SPI_TIMODE_DISABLE,
                    .CRCCalculation = SPI_CRCCALCULATION_DISABLE,
                    .CRCPolynomial = 0x00000001},
        .pTxBuffPtr = (uint8_t *)SPI_REG_TXFIFO,
        .TxXferSize = 1,
        .TxXferCount =0,
        .pRxBuffPtr = (uint8_t *)SPI_REG_RXFIFO,
        .RxXferSize = 1,
        .RxXferCount =0,
        .RxISR = 0,  
        .TxISR = 0,  
        .hdmatx = 0,  
        .hdmarx = 0,
        .Lock = HAL_UNLOCKED,
        .State = HAL_SPI_STATE_READY,
        .ErrorCode = HAL_OK
    };

size_t port_sd_init()
{
    __GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; //AF5 para pines SPI1

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin  = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    //HAL_SPI_RegisterCallback(&hspi,HAL_SPI_MSPINIT_CB_ID,My_SPI_MspInit);
    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
    HAL_SPI_Init(&hspi);
    SPI1 -> CR2 |= SPI_CR2_SSOE;

    return 0;
}

HAL_StatusTypeDef port_sd_transmit(uint8_t *pData, uint16_t Size, uint32_t Timeout){
    return HAL_SPI_Transmit(&hspi, pData, Size, Timeout);
}

HAL_StatusTypeDef port_sd_receive(uint8_t *pData, uint16_t Size, uint32_t Timeout){
    uint8_t dummy[1];
    dummy[0] = 0xFF;
    return HAL_SPI_TransmitReceive(&hspi, dummy, pData, Size, Timeout);
}

sd.c

uint32_t volatile * spi = (void *)0;

static inline uint8_t spi_xfer(uint8_t d) 
    uint8_t tx_data[1];
    tx_data[0] = d;
    uint8_t rx_data[1];
    REG32(spi, SPI_REG_TXFIFO) = d;
    int i = 8;

    port_sd_transmit(tx_data,1,100);
    do {
        port_sd_receive(rx_data,1,100);
        i--;
    } while ((rx_data[0] & 0b1111110) && i > 0);

    return rx_data[0];
}

static inline uint8_t sd_dummy(void) 
{
    return spi_xfer(0xFF);
}

static uint8_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) 
{
    unsigned long n;
    uint8_t r;
        
    sd_dummy();

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    uint8_t reg[6];
    reg[0] = cmd;
    reg[1] = arg >> 24;
    reg[2] = arg >> 16;
    reg[3] = arg >> 8;
    reg[4] = arg;
    reg[5] = crc;
    if(port_sd_transmit(reg,6,1000) != HAL_OK)
    {
        printf("Error de tx");
    }

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);


    n = 1000;
    do {
        r = sd_dummy();
        if (!(r & 0x80)) {
            goto done;
        }
    } while (--n > 0);
    kputs("sd_cmd: timeout");
done:
    return r;
}

static inline void sd_cmd_end(void)
{
    sd_dummy();
}

static void sd_poweron(unsigned int input_clk_khz)
{
    long i;
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    
    for (i = 10; i > 0; i--) {
        sd_dummy();
    }
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    sd_dummy();
}

static int sd_cmd0(void)
{
    int rc;
    dputs("CMD0");
    rc = (sd_cmd(0x40, 0, 0x95) != 0x01); 
    sd_cmd_end();
    return rc;
}

static int sd_cmd8(void)
{
    int rc;
    dputs("CMD8");
    rc = (sd_cmd(0x48, 0x000001AA, 0x87) != 0x01); 
    sd_dummy(); /* command version; reserved */
    sd_dummy(); /* reserved */
    rc |= ((sd_dummy() & 0xF) != 0x1); /* voltage */
    rc |= (sd_dummy() != 0xAA); /* check pattern */
    sd_cmd_end();
    return rc;
}

static void sd_cmd55(void)
{
    sd_cmd(0x77, 0, 0x65); 
    sd_cmd_end();
}

static int sd_acmd41(void)
{
    uint8_t r;
    dputs("ACMD41");
    do {
        sd_cmd55(); 
        r = sd_cmd(0x69, 0x40000000, 0x77); /* HCS = 1 */
    } while (r == 0x01); 
    return (r != 0x00);
}

static int sd_cmd58(void)
{
    int rc;
    dputs("CMD58");
    rc = (sd_cmd(0x7A, 0, 0xFD) != 0x00); 
    rc |= ((sd_dummy() & 0x80) != 0x80); /* Power up status */
    sd_dummy();
    sd_dummy();
    sd_dummy();
    sd_cmd_end();
    return rc;
}

static int sd_cmd16(void)
{
    int rc;
    dputs("CMD16");
    rc = (sd_cmd(0x50, 0x200, 0x15) != 0x00);
    sd_cmd_end();
    return rc;
}

static uint16_t crc16(uint16_t crc, uint8_t data) {      //CRC16 XMODEM
    crc = (uint8_t)(crc >> 8) | (crc << 8);
    crc ^= data;
    crc ^= (uint8_t)(crc >> 4) & 0xf;
    crc ^= crc << 12;
    crc ^= (crc & 0xff) << 5;
    return crc;
}

#define SPIN_SHIFT  6
#define SPIN_UPDATE(i)  (!((i) & ((1 << SPIN_SHIFT)-1)))
#define SPIN_INDEX(i)   (((i) >> SPIN_SHIFT) & 0x3)

static const char spinner[] = { '-', '/', '|', '\\' };

static uint8_t crc7(uint8_t prev, uint8_t in)
{
  // CRC-7 polynomial 0x89
  uint8_t remainder = prev & in;
  remainder ^= (remainder >> 4) ^ (remainder >> 7);
  remainder ^= remainder << 4;
  return remainder & 0x7f;
}

int sd_init(unsigned int input_clk_khz)
{
  kputs("INIT");
    sd_poweron(input_clk_khz);
    if (sd_cmd0() || // software reset SD
        sd_cmd8() || // check version of SD card
        sd_acmd41() || // start SD initialization process
        sd_cmd58() || //reads the OCR register of the SD (voltage range, UHS-II status, Card capacity status, Card power up status)
        sd_cmd16()) { //set block length to 512B
        kputs("ERROR");
        return 1;
    }
    return 0;
}

main.c

int main()
{
    HAL_Init();

    port_sd_init();
    
    sd_init(HSI_VALUE);
    while(1){

    }
    return 0;
}

I have checked MOSI and CS and they seem to be working correcly.

The problem is that SCK seems to never activate so MISO does not return anything.

EDIT

This are the registers after configuration:

GPIOA

MODER

PUPDR

IDR

ODR

AFRL

SPI1 REGISTERS

CRI

CR2, SR, DR

0

There are 0 answers