Go Down

Topic: [RESOLU] Input capture non fonctionnelle sur ATmega32u4 (Read 2289 times) previous topic - next topic

Reynosa

Nov 17, 2013, 01:50 am Last Edit: Nov 17, 2013, 08:35 pm by Reynosa Reason: 1
Bonsoir à tous et à toutes !

Pour mon projet sur arduino leonardo programmé sur avr Studio, j'ai besoin de récupérer le temps entre chaque front montant sur un signal ppm de ce genre:
http://www.pabr.org/pxarc/1.1/doc/opwm_ppm.gif
Pour une question d'encombrement, je suis contraint d'utiliser l'input capture sur la broche ICP3 de l'atmega32u4.
Jusque là pas de problème, je code un petit programme de test pour vérifier premièrement que tout fonctionne bien seul, avant d'intégrer le tout dans le programme final.
Code: [Select]
/*
* GccApplication1.cpp
*
* Created: 14/11/2013 16:46:50
*  Author: Procrastineur
*/
#define F_CPU 16000000UL
#define UBRRVAL1 8
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile uint32_t Micros = 0;
volatile uint16_t RC_Values[6] = {0};

void transmit_data(uint8_t data)
{
/* Wait for empty transmit buffer */
while ( !( UCSR1A & (1<<UDRE1)) );

/* Put data into buffer, sends the data */
UDR1 = data;
}

ISR(TIMER3_CAPT_vect)
{
PORTD |= 0x10;
volatile static uint8_t chan  = 0;
volatile        uint16_t temp = 0;

temp  = ICR3;
temp /= 2;
TCNT3 = 0;

sei();

if (temp > 3000)
chan = 0;

if (temp >= 800 && temp <= 2200)
RC_Values[chan] = temp;

chan++;
PORTD &= ~0x10;
}

int main(void)
{
//désactivation du module usb qui sature le µC
PRR1  |= 0x80;

// initialisation UART
DDRD  |= 0x18;
UBRR1H = (UBRRVAL1>>8); //high byte
UBRR1L = (uint8_t)UBRRVAL1; //low byte

UCSR1C = (1<<UCSZ11) | (1<<UCSZ10); //Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size
UCSR1B = (1<<RXEN1 ) | (1<<TXEN1 ); //Enable Transmitter and Receiver

// initialisation timer3
TCCR3A = 1<<WGM31 | 1<<WGM30;
TCCR3B = 1<<ICES3 | 1<<WGM33 | 1<<CS31;
OCR3A  = 32000;
TIMSK3 = 1<<ICIE3;
TIFR3  = 1<<ICF3;

sei();

while(1)
       {
           transmit_data(RC_Values[1]>>8);
           transmit_data(RC_Values[1]);
           transmit_data(0x0D);

   _delay_ms(500);
       }
}

Mauvaise nouvelle ça ne fonctionne pas... J'ai un beau triturer le pauvre morceau de code bidon dans tous les sens je n'arrive à rien... J'avais sous la main une Arduino Uno, donc j'ai adapté le nom des registres et j'ai tout envoyé dessus. Miracle tout fonctionne à merveille   :smiley-eek:
Pour information : PORTD pin 4 (Digital 4) ne passe jamais à "1" sur la leonardo.

C'est la raison pour laquelle je me tourne vers vous tous, je suis incapable d'expliquer pourquoi cela fonctionne d'un côté et non de l'autre  =(

Merci d'avance !

Super_Cinci

Salut,

Il me semble qu'il est fortement déconseillé de clarer des variables dans les routines d'interruption. Surtout que tu utilises des static, autant les déclarer en global volatile.

pourquoi utiliser le phase correct? car dans ce mode, TCNT3 monte et descend, tu ne peux pas mesurer grand chose avec un chrono qui fait le yoyo....

Reynosa

Bonjour

Pour les variables ça a toujours marché chez moi, mais je ferais la modification.
Le phase correct est le seul mode que je peux utiliser où j'ai le droit de définir le top que je veux et pour pallier au problème de monter et descente je remet le compteur à zéro à chaque capture. Avec le signal que j'ai, il est impossible que TCNT passe dans la phase de descente.

Le problème ici, c'est que l'interruption ne se lève jamais.

Super_Cinci


Avec le signal que j'ai, il est impossible que TCNT passe dans la phase de descente.
Mais dans ce cas, pourquoi définis-tu un TOP? j'imagine que c'est pour détecter une absence de signal (un coup d'OVF = time out.

Tu as les modes 4 : CTC sur TOP = OCR3A ou 15 : fast PWM avec TOP = OCR3A.

je m'étonne moi-même, j'ai pris un prog que j'avais fait qui utilise ICP, et j'ai mis le timer en mode 0 et il marche à merveille (time out sur 0xFFFF (4,1 sec.), mais dans mon cas, c'était cohérent, mes impulsions sont de l'ordre de la seconde)... tu devrais donc essayer le mode 4.

Par contre dans le core arduino, il y a une préinitialisation sauvage des timers, et pour être sûr, je configure tous les registres. n'aurais-tu pas ça de ton côté?

Reynosa

Je définie le top parce que sinon ça ne servirait pas à grand chose... Là il est définie de manière à repousser la zone de descente à un endroit temporellement inaccessible par le système en amont.

Effectivement le mode CTC pourrait marcher aussi. Mais pour le moment ça ne va strictement rien changer parce que là routine d'interruption ne s'exécute pas. Ce qui veut dire qu'aucune interruption n'est levée, alors qu'à l'oscilloscope j'ai bien tous mes fronts de visible.

Pour ma part je n'utilise pas du tout Arduino à part la carte sur laquelle le µC est câblé. Donc j'ai l'initialisation basique des registres comme précisé dans la doc. Le seul registre que je ne touche pas c'est le TCCR3B et sert uniquement à forcer des comparaisons.

Super_Cinci

Mais est-on sûr que l'ICP fonctionne en mode UP-DOWN? essaie quand même le mode 4, sinon, le mode 0, puisque tu cherches un TOP le plus loin possible, 65535, c'est plus loin que 32000...

Reynosa

le code présent dans le premier message fonctionne parfaitement sur une Arduino Uno (µC = ATmega328p) mais refuse de lever les interruptions sur la leornardo (µC = ATmega32u4). J'ai essayé le mode 4 tout à l'heure et le 0 de suite et ça ne change rien.

Reynosa

Je me suis penché sur le côté électrique de la chose...
J'avais toujours mon ppm sur la broche ICP3, mais le calibre vertical de mon oscillo m'a mis la puce à l'oreille : Chute de tension !
Donc le µC ne voit plus de front montant, le seuil niveau haut n'est plus atteint.. Pourtant je pensais avoir la broche en entré, le registre DDRC est censé être initialisé à 0 d'après la doc. Ca ne devait pas être le cas, ou alors il y avait un autre probleme, je n'en sait à vrai dire strictement rien. Néanmoins j'ai forcé manuellement le bit à 0.
Code: [Select]
DDRC  &= ~0x80;
Depuis tout fonctionne  :) Si quelqu'un avait éventuellement une explication je suis preneur  XD


Super_Cinci

sous IDE arduino, j'ai une fois fait un tout petit programme, puis décodé le .hex compilé. j'y ai appris plein de trucs, notamment le fait que arduino préconfigure TOUS les timers, donc si tu ne joues pas avec TOUS les registres, tu risques d'avoir des traces gênantes. peut-être aussi le cas avec avr studio sur le DDRC?

Reynosa

C'est possible, mais c'est pas normal, d'après le datasheet ce registre a une valeur initiale de 0 ce qui veut dire que le port est configuré en entré au démarrage. Néanmoins il est possible que je me trompe sur ce point...

Go Up