Author Topic: STM32 - SPI Slave - Using Hal Drivers - Unreliable TXRX and Slow Initialization  (Read 6611 times)

0 Members and 1 Guest are viewing this topic.

Offline MahonroyTopic starter

  • Newbie
  • Posts: 2
Hello, I will first describe what I am trying to accomplish, what I have tried, and how it is not working; any help/advice is greatly appreciated.

I have an external MCU (Particle Photon) acting as the SPI Master. Approximately every half second it needs to send 64 bytes to the STM32F103. It can also be multiples of 64 bytes (e.g. 50x 64 byte chunks equaling 3,200 bytes in this example... maximum of 200x chunks). The STM32 also has its own data that needs to be sent back to the master MCU, same format.

I have stripped a lot of this down, and am just trying to get a single 64 byte exchange to happen reliably, and I am failing at that.

I used STM32CubeMX to generate the source code and configurations. Here are the functions I am using:

SPI Buffers & Init Flag:
Code: [Select]
uint8_t txData[64]; //uint8_t txData[MAX_DEVICES_TRACKED * 64];
uint8_t rxData[64]; //uint8_t rxData[MAX_DEVICES_TRACKED * 64];
bool spiReady = true;

Main Loop:
Code: [Select]
while(true)
{
if(spiReady)
{
spiReady = false;
InitSPISlave(&hspi1);
}
}

Init SPI:
Code: [Select]
void InitSPISlave( SPI_HandleTypeDef *spiHandler )
{
memset(rxData, 0, sizeof(rxData));
HAL_SPI_TransmitReceive_IT(spiHandler, txData, rxData, sizeof(txData));
}

Callbacks That Occur After SPI TXRX Complete, And Error Callback:
Code: [Select]
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
printf("SP1 Data Received: ");

for(int i = 0; i < 64; i++)
{
printf("%lx ", (long)rxData[i]);
}
printf("\n");

memset(txData, 0, sizeof(txData)); //If I don't clear the data, it comes across ok

spiReady = true;
}

void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
printf("SPI1 ERROR: %d \n", hspi->ErrorCode);
spiReady = true;
}

For testing purposes I have a timer that periodically populates the txData buffer. As soon as the transaction is complete, and the master MCU has the data, I want to clear out the txData buffer.... when more data becomes available it will then go into the txData, which is what the timer is simulating.


I am experiencing 2 problems:
  • If I comment out "memset(txData, 0, sizeof(txData));" the data goes to the master ok. If I leave it as is and clear it after every transaction, the master receives the data but either the first byte is zero, or the entire buffer is shifted over by a byte. This seems somewhat random. I also get SPI errors in the error callback, periodically get OVR error "HAL_SPI_ERROR_OVR", and then eventually I get "HAL_SPI_ERROR_FLAG" errors, at which point it stops working completely. It almost seems like something is going on with the STM32 SPI register TX buffer? But I don't fully understand this, or how I should fix it. It could be something else but I am not sure.
  • When I call "HAL_SPI_TransmitReceive_IT(spiHandler, txData, rxData, sizeof(txData));" it is really slow to initialize and get up and running. I decided to time this by started a timer when calling that function, and when the callback gets executed, and it takes approximately 300 ms. If I increase the size of the buffers to 640 bytes, it takes several seconds to initialize and start the SPI transfer. I am wanting to do a max of 12,800 bytes, so something is seriously wrong here, there is no reason why it should be taking that long to set up a single SPI transfer. I am not sure what is going on or how to fix this either. I have to call this function again after each SPI transfer, so the MCU is basically always stuck in a state of initializing for several seconds to receive a single transfer.

I tried switching over to DMA SPI, e.g. "HAL_SPI_TransmitReceive_DMA(spiHandler, txData, rxData, sizeof(txData));", and while it is slightly quicker to initialize-still way too slow, I experience the same problems.

I have been scouring the internet trying to read up on this, and most people say the HAL drivers are junk and don't work right, and to work directly with the registers yourself. If this is the case, I don't know where to start in accomplishing that... or if maybe there is a fix I can do to get this up and running?

Any help on working through this is greatly appreciated, thanks!
 

Offline mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13765
  • Country: gb
    • Mike's Electric Stuff
It rarely makes sense to use manufacturers' libraries for something as simple as SPI. You can usually write your own quicker than understanding and debugging manufacturer's general-purpose and usually bloated code.
Just read the SPI section in the manual and write your own code to do exactly what you need.
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4228
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
I have been scouring the internet trying to read up on this, and most people say the HAL drivers are junk and don't work right, and to work directly with the registers yourself

I'd be one of those people!

I'd advise you to start by having a read through the SPI section in the Reference Manual for the particular STM32 device you're using. If you're familiar with the HAL driver already, you'll find the description of the register interface for the SPI hardware familiar too.

This is why I see so little value in the HAL. You basically have to tell it, in a roundabout way, what to write into all the registers in the device. It doesn't really abstract the hardware, so much as obfuscate it.

In a way, that's a good thing. It means you've already learned how the underlying hardware works without realising it!

The headers which come as part of the HAL include register definitions, which you can use directly. For example, to enable DMA on SPI1, you might use:

Code: [Select]
__SPI1_CLK_ENABLE(); // remember to do this before using any peripheral

SPI1->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;

Use your IDE to find the definitions of the register bits; there's loads of them but they're named in a consistent way, so you can usually make a good, educated guess at what each one will be called.

Offline Brutte

  • Frequent Contributor
  • **
  • Posts: 614
It is really annoying when I read same question on different forums without giving cross-reference in both. The answers have already been given there and now these answers are repeated again here by our members.

Bots are wasting our time and also time of people from other forums.

:--

@EEVBlog - Could you please mark cross-posters?
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf