SPI: deinit changing pin function?

I was having some trouble with using the camera as an SPI peripheral (slave), specifically with the rpc library, but I think the issue is more with the SPI bus, in general. The problem manifested in odd behaviour with the SS pin (P3): after the first time it went LOW, the pin would no longer have any effect on the SPI transactions. For example, after the first transaction, I could connect the SS pin to 3V3 and SPI would more or less work(!) (but I suspect the ‘less’ part is due to the SS pin not working right, which leads to frame errors).

I traced the issue to SPI.deinit(). When that function is called, the pin mode for P3 is changed to an alternate function and it always reads LOW – even if connected to 3V3. So when testing the SS pin for the start of a transaction, it always returns LOW, so framing errors can occur.

I ran a short code to demonstrate:

import pyb

pin = pyb.Pin("P3", mode = pyb.Pin.IN, pull = pyb.Pin.PULL_UP)
spi = pyb.SPI(2)

print(pin.mode())
print(pin.af())
print(pin.af_list())
print(pin.value())

spi.init(pyb.SPI.SLAVE, polarity=0, phase=0)
print('init')

print(pin.mode())
print(pin.af())
print(pin.af_list())
print(pin.value())

spi.deinit()
print('deinit')

print(pin.mode())
print(pin.af())
print(pin.af_list())
print(pin.value())

When you run this code, the pin mode changes to 3 after deinit() is called, which corresponds to an alternate function, in this case AF = 0 --> Pin.AF1_TIM1.

I get a lost in the library files, and I’m struggling to figure out where exactly deinit() lives – I’d be curious to see what that function does and try to fix it.

The full output of the above code is:

0
0
[Pin.AF1_TIM1, Pin.AF5_SPI2, Pin.AF7_USART3, Pin.AF9_CAN2]
1
init
1
0
[Pin.AF1_TIM1, Pin.AF5_SPI2, Pin.AF7_USART3, Pin.AF9_CAN2]
1
deinit
3     ##  <------ pin mode has changed!
0
[Pin.AF1_TIM1, Pin.AF5_SPI2, Pin.AF7_USART3, Pin.AF9_CAN2]
0     ## <------ always reads LOW!

Will look into this. This could be the reason for the SPI mode in the RPC library not working. We re-factored SPI code recently.

I can’t test what’s going on until the week of December 6th.

Right now we kinda unconditionallity deinit the pin on the spi bus deinit: https://github.com/openmv/openmv/blob/master/src/omv/ports/stm32/stm32fxxx_hal_msp.c#L523C8-L523C8

This is probably not playing well with the pyb module API.

Try reiniting the pin afterwards. This should fix the issue.

As for fixing this… not sure if our code is broken. Deiniting the pin is the behavior we wanted. It might make sense to always re-init the pin after deiniting the SPI bus.

Have to think about that… I suppose we could just switch the pin to a gpio output on deinit versus AF if it was in that mode. Not sure what to do here.