Reputation: 21
I am trying my best to read data from an SD card using SPI. It works using HAL, but it's very slow, so I am trying to code my own SPI driver. I am stuck on trasnmitting data. The GPIO implementation is not faulty, so it must be the SPI implementation. I have looked at dozens of bare metal STM32 SPI implementations, and could not find any difference between mine and theirs.
void fhSpiInit(u32 pScaler)
{
fhGpioInitSystemA();
fhGpioPinSetupA(FH_GPIO_PIN_07, FH_GPIO_MODE_ALTERNATE, FH_GPIO_OTYPE_PUSH_PULL, FH_GPIO_SPEED_HIGH, FH_GPIO_PULL_NONE);
fhGpioPinSetupA(FH_GPIO_PIN_06, FH_GPIO_MODE_ALTERNATE, FH_GPIO_OTYPE_PUSH_PULL, FH_GPIO_SPEED_HIGH, FH_GPIO_PULL_NONE);
fhGpioPinSetupA(FH_GPIO_PIN_05, FH_GPIO_MODE_ALTERNATE, FH_GPIO_OTYPE_PUSH_PULL, FH_GPIO_SPEED_HIGH, FH_GPIO_PULL_NONE);
fhGpioPinSetupA(FH_GPIO_PIN_03, FH_GPIO_MODE_OUTPUT, FH_GPIO_OTYPE_PUSH_PULL, FH_GPIO_SPEED_HIGH, FH_GPIO_PULL_NONE);
fhGpioAlternateFunctionA(FH_GPIO_PIN_07, 5);
fhGpioAlternateFunctionA(FH_GPIO_PIN_06, 5);
fhGpioAlternateFunctionA(FH_GPIO_PIN_05, 5);
RCC->APB2RSTR &= ~RCC_APB2RSTR_SPI1;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
SPI1->CR1 = 0;
SPI1->CR2 = 0;
SPI1->CR1 |= pScaler;
SPI1->CR1 |= SPI_CR1_MSTR;
SPI1->CR1 |= SPI_CR1_SSM;
SPI1->CR1 |= SPI_CR1_SSI;
SPI1->CR1 |= SPI_CR1_SPE;
fhSpiCsHigh();
}
void fhSpiDeinit()
{
SPI1->CR1 &= ~SPI_CR1_SPE;
RCC->APB2ENR &= ~RCC_APB2ENR_SPI1EN;
RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST;
}
void fhSpiReInit(u32 pScaler)
{
fhSpiDeinit();
fhSpiInit(pScaler);
}
u8 fhSpiTransferByte(u8 pToWrite)
{
SPI1->DR = pToWrite;
halt(!(SPI1->SR & SPI_SR_TXE));
halt(!(SPI1->SR & SPI_SR_RXNE));
u8 ret = SPI1->DR;
printf("\tSPI1: %02x <=> %02x\n", pToWrite, ret);
return ret;
}
void fhSpiCsLow()
{
fhGpioPinWriteA(FH_GPIO_PIN_03, 0);
}
void fhSpiCsHigh()
{
fhGpioPinWriteA(FH_GPIO_PIN_03, 1);
}
Maybe my wiring is the problem. I have checked the voltages: going into the STM microcontroller is 5.06V, and going into the SD card from the STM board is 3.44V (a little high, but should be OK).
The SD card driver is not mine, I used ulibSD to minimize errors.
My implementation of ulibSD SPI functions:
/**
\brief Initialize SPI hardware
*/
void SPI_Init(void)
{
fhSpiReInit(SPI_BAUDRATEPRESCALER_256);
}
/**
\brief Read/Write a single byte.
\param d Byte to send.
\return Byte that arrived.
*/
BYTE SPI_RW(BYTE d)
{
return fhSpiTransferByte(d);
}
/**
\brief Flush of SPI buffer.
*/
void SPI_Release(void)
{
return;
}
/**
\brief Selecting function in SPI terms, associated with SPI module.
*/
void SPI_CS_Low(void)
{
fhSpiCsLow();
}
/**
\brief Deselecting function in SPI terms, associated with SPI module.
*/
void SPI_CS_High(void)
{
fhSpiCsHigh();
}
/**
\brief Setting frequency of SPI's clock to maximun possible.
*/
void SPI_Freq_High(void)
{
fhSpiReInit(SPI_BAUDRATEPRESCALER_2);
}
/**
\brief Setting frequency of SPI's clock equal or lower than 400kHz.
*/
void SPI_Freq_Low(void)
{
fhSpiReInit(SPI_BAUDRATEPRESCALER_256);
}
uint32_t gSpiTimerEnd = 0;
/**
\brief Start a non-blocking timer.
\param ms Milliseconds.
*/
void SPI_Timer_On(WORD ms)
{
gSpiTimerEnd = gSysTick + ms;
}
/**
\brief Check the status of non-blocking timer.
\return Status, TRUE if timeout is not reach yet.
*/
BOOL SPI_Timer_Status(void)
{
if (gSpiTimerEnd == -1)
{
return false;
}
if (gSysTick >= gSpiTimerEnd)
{
SPI_Timer_Off();
return false;
}
return true;
}
/**
\brief Stop of non-blocking timer. Mandatory.
*/
void SPI_Timer_Off(void)
{
gSpiTimerEnd = -1;
}
USB_VCC -> STM_5V
USB_GND -> STM_GND
SD_GND -> STM_GND
SD_VDD -> STM_3V3
SD_MOSI -> STM_MOSI1
SD_MISO -> STM_MISO1
SD_CLK -> STM_CLK1
SD_CS -> STM_A3
Edit: Forgot to paste my output log, sorry! Output:
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: 40 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 95 <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: 40 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 95 <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: 40 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 95 <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: 40 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 95 <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: 40 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 95 <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: 40 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 00 <=> ff
SPI1: 95 <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SPI1: ff <=> ff
SD_Init: 1
As you can see, the driver consistently reads 0xFF no matter what.
Upvotes: 2
Views: 71