Data type conversion with adc

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.
javiojeda
Posts: 4
Joined: Wed Feb 03, 2021 2:16 pm

Data type conversion with adc

Post by javiojeda » Wed Feb 03, 2021 2:34 pm

Hello,

I have an issue with my pyboard v1.1. I want to generate a control as follow :

every 1ms (
error = adc_input - adc_measure
error_corrected = K_P*error
write on DAC
)

With K_P = 2

Firstable, I used a simple while loop as :

Code: Select all

from pyb import Timer, Pin, ADC, DAC

from utime import sleep_ms

tim = Timer(1, freq=1000) # Définition du timer 1 à la fréquence 1000Hz

adc_pos = ADC(Pin('X11')) # Convertisseur analogique-numérique sur la pin 11

adc_neg = ADC(Pin('X12')) # Convertisseur analogique-numérique sur la pin 12

dac = DAC(Pin('X5'), bits=12)   # Convertisseur CNA 12 bit sur la pin X5

K_P = 2

while True:
    
    # Conversion numérique de la tension de sortie du système
    entree_pos = adc_pos.read() # Lecture du CAN
    entree_neg = adc_neg.read() # Lecture du CAN
    
    erreur = entree_pos - entree_neg
    
    erreur_corrigee = K_P*erreur
    
    dac.write(int(erreur_corrigee)) # Ecriture sur le CNA
    
    sleep_ms(1)
    
This solution works perfectly. My signals are correct and similar to signals obtained by simulations.

Now, I want to use a timer instead of sleep_ms(1). My code is now :

Code: Select all


from pyb import Timer, Pin, ADC, DAC

tim = Timer(1, freq=1000) # Définition du timer 1 à la fréquence 1000Hz

adc_pos = ADC(Pin('X11')) # Convertisseur analogique-numérique sur la pin 11

adc_neg = ADC(Pin('X12')) # Convertisseur analogique-numérique sur la pin 12

dac = DAC(Pin('X5'), bits=12)   # Convertisseur CNA 12 bit sur la pin X5

K_P = 2

def correction_avec_timer(timer):
    
    global K_P

    # Conversion numérique de la tension de sortie du système
    entree_pos = adc_pos.read() # Lecture du CAN
    entree_neg = adc_neg.read() # Lecture du CAN

    erreur = entree_pos - entree_neg
    
    erreur_corrigee = K_P*erreur

    dac.write(int(erreur_corrigee)) # Ecriture sur le CNA
    

# Fonction qui se déclenche à chaque fois que le timer finit sa boucle
tim.callback(correction_avec_timer)    
If K_P = 2 everything work perfectly as the previous while loop solution. However, if K_P = 2.0 I have no voltage from my DAC (oscilloscope visualisation).

I quite not understand why? Do you have any idea?

entree_pos is an integer thus, erreur is also an integer. K_P*erreur is a float beacause K_P is a float, however int(erreur_corrigee) is an integer and the DAC should work?

Thank you for your advices,

Le fond du garage
Posts: 9
Joined: Mon Dec 21, 2020 6:38 pm

Re: Data type conversion with adc

Post by Le fond du garage » Wed Feb 03, 2021 8:29 pm

a tu essayer avec la version sans timer? pour voir si tu a le même problème?
essaye de cast 'erreur' en float avant le calcul pour voir.

do you test it with the first version? have the same trouble?
test with cast the 'erreur' var in float before using it in calc.

Le fond du garage
Posts: 9
Joined: Mon Dec 21, 2020 6:38 pm

Re: Data type conversion with adc

Post by Le fond du garage » Wed Feb 03, 2021 8:32 pm

a tu tester ta fonction timer avant?

perso j'utilise ce type d'init pour les timers

Code: Select all

tim=machine.Timer()
tim.init(period=1000, callback=tick1) 

Le fond du garage
Posts: 9
Joined: Mon Dec 21, 2020 6:38 pm

Re: Data type conversion with adc

Post by Le fond du garage » Wed Feb 03, 2021 9:51 pm

after multiple test with your code, i find i can't make opérate with float in timer callback.

Code: Select all

from pyb import Timer, Pin, ADC, DAC
def correction_avec_timer(_):
    K_P=2.0
    try:
        erreurCorrigee =K_P*3
    except:
        print('erreur')
    else:
        print(erreurCorrigee)
    

# Fonction qui se déclenche à chaque fois que le timer finit sa boucle
tim.callback(correction_avec_timer)  
if i use k_p with 2 all is ok, but with float, i have an error.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Data type conversion with adc

Post by dhylands » Thu Feb 04, 2021 2:42 am

That's because floats require allocating memory and you're not allowed to allocate memory inside a HARD IRQ.

You should probably familiarize yourself with: http://docs.micropython.org/en/latest/r ... #isr-rules

javiojeda
Posts: 4
Joined: Wed Feb 03, 2021 2:16 pm

Re: Data type conversion with adc

Post by javiojeda » Thu Feb 04, 2021 7:45 am

Dear Le fond du garage, Dear dhylands,

Thank you for yours advices. I'm not in my lab today, I'll test tomorrow some new codes.

@dhylands : Do you think that a pre-allocation of erreur_corrigee could overcome the HARD IRQ limitation ? Something like :

Code: Select all


...

K_P = 2.0

erreur_corrigee = 0.0


def correction_avec_timer(timer):
    
    global K_P
    global erreur_corrigee

...

    erreur = entree_pos - entree_neg
    
    erreur_corrigee = K_P*erreur
    
...
@Le fond du garage : What is the difference between your init and mine?

Code: Select all

tim=machine.Timer()
tim.init(period=1000, callback=tick1) 
Thank you! I think I'm improving my micropython skills! :)

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Data type conversion with adc

Post by dhylands » Thu Feb 04, 2021 2:11 pm

Doing x = y * 1.5 will cause a memory allocation in order to store the result of y * 1.5

If you really need the floating point operation then the only real option you have is to use micropython.schedule which will cause your handler to run in the main program context rather than ISR context, and this in turn allows it to allocate memory.

javiojeda
Posts: 4
Joined: Wed Feb 03, 2021 2:16 pm

Re: Data type conversion with adc

Post by javiojeda » Fri Feb 05, 2021 7:42 am

Dear dhylands,

Thank your for your comment.

I quite not understand the functioning of micropython.schedule and how to implement it. Moreover, what is the difference using a simple while loop with a utime.sleep_ms(1) function.

On my oscilloscope with this solution my sample period is really stable around 1ms. Maybe it is not the most micropythonic solution but the most effective, is it?

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

Re: Data type conversion with adc

Post by pythoncoder » Fri Feb 05, 2021 10:58 am

It is possible to perform scaling using integer arithmetic, which can be done in an ISR. For example, to multiply by 1.5: 1.5 == 3/2. So multiply by 3 and shift right 1 bit:

Code: Select all

x *= 3
x >>= 1
This can be extended to more difficult numbers. Bear in mind that integers are 30 bits so you have a good deal of headroom when it comes to multiplication.
Peter Hinch
Index to my micropython libraries.

Le fond du garage
Posts: 9
Joined: Mon Dec 21, 2020 6:38 pm

Re: Data type conversion with adc

Post by Le fond du garage » Fri Feb 05, 2021 8:52 pm

and wy not using asyncio?

Post Reply