I am trying to transmit data from a stm32F411 master to a stm32F411 slave device. The data will be used to configure and write data to a SD card attached to the slave. I am using the slave to offload the work of transferring data to the SD card. The SPI on the slave side is handled by polling, no DMA or interrupts are used. Both projects are setup using CubeIDE.
The problem is that the slave does not seem to be receive the data correctly as it is either corrupted, shifted in some way or is missing characters. The slave is also not transmitting the data back to the master correctly, only sending what looks like dummy data.
Master SPI config:
static void MX_SPI3_Init(void) {
hspi3.Instance = SPI3;
hspi3.Init.Mode = SPI_MODE_MASTER;
hspi3.Init.Direction = SPI_DIRECTION_2LINES;
hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi3.Init.NSS = SPI_NSS_SOFT;
hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi3.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi3) != HAL_OK) {
Error_Handler();
}
}
Slave SPI config:
static void MX_SPI1_Init(void)
{
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_SLAVE;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_HARD_INPUT;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
}
Master logic and example input:
sd_open_file("Quadcopter.txt", FA_WRITE | FA_READ | FA_OPEN_ALWAYS);
uint8_t sd_open_file(const char *file_name, uint8_t instruction){
uint8_t response[1];
uint8_t command = LOGGER_SD_OPEN_FILE;
uint16_t file_length = strlen(file_name)+1;
uint16_t total_length = file_length+1;
uint8_t transmit_length[] = {(total_length >> 8) & 0xFF, total_length & 0xFF};
uint8_t transmit_buffer[total_length]; // string length, \0 and command
transmit_buffer[0] = instruction;
memcpy(&transmit_buffer[1], file_name, file_length); // Copy the string including null terminator.
HAL_StatusTypeDef status;
slave_select();
status = HAL_SPI_Transmit(m_device_handle, &command, 1, 5000); // send command
status = HAL_SPI_Transmit(m_device_handle, transmit_length, 2, 5000); // send how many bytes the dat will be
status = HAL_SPI_Transmit(m_device_handle, transmit_buffer, total_length, 5000); // send data
status = HAL_SPI_Receive(m_device_handle, response, 1, 5000);
uint8_t data[200];
status = HAL_SPI_Receive(m_device_handle, data, total_length, 1000);
slave_deselect();
...
}
Slave logic:
HAL_StatusTypeDef spi_slave_result_receive = HAL_SPI_Receive(&hspi1, slave_buffer, 1, 1000);
...c
HAL_StatusTypeDef status_receive;
// We ask how much data should we receive.
if((status_receive = HAL_SPI_Receive(&hspi1, slave_buffer, 2, 1000)) != HAL_OK){
break;
}
uint16_t amount_of_data_to_receive = (slave_buffer[0] << 8) | slave_buffer[1];
// Receive the instruction and file name
if( (status_receive = HAL_SPI_Receive(&hspi1, slave_buffer, amount_of_data_to_receive, 1000)) != HAL_OK){
break;
}
// instruction is byte 0
char* extracted_string = extract_string_from_spi_data_at_index(slave_buffer, SLAVE_BUFFER_SIZE, 1);
volatile uint8_t result = sd_open_file(extracted_string, slave_buffer[0]);
HAL_SPI_Transmit(&hspi1, &result, 1, 100);
HAL_SPI_Transmit(&hspi1, slave_buffer, amount_of_data_to_receive, 100);
free(extracted_string);
I tried to look at the the SPI bus trough a logic analyzer. I can see that the master transmits everything correctly. The slave returns some bad data.

I tried to echo back the data that was sent to the slave. Found the separate issue with transmitting instead.

I tried to lower the frequency of the SPI bus. Did not do anything,
I tried changing the polarity and the phase on both the slave and the master. Did not do anything
Durring debugging of the slave I see that it is successfully reaching the end of the slave logic. In the debug data I can see that the slave_buffer successfully gets does the first read for the instruction. Messes up the next read by skipping past two bytes and reading what would be a byte of the third read.

Messes up the third read as the first byte is skipped, skips some more bytes and corrupts some data.

I tried to just use one big array to get all the data before acting on it, that did not work well. This is approach i am using now is the best working one so far.
I tried to also hand feed the slave function correct data, like the correct amount of data to receive and send out and it still failed. So the transmission is a completely separate issue that is not caused by the receiving issue.
I made some sanity check code to make sure the master slave communication is working with a led on both the master and the slave and it works perfectly. It sends one byte and receives one byte.
I looked at this posts on stackoverflow and it seems similar in that it is not receiving data correctly, but i am receiving some data, just messed up and i have a problem of sending out out again.
I expected the SPI on the slave to successfully receive data that is above 10 bytes long and transmit it back at least. Is my plan for doing this flawed? I thought about attaching the master to a flash chip and writing there instead, but I like the idea of having a chip that handles the SD card writing for me. Any help is appreciated.
EDIT:
On @wek's request, I added a gpio pin toggle to the sanity check code, to see how long it takes to process one byte. Bellow is the logic analyzer output of it:
