RPi pico machine.SPI periodic dropout.

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
JWF
Posts: 5
Joined: Sun Jun 06, 2021 5:39 pm

RPi pico machine.SPI periodic dropout.

Post by JWF » Sun Jun 06, 2021 7:05 pm

Hello MicroPython forum.

I recently picked up a pico development board and I am really enjoying the versatility of MicroPython. In my current project I am trying interface a RPi4 with a high performance ADC, in particular the ADS131M04. However, the non-maskable interrupts are reaking havoc with communication timings. I am experimenting with placing a microcontroller as a intermediate buffer, and as a Python developer by trait the pico with MicroPython seems as the obvious choice.

The ADC requires a 8.192 MHz clock which I generate using the PIO with the following code (working splendid).

Code: Select all

class ClockGenerator:
    def __init__(self, pin: int, frequency: float) -> None:
        self.clock_out_StateMachine = rp2.StateMachine(
            0,
            self.square,
            freq=int(frequency * 2),
            set_base=Pin(pin)
        )
    
    @staticmethod
    @asm_pio(set_init=PIO.OUT_LOW)
    def square() -> None:
        wrap_target()
        set(pins, 1)
        set(pins, 0)
        wrap()
        
    def start(self) -> None:
        """Enable clock output"""
        self.clock_out_StateMachine.active(1)
        
    def stop(self) -> None:
        """Disable clock output"""
        self.clock_out_StateMachine.active(0)
The ADC uses SPI (SPI mode 1) to communicate, and a seperate active low signal to indicate available measurement data. I am using the machine.Pin to run a interrupt routine on the ADC_READY falling edge and then machine.SPI to read 18 bytes off the ADC. By the below code.

Code: Select all

def READ_ADC(*_):
    cs.value(0)
    _ = ADC.read(18)
    cs.value(1)
    
sck = Pin(2, Pin.OUT)
mosi = Pin(3, Pin.OUT)
miso = Pin(4, Pin.IN)
cs = Pin(5, Pin.OUT, value=0)
ADC_READY = Pin(14, Pin.IN)
    
ADC = SPI(0, baudrate=int(12e6), sck=sck, mosi=mosi, miso=miso, polarity=0, phase=1)
    
ADC.write(bytes([0x00]*18))
ADC_READY.irq(trigger=Pin.IRQ_FALLING, handler=READ_ADC)
Now heres my issue!

The SPI communication seems to drop at periodic intervals. In the picture below the yellow signal is the ADC_READY signal, green SPI CS and blue SPI SCK. In the beginning it is observed that following each yellow falling edge the data is read with a burst of SPI clocks, why the ready signal returns high, untill next availabe data event. However, at periodic intervals the SPI seems to choke up. The ready signal (yellow) goes low indicating new available measurement data, the IRQ rutine is entered and the SPI CS (green) is held low, but no SPI clocks (blue).

Image

The communication dropout seems to be ongoing for approximately 7.4 ms, as seen in the picture below. By the end multiple SPI SCK bursts seems to be issued faster than normal in an attempt to "catch up", before resuming normal operation. This is of course futile as the ADC have a one-deep output buffer.

Image

This phenomenon seems to be periodic happening approximately every second.

Image

I have been trying to fiddle with this for a couple of days but I am at a loss.

Hoping anyone out there can help me figure this out.

Best regards
Jakob W. Funding

dk2jk
Posts: 2
Joined: Sun Jun 13, 2021 9:09 am
Location: JO41dl

Re: RPi pico machine.SPI periodic dropout.

Post by dk2jk » Sun Jun 13, 2021 10:19 am

Hello, I have a similar dropout effect with PWM generation.
Board: Raspberry Pico
Task: A sinusoidal signal is to be generated.
Output takes place via a PWM plus Low-pass RC. The pulse width (duty) is changed step-by-step from a sine table. There should be a continuous signal.
However, the output signal has a dropout for approx. 8 ms at irregular intervals.
What could trigger this dropout ? May be this a System-Timer ?.
This effect also occurs when the Pwm output (pwm.duty_u16) runs via a timer interrupt.

With regards
dk2jk

Code: Select all

N=20
# Sinustabelle ########
sintab =genSintab(n=N,ampl=0x8000,rand=0x4)
'''
sinustabelle
0x8000  0xa78c  0xcb3a  0xe78a  0xf9b8  0xfffc  0xf9b8  0xe78a  0xcb3a  0xa78c
0x7fff  0x5873  0x34c5  0x1875  0x0647  0x0004  0x0647  0x1875  0x34c5  0x5873 
'''

# DDS #################
class dds:
    en      = True
    i=0
def nextstep():     
    if  dds.en:
        dds.i= (dds.i+1) % N    # N is length of sin table   N=20
        pwmSet(sintab[dds.i])   # pwmSet = pwm.duty_u16
    else:
        dds.i=0
        pwmSet(sintab[0])
    pass
   
# Timer #####################
if __name__ =='__main__': 
    while True:
        nextstep()              # step throu sin table
        p17.value(dds.i > N/2)  # square wave output
Image

fdufnews
Posts: 70
Joined: Mon Jul 25, 2016 11:31 am

Re: RPi pico machine.SPI periodic dropout.

Post by fdufnews » Mon Jun 14, 2021 6:20 am

Garbage collection perhaps.

User avatar
pythoncoder
Posts: 5373
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: RPi pico machine.SPI periodic dropout.

Post by pythoncoder » Mon Jun 14, 2021 9:18 am

Very possible, but I think that if Pyboards had this problem it would have been spotted by now.

A minimal test case might be to run PWM at a fixed frequency with a 50% duty ratio, put the result through an RC filter, and look for glitches with a scope.
Peter Hinch

User avatar
pythoncoder
Posts: 5373
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: RPi pico machine.SPI periodic dropout.

Post by pythoncoder » Mon Jun 14, 2021 1:14 pm

I tried this and failed to replicate the fault. To provoke occasional GC I first ran some floating point maths. I then ran a large application which performs periodic GC. In each case the output of the filter was stable.

Assuming you guys are running recent firmware I can only conclude that this fault depends on the details code which is running concurrently with the PWM or SPI. If either of you can produce a minimal test case, I suggest raising an issue on GitHub.
Peter Hinch

scruss
Posts: 106
Joined: Sat Aug 12, 2017 2:27 pm

Re: RPi pico machine.SPI periodic dropout.

Post by scruss » Mon Jun 14, 2021 8:24 pm

It might also be worth dropping something on the MicroPython section of the Raspberry Pi Forums, too. Some of the RP2040 hardware engineers hang out there.

User avatar
pythoncoder
Posts: 5373
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: RPi pico machine.SPI periodic dropout.

Post by pythoncoder » Tue Jun 15, 2021 10:49 am

Yes. This is definitely worth pursuing. It seems very telling that two different candidates are producing such a similar outcome.
Peter Hinch

hippy
Posts: 70
Joined: Sat Feb 20, 2021 2:46 pm
Location: UK

Re: RPi pico machine.SPI periodic dropout.

Post by hippy » Tue Jun 15, 2021 12:34 pm

fdufnews wrote:
Mon Jun 14, 2021 6:20 am
Garbage collection perhaps.
Seems unlikely to me. PIO and PWM are separate hardware entities so should continue running even if MicroPython had frozen solid.

In the PWM case the trace appears to show the RC output voltage rising to 3V3 which could only happen with the PWM output frozen high or with a higher duty than in the lookup table.

The only thing PIO and PWM have in common, as far as I can see, is they are both clocked; take the clock away and they will both stop.

I don't know how that could arise but that's my gut feeling.

I would add another free-running PIO square wave generator or preset PWM, see how those behave when things turn south, see if any correlations can be determined.

JWF
Posts: 5
Joined: Sun Jun 06, 2021 5:39 pm

Re: RPi pico machine.SPI periodic dropout.

Post by JWF » Tue Jun 15, 2021 7:29 pm

Hello all, thanks for your interest!

Sorry for the late reply, I have been tied op lately.

Today I have tried to use another pico board with MicroPython v.1.15 (2021-04-18) installed through Thonny, sadly with identical results. However neither of my boards seems to have a problem with PWM generation, either with the PIO squarewave generator running simultaneously or not.

I have tried to check the PIO squarewave generator output when the SPI dropout occurs, and it seems to continue steadily as seen in below scope picture. Here signals are as follows: ADC_READY (yellow), PIO clockgen (purple) and SPI SCK (blue).
Image

Additionally I have tried to create a minimal (and easy replicatable) test case. Here a 50% dutycycle PWM signal is used on pin 16 to create an artificial ADC_READY signal for the pico to run interrupt routine on pin 14. All external hardware is disconnected besides a wire shorting pin 16 to pin 14. Again in the interrupt routine CS is held LOW momentarily while 18 bytes are clocked out on the SPI bus.

This code in its entirety is found below.

Code: Select all

from machine import Pin, SPI, PWM
        
def READ_ADC(*_):
    cs.value(0)
    ADC.read(18)
    cs.value(1)
    
if __name__ == "__main__":
    pin = Pin(16, Pin.OUT)
    pwm = PWM(pin)
    pwm.freq(4000)
    pwm.duty_u16(32512)

    sck = Pin(10, Pin.OUT)
    mosi = Pin(11, Pin.OUT)
    miso = Pin(12, Pin.IN)
    cs = Pin(13, Pin.OUT, value=1)
    ADC_READY = Pin(14, Pin.IN)
    
    ADC = SPI(1, baudrate=int(12e6), sck=sck, mosi=mosi, miso=miso, polarity=0, phase=1)
    ADC_READY.irq(trigger=Pin.IRQ_FALLING, handler=READ_ADC)
 
Sadly the issue consists. PWM pin 14 (yellow) and SPI SCK pin 10 (purple).

Image

As a thought I tried to lower the number of SPI read bytes from 18 to 1 with no behavioural change.

User avatar
pythoncoder
Posts: 5373
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Is the ISR actually running?

Post by pythoncoder » Wed Jun 16, 2021 8:48 am

OK, this is clearly a different problem from that reported by @dk2jk. You have an easily reproduced test case where the Pico appears not to be responding to an IRQ. There is a doubt in my mind as to whether the ISR is not being called, or if it is being called but the SPI is not responding.

To resolve this, in the ISR set a pin high, then low and put the scope on that pin.

If the ISR is not being called you might discard all the SPI code and check if the ISR is still not being called. In this instance you would have an extremely simple test case.
Peter Hinch

Post Reply