So I was dealing with a troublesome connection where my uart was actually fluctuating serial baud rate as boot was happening on this chip and the old buspirate - i used the (4) option to auto calc…is 5 missing this option perhaps I am just not a cool bus pirat(sp) user.
Good question. The PIC in Bus Pirate v3.x had autobaud detect hardware. The RP2040 in 5+ do not. There is some mention of autobaud via the PIO online, but I have never been able to find the actual code used.
Another option is to use the Bus Pirate as a logic analyzer with pulseview, I believe the decoder will detect the baud rate.
Interesting question. I saw Adafruit did something here a few years back, but the code doesn’t seem to have been released. So I searched how this would be done…
- Sample the shortest spike in the communication line (typically when a
010
bit pattern is sent).- This will detect ANY baud rate, not just the standard ones.
- Viewed another way, it works even with broken clocks.
- If periodically feeding the result to another program, could automatically adjust even if the other side changes baud rate.
- Both
CR
andLF
have a010
and/or101
bit pattern, so typical ASCII output will find the shortest pulse rapidly. - For binary data, initial results may be an integer multiple of the baud rate (e.g.,
001100
for 2x,000111000
for 3x, …) … so don’t just accept the first result! - May also want to filter spikes that are outside “reasonable” ranges, to filter noise.
- Now that the shortest pulse is found, get a bitstring interpretation of the data using that presumed baud rate.
- Interpret that bitstring to discover the actual combination used:
- Data Bits: 7 or 8
- Parity Bits: 0 or 1
- Stop Bits: 1 or 2
- Total configurations to test: Eight
- As a heuristic (option when appropriate), check if the data is primarily ASCII.
Table of Time to Baud Rate
Time | Baud Rate |
---|---|
3333µs (3.3ms) | 300 |
833µs | 1200 |
416µs | 2400 |
208µs | 4800 |
104µs | 9600 |
69µs | 14400 |
52µs | 19200 |
34µs | 28800 |
26µs | 38400 |
17.3µs | 57600 |
8µs | 115200 |
What is the maximum baud rate detectable using a RP2040 @ 125MHz clock (e.g., without overclocking)?
detecting shortest `101` bit pattern
Note: this is written without any testing, so consider it pseudo-code…
EntryPoint:
; Must start with pin high
JMP PIN WaitForPinToGoLow
JMP EntryPoint
LowLength_Found:
IN X ; push the count into the output buffer, autopush enabled
WaitForPinToGoLow:
JMP PIN WaitForPinToGoLow; loop while pin high
; Pin transitioned from high -> low
; Reset count to zero (or any other value)
SET X = 0x00000000
.wrap_target ; Reduces need for last instruction to jump here
LowLength_Loop:
JMP PIN LowLength_Found ; branch taken when input is high
; Next two lines: unconditional decrement of register X
; See https://github.com/raspberrypi/pico-sdk/issues/1042
JMP X-- LowLength_DecHack
LowLength_DecHack:
; loop back to check the pin state again
; Uncomment next instruction if not using .wrap_target
; JMP LowLength_Loop
From transition high → low:
Cycle | Instruction |
---|---|
0 | JMP in WaitForPinToGoLow fails |
1 | SET X = 0 |
2 | First JMP to detect pin going high (fails) |
3 | DEC X pseudo-instruction |
2*N | Next JMP to detect pin going high (success) |
2*N + 1 | IN X puts counter into ISR |
2*N + 2 | … back to cycle 0 |
This just constantly detects the length. Something else must read from the ISR FIFO, throwing away the first (ISR queue depth) samples, and then reading some number of ISR entries (discarding if really large negative values), and taking the smallest reasonable result. Or maybe average the values close to the smallest reasonable result? If the smallest sampled value is close to a standard baud rate, time to try it out!
The above shows how to detect the length of low signals. However, decoding serial requires both high and low. Thus, adjust the above PIO program to outputs the length of BOTH the high and low signals.
Essentially, could be identical to prior program, but duplicated for high and low length detections. Use distinct start values for high and low (e.g., 0xFFFFFFFF
and 0x7FFFFFFFF
)? Positive values would reflect how long the signal was high, while negative values would reflect how long the signal was low (or vice-versa … one of those is better for idle time detection). Change the pseudo-DEC to not be unconditional (to detect idle time) … thus pushing zero into the OSR implying idle time? Maybe use register Y to store X & 0x7FFFFFFF
, and use that for detecting idle?
Thank goodness for the DEC X
pseudo-instruction. Else, there would be no way to count time passing. With it, PIO becomes much more useful.
Given a stream of high/low timings being pushed to the ISR, a program could read them (discarding idle time) and then decode the data after N values received, using the shortest time, thus supporting arbitrary baud rates? If it detects the baud changed, it could also re-process historic data…
Not perfect, but likely a “good enough” heuristic for automagic baud detection and sync?