After validating my STM32F407 SPI driver with a logic analyzer, the next step was connecting the STM32 to another device. I chose an Arduino as the SPI slave. What looked like a straightforward integration quickly became a hardware debugging exercise when signals that were clearly leaving the STM32 were no longer reaching the Arduino.
Eventually I want to add a camera to my quadcopter and I will likely need another microcontroller to process the video. So I need to figure out master and slave communication.
This ended up being one of the more useful tests in the project so far. The problem was not simply solved by changing code. I had to follow the signals physically through the circuit and determine exactly where they disappeared.
The Goal
My previous SPI test transmitted "Hello World" from SPI2 on the STM32F407 and verified the output with a logic analyzer.
That proved that the STM32 could generate the expected SPI clock and data. Now I wanted to move from observing the bus to communicating with an actual slave device.
The STM32 would operate as the SPI master and the Arduino as the slave.
Connecting the Two Boards
SPI requires several signals to be shared between the master and slave. For this test I needed the clock, master output, slave output and slave select signals along with a common ground reference.
STM32 SCLK → Arduino SCK
STM32 MOSI → Arduino MOSI
STM32 MISO ← Arduino MISO
STM32 NSS → Arduino SS
STM32 GND ↔ Arduino GND
I initially routed the signals through the breadboard and the interface hardware between the two boards. With everything connected, I programmed both devices and started checking the bus with the logic analyzer.
First Question: Is the STM32 Actually Transmitting?
When communication between two devices fails, there are immediately several possible causes. The master may not be transmitting. The slave may be configured incorrectly. The SPI modes may not match. Slave select may not be asserted correctly. There may also simply be a wiring problem.
Instead of changing several things at once, I started with the side of the system I had already tested: the STM32.
This was an important result because it reduced the search space. I already knew from the previous "Hello World" test that my SPI driver could generate valid signals. Seeing those signals again told me that the STM32 peripheral was still operating.
Verify what is known to work before changing it. If the expected signal exists at the source, start following that signal toward the destination.
Following the Signal
This is where the logic analyzer became particularly useful.
Instead of only connecting the analyzer at one location, I moved the probes along the physical signal path. Close to the STM32, I could measure the expected SPI activity. I then moved the probes to the other side of the circuit closer to the wires leading to the Arduino.
The result changed.
This was the critical observation.
The firmware had not changed. The SPI configuration had not changed. The STM32 was still generating the signals. The only thing that changed was where I measured them.
That meant I was no longer primarily debugging the SPI peripheral. I was debugging the physical path between the two boards.
The Signal Exists Here, But Not There
At this point the circuit effectively gave me two observations:
The same signal that was measurable before passing through the interface was missing afterward.
The breadboard connections, jumper wires and level shifting interface therefore became much more interesting than the SPI code.
Isolating the Interface
The two boards operate with different logic voltage conventions, so I had originally included level shifting hardware between them. That also introduced another component into every signal path.
At this point I needed to determine whether that interface was actually helping the communication or preventing it.
Since the analyzer showed valid signals before the interface and missing signals after it, I tested the connection without that part of the signal path.
Simplifying the Circuit
Bypassing the problematic portion of the interface restored communication.
That result confirmed what the earlier measurements had suggested: the SPI peripheral itself was not the source of the failure. The problem was in the physical signal path between the STM32 and Arduino.
What Actually Solved the Problem
The useful part of this test was not any single code change. It was the process of progressively reducing the number of possible causes.
First, I verified that the STM32 was still producing the expected SPI signals. Then I measured the same signals at another point in the circuit. When the behavior changed depending on the measurement location I could stop treating the firmware as the most likely problem.
From there, simplifying the physical connection allowed me to isolate the component that was interfering with the signal path.
The Bigger Lesson
Embedded debugging crosses the boundary between software and hardware.
When the Arduino was not receiving the expected SPI communication it would have been easy to keep changing register settings or rewriting the transmit code. But software changes would not fix a signal that was being lost after it left the microcontroller.
Being able to probe the bus at multiple physical points turned an ambiguous communication failure into a much more specific question:
Once I could answer that question the problem became considerably easier to isolate.
That is a debugging technique I expect to use repeatedly as the quadcopter becomes more complex. Verify each layer independently and follow failures across the boundary between software and hardware rather than assuming which side is responsible.
Building Toward the Flight Controller
The Arduino is serving as a useful development target while I build and test the STM32 communication stack. The larger objective is still the quadcopter flight controller.
Developing a repeatable debugging process now is just as important as developing the drivers themselves.
At this stage, another piece of the system has moved from "the code should work" to something much more useful: behavior I have actually observed and validated on the hardware.