Bonjour à tous,
1ère question, triviale mais je trouve pas l'info :
comment initialiser le pointeur de pile sur un ATmega (8) ?
merci. je reviendrai.
-----
Bonjour à tous,
1ère question, triviale mais je trouve pas l'info :
comment initialiser le pointeur de pile sur un ATmega (8) ?
merci. je reviendrai.
En assembleur:
En C, rien à faire, le compilo s'en occupe. Si tu as le message d'erreur en C, il semblerait que ce soit un problème de versions de logiciels. Si tu veux le trifouiller, il faut aller voir dans la config du linkerCode:SPI_INIT: ldi r16,low(RAMEND) out Spl,r16 ldi r16,high(RAMEND) out sph,r16
merci
à propos de logiciel tout allait bien avec avr studio 4
maintenant avec la version 5 rien ne va plus -> je vais essayer "import project"
çà marche ! mais je traine toujours mon problème d'adc depuis des mois
(en fait je programme des pics, et je regarde l'atmega quand j'ai le temps)
atmega8-3x74LS47-3 afficheurs -> fonctionne
pin 20,21 = 5V
pin 28 = potar -> tension OK
mais mon adc me retourne toujours 640 en décimal
cette ébauche de programme alterne 000 et 640 !!!
Code:.include "m8def.inc" SP_INIT: ldi r16,low(RAMEND) out Spl,r16 ldi r16,high(RAMEND) out sph,r16 reset: LDI R16,0xFF OUT DDRD,R16 ;aff dizaines & unités LDI R16,0x0F OUT DDRC,R16 ; aff centaines ; CLR R16 OUT PORTD,R16 OUT PORTC,R16 ; affiche 000 ; LDI R20,0x05 STS ADMUX,R20 ; IN=ADC5 LDI R20,0x87 STS ADCSRA,R20 ; En, F/128 MAIN: CLR R22 CLR R23 CALL tempo LDI R20,0xC7 STS ADCSRA,R20 ;Start ADC CALL tempo LDS R26,ADCL ; lire ADC LDS R27,ADCH ; LDI R27,0x02 afficher 520 = OK ; LDI R26,0x08 ; Hexa -> BCD C: TST R27 BREQ OXX SBIW R26,0x32 SBIW R26,0x32 INC R23 RJMP C OXX: CPI R26,0x64 BRLO D SUBI R26,0x64 INC R23 RJMP OXX D: CPI R26,0x0A BRLO U SUBI R26,0x0A INC R22 RJMP D U: SWAP R22 ADD R22,R26 OUT PORTD,R22 OUT PORTC,R23 CALL tempo CALL tempo RJMP reset ; tempo: LDI R17,0x08 LOOP: SER R18 FLOOP: SER R19 VFL: DEC R19 BRNE VFL DEC R18 BRNE FLOOP DEC R17 BRNE LOOP RET
Attention, le prescaler de l'ADC doit être réglé de façon à ne pas dépasser une certaine fréquence.
De plus, AREF (broche 21) est une sortie si tu utilises la référence interne ou AVcc comme référence. Il ne faut donc pas la relier à Avcc, mais plutôt lui mettre un condo de découplage, et éventuellement t'en servir pour alimenter un potar.
Vu ton code on dirait que c'est bon (clock/128 et utilisation de Aref en externe).
Méfie-toi des tempos. Un AVR ça tourne 4 fois plus vite qu'un PIC16 pour un même quartz. La tempo pourrait être trop courte pour permettre la complétion de la conversion.
Tu devrais plutôt tester ADSC pour vérifier si la conversion est terminée.
Egalement, tu utilises STS pour accéder aux registres ADC, qui est l'accès à la SRAM, hors les registres ne sont pas là.
Si les registres ADC sont déclarés dans ton include à la suite des DDRx, utilise OUT comme pour les registres DDRx.
Si ils sont déclarés avec un offset de 0x20 (alias en RAM), utilise ST
Merci de me remettre le nez dans l'assembleur, ça faisait bien longtemps que je n'y avais pas touché
Pour plus tard, prends garde à ne pas écraser les adresses mémoire des vecteurs d'interruption. Page 47 de la datasheet de l'Atmega8, tu as un bout de code typique (et le fameux rjmp RESET)....D'ailleurs l'initialisation de la pile y est aussi
Un AVR ça se programme en C...
Quand on met un bit dans un registre, on met un commentaire à côté pour se rappeler ce que ça veut dire (et pas "0xC7" ) accessoirement avec des #define LISIBLES.
Je sais pas si c'est le cas sur ton AVR mais sur le mien (90PWM3B) il faut attendre que la PLL de l'horloge soit stabilisée.
Et AREF étant une sortie d'impédance élevée si tu choisis AREF=AVCC, il ne faut rien brancher dessus (sauf une capa). Et il faut attendre au boot que la capa se charge si elle est grosse...
Tiens, un exemple :
Pour détecter la fin de conversion il faut regarder le bit qui t'indique que la conversion est terminée dans le registre approprié (ou utiliser une interruption). Possible que ta tempo soit trop courte...Code:// Deactivate digital inputs on analog pins DIDR0 = | DIDR0_CURRENT | DIDR0_VOLTAGE | DIDR0_BATT_VOLTAGE | DIDR0_TEMPERATURE ; /***************************************** Clock Setup *****************************************/ // Setup PLL for PSC peripherals : Start_pll_32_mega(); Wait_pll_ready(); // Setup CPU clock prescaler to 8 MHz. CLKPR = Bit(CLKPCE); CLKPR = 1; // divide default 16 MHz clock by 2 => 8MHz /***************************************** ADC setup *****************************************/ ADMUX = ADMUX_REFS_BITS | // Ref is AVcc with external capacitor connected on the AREF pin ADC_CURRENT; ADCSRA = Bit(ADEN) | // Enable ADC Bit(ADATE) | // Autotrigger Bit(ADIE) | // Enable ADC Interrupt 3; // ADC clock prescaler ADCSRB = Bit(ADHSM) // ADC High Speed Mode | 10 // PSC2ASY Event ;
Vérifie la config de l'ADC (tu as bien configuré tous les registres ?), et que tu lis ADCH et ADCL dans le bon ordre.
A l'origine Aref n'était pas relié
j'ai ensuite mis un strap pour être sûr
mais tu soulèves un problème intéressant :
si je mets une référence de tension externe
et que je configure accidentellement une
référence interne (5V ou 2V56), çà va cramer ?
c'est sûrLa tempo pourrait être trop courte pour permettre la complétion de la conversion.
ici j'ai de la marge (1s)
pourquoi pasTu devrais plutôt tester ADSC pour vérifier si la conversion est terminée.
ici j'ai voulu aller au plus simple
Egalement, tu utilises STS pour accéder aux registres ADC, qui est l'accès à la SRAM, hors les registres ne sont pas là.
Si les registres ADC sont déclarés dans ton include à la suite des DDRx, utilise OUT comme pour les registres DDRx.
Si ils sont déclarés avec un offset de 0x20 (alias en RAM), utilise ST
Le problème est donc là.
j'ai pas tout saisi. tu n'aurais pas un cours dessus ?
quand j'arriverai jusque là, j'aurai des cheveux blancsPour plus tard, prends garde à ne pas écraser les adresses mémoire des vecteurs d'interruption. Page 47 de la datasheet de l'Atmega8, tu as un bout de code typique (et le fameux rjmp RESET)....D'ailleurs l'initialisation de la pile y est aussi
Un grand merci
Y'a des chances effectivement, comme toute broche mise en court-jus d'ailleurs...Par défaut, Aref est configuré en entrée, les risques sont moindres.
J'ai pas calculé, j'ai juste émis le doute, on sait jamaisc'est sûr
ici j'ai de la marge (1s)
Pas besoin de plus pour le moment...pourquoi pas
ici j'ai voulu aller au plus simple
page 18 de la datasheet, tu as le schéma avec la correspondance. En gros les 1ko de SRAM sont placés en mapping mémoire à partie de 0x060 jusqu'à 0x45F.
Le problème est donc là.
j'ai pas tout saisi. tu n'aurais pas un cours dessus ?
Les 32 registres de travail sont à partir de 0x0000 et les registres d'entrées-sorties sont à partir de l'adresse 0x020. Seulement, ils disposent d'un autre mode d'adressage ou ils sont placés à partir de l'adresse 0x000. Je ne sais pas trop pourquoi ces deux adresses cohabitent, sans doute pour des questions de compatibilité...
Page 24 de la doc, on te dit que si tu accèdes via les adresses partant de 0, tu dois utiliser IN et OUT. Si tu utilises les adresses à partir de 0x20, tu dois utiliser ST et LD.
Je soupçonne STS et LDS de n'être utiles qu'à partir de 0x060 mais je ne m'y engagerai pas, je ne maîtrise pas assez l'assembleur.
Un petit tour dans le m8def.inc te dira à quelle valeur correspond ADCSRA.
Si tu as un ".equ ADCSRA 0x06" alors il faut utiliser IN et OUT.
Si tu as un ".equ ADCSRA 0x26", ST et LD
L'avantage d'utiliser les adresses basses, c'est de pouvoir accéder directement aux bits par CBI et SBI
Par exemple, pour lancer la conversion, tu écris:
Alors que tu peux écrire plus simplement:Code:LDI R20,0xC7 STS ADCSRA,R20 ;Start ADC
Deux fois plus rapide, pas de registre utilisé comme buffer et une conservation de l'état précédent de ADCSRA (autrement dit, pas besoin de modifier tout le prog si tu touches au prescaler par exemple ou de faire un masquage)Code:SBI ADCSRA,ADSC
Encore faudrait-il qu'ils repoussentquand j'arriverai jusque là, j'aurai des cheveux blancs
Les interruptions sont hyper simples à utiliser...un vecteur différent par interruption (ça change hein ), pas de priorité à gérer (mais leur hiérarchie est assez logique), le placement des adresses sur la pile est automatique.
Au pire, il faut sauvegarder les registres de travail à la main, mais avec 32 registres, il est aussi possible de les répartir entre programme principal et routines d'interruption.
En gros ton programme commence par un ensemble de sauts, le premier étant le reset, dirigé normalement vers le début du programme
Dans les interruptions inutilisées, tu fais un rjmp Reset. Comme ça si une interruption non souhaitée (erreur de config) survient, le programme redémarre plutôt que de partir dans la quatrième dimension. Sinon un simple iret dans la routine permet d'en sortir immédiatement et de continuer l'exécution, moyennant la perte de quelques temps de cycleCode:rjmp Reset rjmp INT0_H rjmp INT1_H rjmp TIMER2_COMP_H . . . rjmp SPM_RDY_H Reset: début effectif du programme INT0_H: //routine éventuelle iret
De rien...mais je suis assez d'accord avec Bobfuck pour te conseiller le C. Tu t'évites bien des noeuds dans les neurones, pour un résultat quasi-identique, voire meilleur que l'assembleur à la mainUn grand merci
Et puis les libraries C pour l'AVR sont quand même bien faites.
Au début, par exemple tu utilises les fonctions setup_machin() et adc_get_result(), tu as pratiquement une fonction C par fonction du uC, c'est très clair.
Ensuite, tu regardes dans les headers et la datasheet, et tu remplaces certaines fonctions par le code source original (par exemple c'est pas la peine d'appeler 4 fonctions pour initialiser le même registre !... ça économise de la flash).
A la fin sans t'en apercevoir tu as appris à utiliser les registres du uC.
La gestion des interruptions en C est aussi totalement classe :
et hop une routine d'interruption !Code:ISR(ADC_vect) { uint16_t adc = Adc_get_10_bits_result(); ... }
bonsoir,
je profite de cette discussion pour en apprendre encore un peu:Et puis les libraries C pour l'AVR sont quand même bien faites.
Au début, par exemple tu utilises les fonctions setup_machin() et adc_get_result(), tu as pratiquement une fonction C par fonction du uC, c'est très clair.
j'ai foncé bille en tête pour utiliser l'AVR sans penser aux librairies car j'ai pas l'impression quelles soient fournies avec la suite AVR, je me trompe?
C'est fourni avec avrstudio, fouille dans les programmes d'exemple.
Ceci dit tu peux aussi bien patouiller les registres à la main... mais c'est sympa pour débuter, ça te donne un stock de code tout cuit.
Mais...mais...je les ai pas vu ces programmes d'exemple...à moins que ce soit dans la v 5
beuah c'est peut-être avec avr-gcc alors XDDD
je sais plus mais elles sont bien venues de quelque part ces libraries...
Effectivement, c'est avec la V5:
http://atmel.com/dyn/products/tools_...family_id=2138
çà marche !!
Code:.include "m8def.inc" reset: ldi r16,low(RAMEND) out Spl,r16 ldi r16,high(RAMEND) out sph,r16 LDI R16,0xFF OUT DDRD,R16 ;aff dizaines & unités LDI R16,0x0F OUT DDRC,R16 ; aff centaines ; CLR R16 OUT PORTD,R16 OUT PORTC,R16 ; affiche 000 ; LDI R20,0x05 OUT ADMUX,R20 ; IN=ADC5 LDI R20,0x87 OUT ADCSRA,R20 ; En, F/128 MAIN: CLR R22 CLR R23 RCALL tempo LDI R20,0xC7 OUT ADCSRA,R20 ;Start ADC RCALL tempo IN R26,ADCL ; lire ADC IN R27,ADCH ; Hexa -> BCD C: TST R27 BREQ OXX SBIW R26,0x32 SBIW R26,0x32 INC R23 RJMP C OXX: CPI R26,0x64 BRLO D SUBI R26,0x64 INC R23 RJMP OXX D: CPI R26,0x0A BRLO U SUBI R26,0x0A INC R22 RJMP D U: SWAP R22 ADD R22,R26 OUT PORTD,R22 OUT PORTC,R23 RJMP MAIN ; tempo: SER R19 VFL: DEC R19 BRNE VFL RET
à ce niveau j'hésite :
le but à long terme est de filmer ces afficheurs avec une caméra ultra-rapide (400Hz),
et ensuite reconnaissance des chiffres pour récupérer mes valeurs instantanées
et donc si je multiplexe mes afficheurs à 4kHz çà va marcher ?
bah ça devrait....
Plutôt que de filmer un cadran, lu par une caméra, analysé...pourquoi ne pas directment envoyer l'info au PC?
parce que il va y avoir des centaines d'afficheurs amovibles
ce serait pas plus simple de récupérer directement le signal qui est envoyé aux dits afficheurs ?
Bonsoir,
C'est vrai que bizarre comme principe de mesure. Il doit avoir un truc qui m'échappe dans la nécessité de faire cela.
Pourquoi ne pas faire les mesures et les envoyer directement à un moyen d'acquisition.
Car là on est dans le principe:
analogique->numérique->analogique->numérique.
sans compter vision->imperfection->complexité...Bonsoir,
C'est vrai que bizarre comme principe de mesure. Il doit avoir un truc qui m'échappe dans la nécessité de faire cela.
Pourquoi ne pas faire les mesures et les envoyer directement à un moyen d'acquisition.
Car là on est dans le principe:
analogique->numérique->analogique->numérique.
et avec une transmission des valeurs mesurées par fibre optique ?
oui mais là il faut des buffers, et j'en voudrais un triple en DIP8 pour passer de +5 à +12V
t'as déjà vu ? sinon que proposes tu ?
Tu peux trouver les transmetteurs/récepteurs optiques style TORX machin pour audio numérique à $1.50 environ...
Tu peux multiplexer un petit peu aussi
Enfin si tu veux une isolation galvanique complète, la fibre c'est bon... mais comment tu fais pour les alims ?