I2C uses an ever so slightly modified version of the PICO SDK I2C PIO program. I’ve been reworking it a bit because it’s kind of obnoxious to deal with.
;do_nack:
; jmp y-- entry_point ; Continue if NAK was expected
; irq wait 0 rel ; Otherwise stop, ask for help
do_byte:
set x, 8 ; Loop 9 times
bitloop:
out pins, 1 [7] ; Serialise write data (all-ones if reading)
nop side 0b1 [2] ; SCL rising edge
wait 1 pin, 1 [4] ; Allow clock to be stretched, in pins: 0=sda, 1=scl
in pins, 1 [7] ; Sample read data in middle of SCL pulse
jmp x-- bitloop side 0b0 [7] ; SCL falling edge
; Handle ACK pulse
;out pins, 1 [7] ; On reads, we provide the ACK.
;nop side 0b1 [7] ; SCL rising edge
;wait 1 pin, 1 [7] ; Allow clock to be stretched, in pins: 0=sda, 1=scl
;jmp pin do_nack side 0b0 [1] ; Test SDA for ACK=0/NAK=1, fall through if ACK, 1 jump pin defined in init
mov isr, null ; Reset the input bit counter
This is the business end. At Handle ACK pulse the program tries to test for the expected ACK/NACK of a write operation, and fails with an interrupt.
This is great if you want to queue up a bunch of data to send and then just forget about it. For us though, it makes things overly complicated.
I’ve commented out the Handle ACK pulse chunk, as well as do_nack. I increased the bitloop to 9 cycles. Now it brute forces through the ACK/NACK and we’ll handle the error checking in code.
wait 1 pin, 1 [4] ; Allow clock to be stretched, in pins: 0=sda, 1=scl
Clock stretching is enabled in this PIO program. This is another source of confusion I’ve seen a few times. This will be split into two programs with and without clock stretching, to be selected from the configuration menu.
Previously, the I2C mode would halt execution and display an error after the write address (0b10) was not ACKed. Now it will power through and just acknowledge the NACK.
This is more consistent with BPv3.x UX, but it depends on the user understanding that NACK means nobody answered. I feel this is more robust and more in line with how I expect the interface to work.
We now have a program for clock stretching and a program without. Selection is though the mode config menu, default is off/disabled.
Next, the I2C low level “drivers” need to be completely reworked. They are a bit of a mess from dealing with error detection in the PIO, so a good clean is in order. This will continue tomorrow.
Easier than I thought. The program was initialized before it was loaded. This fixes everything.
Clock stretching works to the extent that it doesn’t error out. However, I’m going to have to find a device that supports clock stretching and see how it works.
I will do a bit more testing, especially of the various demos, and then push.
This might be confusing for a beginner. Does it make sense to indicate in a subtle way that there was a implied NACK response, i.e. a change in color/dimmed or lower case letters, etc? Or better documentation?