Description
On the RP2040, several sets of pins can be selected for each of the two SPI modules. Sometimes we need to disable the SPI function of a pin, while leaving it in the state it was in. For example the following code should leave pin 14 (SCK) low between write()
and sck(1)
:
from machine import SPI, Pin
sck = Pin(14)
mosi = Pin(15)
spi = SPI(id=1, baudrate=100000, polarity=0, phase=0, sck=sck, mosi=mosi)
spi.write(bytearray([0xAA]))
sck.init(mode=Pin.OUT, value=0)
sck(1)
However, the first time it runs after reset, there's a ~1 microsecond glitch during which pin 14 floats upward. The glitch causes unreliable behavior with SPI devices if you don't take measures to avoid it (the workaround is to run sck.init(mode=Pin.OUT, value=0)
at least once before using SPI.)
I tested this on the latest master branch, MicroPython v1.19.1-716-g227ea47f4, with a Raspberry Pi Pico having a 1k pull-up on pin 14. Here is a trace of the output:
I believe the source of the problem is here:
https://github.com/micropython/micropython/blob/master/ports/rp2/mphalport.h#L99-L103
static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) {
gpio_set_function(pin, GPIO_FUNC_SIO);
gpio_set_dir(pin, GPIO_OUT);
machine_pin_open_drain_mask &= ~(1 << pin);
}
The SPI alternate function is disabled before the pin is set to an output.
I don't quite understand what's going on here, but I believe that switching the order of these operations would let it work as intended. Is there a reason to do them in this order? Or is there some other problem?