2023-08-16 01:28 PM
Hello,
I am considering using 2 STM32F373 in my project. One uC will be for a control panel, and the second uC will accept commands to produce DAC and PWM output. What is the best way to have them exchange data? Should I use SPI? I see i2c is not as fast as SPI.
Thanks!
2023-08-16 02:21 PM
Use whichever you’re comfortable with.
If you use SPI, one device will be in charge of the communications. If the other has something it wants to report (e.g. over-current on an output), it is unable to do so until the master asks it.
If that’s OK then SPI is fine. (Or you could add an extra “service-request” signal)
I2C can be multi-master but it’s difficult.
Much easier for two-way communication is to have a UART at each end.
2023-08-16 02:50 PM
I can get away with the master always initiating the requests.
Does the slave uC have the RX interrupt enabled for each byte so that it can detect the sync byte, and the 'packet size' byte? Or, should the master always set the same sized packet each time so the slave knows how many bytes to read into DMA? Or do I have the slave interrupt on each byte rx'd for the first 2 bytes, ( sync and packet size ) and the set the rx size for DMA to the size of the packet expected?
Lastly, is there a well know method to handle timeouts and retries? I'm planning on using a CRC and maybe having the slave 'reset' it's rx after a few ms of not receiving data in case it gets out of sync with the master. I know there are all kinds of 'gotchas' with timeout/retries and packet protocols:)
2023-08-17 02:28 AM
I think the answer depends what protocol (SPI, I2C, UART) you're using.
UART will always give a string of bytes. It's up to you to know where one command ends and the next starts. Timeouts may be helpful here.
I2C has a start-sequence then the peripheral address as well as whether it is reading or writing. You could choose to require that the first byte(s) written after the address is the command, and the remainder (if any) are data.
SPI has Slave-select. You can have the first byte(s) after slave-select being the command. Just release (raise) SSEL to finish one command ready to start the next.
The HAL DMA libraries are restrictive in that you need to specify the length of the message. If you have variable-length messages interrupts are much easier to code. The overhead of an interrupt per byte only matters if you're sending a lot of data or you have very strict timing requirements.
2023-08-17 02:51 AM
Very important information are missing in your question:
What amount of data: packet size
What packet frequency
What timing: What amount of jitter in the packet transmission.
Not all interfaces are equals regarding these requirements.
For very precise timing and high speed SPI+DMA is easy (eg the slave can abort the DMA at the end of CS using EXTI, so the slave only need to know the max packet size). When the slave need to sent something to the master it can do a request using another GPIO, connected to a master GPIO with EXTI.
With low timing requirement UART+ interrupt is easy. And you get a full duplex channel.
On STM32 I2C is very complicated,
2023-08-17 09:56 AM
I'll implement SPI with the SS pin, since it allows the slave to easily know how many bytes to read ( variable length packets ) I like how a EXTI can be used on the master if I ever need the slave to initiate a request. I can enable both MOSI and MISO if I ever need data back from the slave. Thanks!
2023-08-17 04:01 PM
Beware: use the SS as GPIO (software), not in hardware mode. The SS managed in hardware mode is useless.
2023-08-17 10:59 PM
You didn't specify data rates, so I'll assume you're looking for fast exchange since you mentioned SPI. My own approach would be to model this as process control, using CAN and a CANopen stack, but that can be complicated if CAN is unfamiliar..
What's the distance between the boards, and noise environment? If it's in multiple meters, I'd consider using RS-485, with the control panel as bus master and UART interface at each end. It's simple and quasi bidirectional if you go with two-wire bus. Some protocol like MODBUS would fit a process control model, implementing the output board as a set of registers driven by the control panel bus master. RS-485 has excellent noise tolerance due to twisted pair differential.
The real plus is the simplicity of a UART interface. All that's needed is line turnaround for half duplex, which is straightforward. Using a standard protocol like MODBUS gives you a positive ACK on transactions. Adding a heartbeat transaction gives you comm failure detection if a safe halt is required in fault conditions. And the error detection in an async UART receive works to ensure a clean exchange, or a retry if it fails.
Jack Peacock
2023-08-19 11:57 AM
Thanks for the info. The control panel is a PCB board connected direction to the second board, so there is no wire. I'm sending data from a UI to the board so do not need super high rates. I am currently implementing an SPI DMA based solution with a SS pin. I will also implement UART as well, but I don't need slave to master communication and I wanted to have SPI with SS in case I add a third uC in the future.
The only part I"m missing is timeout/noise/retry error detection with my SPI. I've posted another question asking for the best way to handle error detection/retries with SPI.