Non-blocking ADC read?

The official pyboard running MicroPython.
This is the reference design and main target board for MicroPython.
You can buy one at the store.
Target audience: Users with a pyboard.
Post Reply
abraaoguia
Posts: 4
Joined: Fri Feb 05, 2021 9:07 pm

Non-blocking ADC read?

Post by abraaoguia » Tue Apr 12, 2022 6:35 pm

Hi community,

I'm developing a critical code for a high frequency inverter using Pyboard v1.1.
I would like it to run in 50us.

An issue that I'm facing is that I need to read 3 ADCs in high frequency, and I would like it to occur without blocking the main processor and the code execution. I've tried simply using adc.read() and also adc.read_timed_multi(), both without success. In fact "timed multi" version has a worse performance...

Is there a way to do this in the Pyboard?

Some data that I've measured:
Execution time without ADCs: 8us
Execution time with ADCs read: 158us
Execution time with ADCs read + scale and shift ADCs: 205us
Execution time with ADCs read_timed_multi buffer size 1 + scale and shift ADCs: 81us (code) + 283us (MCU blocked by ADC)

Thanks! A section of the code follows:

Vd_ref_buf = array.array('H', (0 for i in range(1)))#bytearray(1)
Vq_ref_buf = array.array('H', (0 for i in range(1)))#bytearray(1)
theta_buf = array.array('H', (0 for i in range(1)))#bytearray(1)

while True:
pyb.ADC.read_timed_multi((p_Vd_ref, p_Vq_ref, p_theta), (Vd_ref_buf, Vq_ref_buf, theta_buf), tim4)

if flag_current_control == True:
p_code_duration.high()

# ADCs:
Vd_ref = Vd_ref_buf[0]
Vq_ref = Vq_ref_buf[0]
theta = theta_buf[0]
# Loop read method:
#Vd_ref = p_Vd_ref.read()
#Vq_ref = p_Vq_ref.read()
#theta = p_theta.read()
# Shift and scale:
Vd_ref = (Vd_ref*0.40293040293)-825 #((Vd_ref/4095*3.3)-1.65)*500
Vq_ref = (Vq_ref*0.40293040293)-825
theta = (theta*0.00168779093)-0.314159265 # ((theta/4095*3.3)-0.15)*(2*pi*pole_pairs)/3/pole_pairs. The last division make it go 0 to 2*pi

# SVPWM duty cicle:
#duty_abc = svpwm(Vd_ref,Vq_ref,theta)

## Duty Cicle set:
#tch_A_upp.pulse_width_percent(duty_abc[0]) # A upper
#tch_B_upp.pulse_width_percent(duty_abc[1]) # B upper
#tch_C_upp.pulse_width_percent(duty_abc[2]) # C upper

flag_current_control = False
p_code_duration.low()

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

Re: Non-blocking ADC read?

Post by pythoncoder » Thu Apr 14, 2022 8:05 am

Nonblocking ADC read is sadly unsupported. The purpose of read_timed_multi (which blocks) is to enable phase measurements which are impossible with read_timed because it blocks for the duration.
Peter Hinch
Index to my micropython libraries.

rkompass
Posts: 66
Joined: Fri Sep 17, 2021 8:25 pm

Re: Non-blocking ADC read?

Post by rkompass » Thu Apr 14, 2022 4:38 pm

You could do low-level programming of the STM32F405 registers with machine.mem32[] statements.
A SWSTART or JSWSTART bit has to be set to start the conversion. And an EOC (End of Conversion) flag could be probed to determine when it is finished. These statements are very fast.
Yury Magda described it with some micropython code in his book:
Advanced Programming in MicroPython By Example
by Yury Magda
Paperback, 136 Pages, Published 2019
.

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

Re: Non-blocking ADC read?

Post by pythoncoder » Fri Apr 15, 2022 12:52 pm

Good point. Speed could be increased further using the inline assembler to read the three ADC's concurrently and populate an array with the results. It would block, but not for long.
Peter Hinch
Index to my micropython libraries.

Post Reply