Don't blame HAL here, most of the code is badly implemented.
You might need to add some check or wait for the SS pin to go high after the transmission.
If the Rpi doesn't set SS pin high fast enough, the function might loop and stall waiting for clocks that will never come.
Anyways, this seems wrong, the ";" will make the while to loop over itself, instead doing the following code loop.
SS is active low, right? And you want to receive data. But this will do absolutely nothing while SS pin is low!
while(HAL_GPIO_ReadPin(SPI_SS_GPIO_Port, SPI_SS_Pin) == GPIO_PIN_RESET); // Do nothing while SS=0. Remove ";" !
{
The rest of the code will will mainly fail because of this:
HAL_SPI_Transmit_IT(&hspi1, (uint8_t *)batteryVoltage, 6); // IT Transmission starts. This is a NON BLOCKING function!
HAL_SPI_Transmit(&hspi1, (uint8_t *)"v", 1, 100); // But you inmediately start another transmission, without checking if the previous one was finished, this will likely fail and you're not checking the result
HAL_GPIO_WritePin(GPIOA, Voltage_Ready_Pin, GPIO_PIN_RESET); // And now you're resetting the pin, which will break the ongoing communication with the Rpi
Interrupts are ok for slow transmissions like serial and such, or transferring blocks using dma, but for single bytes in a fast spi, it can actually perform slower, as in will add the interrupt overhead for every byte.
SPI is fast enough to do it without interrupts, and DMA is not needed for this, but you must add a small delay in the Rpi after setting low SS pin (100us should be more than enough, but you must test that), to let the stm32 notice and start the SPI receive.
Also add that delay after detecting "Voltage_Ready_Pin", before sending the clocks to receive the data from the stm32.
Ensure the spi clock isn't running crazy fast, like 50MHz. Try first with something lower, ex. 1MHz.
I see you only check the first received byte to detect the answer type.
Unless you're sending exactly 10 bytes from the Rpi, you'll be always losing 100ms here:
HAL_SPI_Receive(&hspi1, (uint8_t *)spi_buf, 10, 100); // Adjust the SPI receiving size to the real expected size, or it will always wait the whole timeout.
Don't waste time clearing the buffer before sending data. Do it after that, when you're free!
memset(spi_buf,'*',10);
You could also clear only the first byte to make it faster:
spi_buf[0]=0;
Also, build a single packet, don't break it in 2 separate transmissions, you will lose spi clocks between! Append 'V' in BatteryVoltage();
HAL_SPI_Transmit_IT(&hspi1, (uint8_t *)batteryVoltage, 6); // Sending voltage (e.g., 13.54)
HAL_SPI_Transmit(&hspi1, (uint8_t *)"v", 1, 100); // Sending the last character 'v' to finish transmission
Simplify the code and check the spi transfer result so you can debug it:
void SPI_Receive_Commands(void)
{
if(HAL_GPIO_ReadPin(SPI_SS_GPIO_Port, SPI_SS_Pin) == GPIO_PIN_RESET) // Check if SS is low (Transmission begins from Rpi)
{
HAL_SPI_Receive(&hspi1, (uint8_t *)spi_buf, 10, 100);
if(spi_buf[0] == 'v') // Battery voltage function
{
Battery_Voltage(); // Generate voltage string, appending 'V' and string null termination, ex. "13.54V\0"
HAL_GPIO_WritePin(GPIOA, Voltage_Ready_Pin, GPIO_PIN_SET); // Indicating Raspberry pi that the transmission is starting
uint8_t res = HAL_SPI_Transmit(&hspi1, (uint8_t *)batteryVoltage, 7, 100); // Send data, 100ms timeout, save result
switch (res) // Check result
{
case HAL_OK:
// Everything OK
break;
case HAL_ERROR:
// Interface error
break;
case HAL_BUSY:
// Interface busy
break;
case HAL_TIMEOUT:
// Interface timeout
break;
}
HAL_GPIO_WritePin(GPIOA, Voltage_Ready_Pin, GPIO_PIN_RESET); // Indicating Raspberry pi that the transmission has finished
printmsg("Sending battery voltage\r\n"); // This can be slow if sending over serial in blocking mode!
memset(spi_buf,'*',10);
while(HAL_GPIO_ReadPin(SPI_SS_GPIO_Port, SPI_SS_Pin) == GPIO_PIN_RESET); // Wait for SS pin to go high, so we don't re-enter within the same transmission
}
}
}