interfaces analogiques (adc & dac) arduino due sÉminaire...
TRANSCRIPT
ARDUINO DUE
¢ Atmel SAM3X8E Arm Cortex M3 � 32 bits � 84 MHz � 3.3 Volts ! Attention !!!
¢ 11 Canaux d’ADC : AT06860 � 12 bits, � Jusqu’à 1MHz (mais 666 kHz à cause du 84 MHz)
¢ 84/6 = 14 MHz max clock de l’ADC ¢ 14 MHz / 21=666 kHz sampling rate
¢ 2 Canaux de DAC � 12 bits � Jusqu’à 666 kHz
UTILISATION SIMPLE
¢ Mavaise idée !! � Vitesse limitée
¢ ~20kHz
� Aucune garantie ¢ Fs ne sera pas constant
� Bloque le flot d’exécution
void setup() { // put your setup code here, to run once: analogWriteResolution(12); analogReadResolution(12); // 10 is default Serial.begin(9600); } void loop() { // put your main code here, to run repeatedly: uint16_t i =0; analogWrite(DAC0,i); Serial.print(analogRead(A0)); i++; }
INTERUPTIONS
¢ Signal émis par du HW ou du SW pour signifier qu’un évènement demande de l’attention immédiate � L’état (registre, stack…) peut être sauvegardé � Le code est interrompu � La fonction d’interruption est appelée.
¢ C.f.: Ordinateurs, structures et applications
TIMER INTERUPTS SUR LE DUE
¢ Les compteurs (timer counters) � On peut leur spécifier une horloge
¢ On peut diviser l’horloge de 84 MHz par: ¢ 2, 8, 32, 128
� On leur spécifie jusqu’à combien compter � Vont générer une interruption HW lors que le
compteur déborde
¢ Exemple: � 84 MHz / 2 = 42 MHz � Compter jusqu’à 1000
¢ L’interrupt surviendra à 42 kHz.
LES COMPTEURS
¢ 3 Modules de Compteurs � TC0, TC1, TC2
¢ Chaque compteur a 3 canaux � 0, 1, 2
¢ 9 Canaux au total � Chaque canal est un compteur et chaque a son
interupt et sa fonction de gestion d’interruption
� Numéro de l’IRQ ¢ 3*TC + canal ¢ Exemple TC1, canal 2
¢ IRQ 3*1+2 = 5
EXEMPLE INTERUPT TC2, CHAN 1 => #7
const int led_pin = 13; int state = false; void setup() { pinMode(led_pin, OUTPUT); pmc_set_writeprotect(false); // power management control (pmc) pmc_enable_periph_clk(ID_TC7); // Allumer le périphérique qui sera utilisé // Config le timer TC2, channel 1, TIMER_CLOCK4 == /128 TC_Configure(TC2,1, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4); TC_SetRC(TC2, 1, 131200); // On compte jusqu’à 131200 TC_Start(TC2, 1); // Partir le timer // Faire en sorte que la fonction d’interruption est appelée TC2->TC_CHANNEL[1].TC_IER=TC_IER_CPCS; // IER = interrupt enable register TC2->TC_CHANNEL[1].TC_IDR=~TC_IER_CPCS; // IDR = interrupt disable register NVIC_EnableIRQ(TC7_IRQn); }
EXEMPLE INTERUPT: FONCTION DE GESTION
¢ 84MHz/128/131200 = 5 Hz (0.2 seconde) � TIMER_CLOCK1 == /2 , � …, � TIMER_CLOCK4 == /128
void loop() { // Il ne se passe rien dans la boucle !!! } void TC7_Handler() { TC_GetStatus(TC2, 1); // Efface le status et permet un nouvel appel de l’interrupt state = !state; digitalWrite(led_pin, state); // On fait juste clignoter une LED 5 fois par sec }
INTERRUPTIONS: PARFAIT POUR LE DAC
¢ Générer la forme d’onde qui va contrôler le moteur
¢ DDS: Direct digital synthesis � Configurer un interrupt pour avoir le taux
d’échantillonage voulu. � Définir un tableau (array)
¢ Ex: un cycle d’une onde triangulaire
� Jouer le tableau en boucle ¢ un échantillon à chaque passage dans la fonction de gestion
Ne pas utiliser: “analogWrite”
Utiliser: “dacc_write_conversion_data” Plus rapide
INTERUPTION ET ADC
¢ Acquérir le signal du photodétecteur
¢ On pourrait procéder de la même manière pour l’ADC � Lire un échantillon à chaque interuption
¢ On aurait le problème de gérer l’interface série à chaque interuption, pour transmettre un point
¢ Et/ou d’écrire du code pour regrouper les données
¢ On peut faire mieux avec le DMA. � DMA == Direct memory access.
DMA & ADC
¢ On peut configurer l’ADC pour échantillonner tout le temps � C’est un périphérique indépendant du processeur � Les échantillons vont juste aller nulle part.
¢ On peut dire à l’ADC d’envoyer les échantillons directement dans la RAM � Adresse du premier échantillon � Taille du tableau.
¢ Quand le tableau est plein, les échantillons se perdent à nouveau
¢ Le processeur peut lire la RAM en temps opportun � Dans la boucle principale
STATÉGIE: ADC
¢ Dans setup() � Configurer l’ADC pour qu’il échantillonne au taux voulu
¢ Lorsqu’on est prêt � Passer l’adresse et la taille du bloc via le PDC
¢ Dans la boucle loop() � Gérer le contrôleur série et transmettre les données du
bloc lorsque l’ordinateur le demande.
� c.f. exemple dans les références ‘nicecircuits.com’
SYNCHRONISATION DU DAC ET DE L’ADC
¢ On veut partir l’acquisition quand le balayage commence: � Configurer le DMA avec le PDC dans l’interrupt
utilisé pour le DAC ¢ À chaque fois qu’on passe à un endroit précis de la forme
d’onde Forme d’onde générée par le DDS
Passer le tableau au DMA lorsqu’on est à cet endroit dans le cycle
NOTES
¢ La programmation avec interuptions n’est pas séquentielle � Comme le DMA est configuré dans l’interrupt
¢ Le tableau peut commencer à se remplir n’importe quand ¢ Peut importe où on est rendu dans la boucle loop()
¢ Bonnes pratiques � Sémaphores � Double buffer
Pas si facile à gérer correctement!
RÉFÉRENCES: INTERUPT TIMERS, DDS
¢ http://rcarduino.blogspot.ca/2012/12/arduino-due-dds-part-1-sinewaves-and.html
¢ http://coolarduino.blogspot.ca/2015/07/fast-sampling-with-arduino-due.html
¢ http://arduino-er.blogspot.ca/2013/04/implement-timer-interrupt-for-arduino.html
¢ http://2manyprojects.net/timer-interrupts
RÉFÉRENCES: ADC
¢ http://asf.atmel.com/docs/3.21.0/sam3s/html/sam_adc_quickstart.html
¢ http://asf.atmel.com/docs/3.21.0/sam3s/html/index.html
¢ http://www.atmel.com/Images/Atmel-42109-SAM-Analog-to-Digital-Converter-ADC-Driver_ApplicationNote_AT03243.pdf
¢ http://www.atmel.com/Images/Atmel-42298-SAM3-4S-4C-Analog-to-digital-Converter-ADC_ApplicationNote_AT06860.pdf
¢ http://asf.atmel.com/docs/3.0.1/sam.drivers.adc.adc_example.arduino_due_x/html/adc_8h_source.html