Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: xdtgj 29. 12. 2017, 09:51:12

Název: Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: xdtgj 29. 12. 2017, 09:51:12
Zdravím všechny místní, potřeboval bych od Vás pomoc s nalezením chyby ve dvou programech. Chtěl jsem na Arduinu rozblikat diodu pomocí časovače v CTC módu v C a později v Asembleru, ale ani v jednom z jazyků se mi to bohužel nepovedlo. Budete někdo vědět, kde by mohl být problém? U programu v Asembleru jsem si kvůli lazení zkusil rozblikat OC1A, který funguje výborně, časovač tedy běží. Dokonce to vypadá, že se program přerušení jednou provede, ale vypadá to, že se provede právě jednou. U programu v C se mi podle všeho nedaří ani rozchodit přerušení. Díky všem za odpovědi.

Program v Asembleru:
Kód: [Vybrat]
; register name definition

.equ pinb, 0x23
.equ ddrb, 0x24
.equ portb, 0x25

.equ pinc, 0x26
.equ ddrc, 0x27
.equ portc, 0x28

.equ pind, 0x29
.equ ddrd, 0x2A
.equ portd, 0x2B

.equ iopinb, 0x3
.equ ioddrb, 0x4
.equ ioportb,0x5

.equ iopinc, 0x6
.equ ioddrc, 0x7
.equ ioportc,0x8

.equ iopind, 0x9
.equ ioddrd, 0xA
.equ ioportd,0xB

.equ spl, 0x5D
.equ sph, 0x5E
.equ sreg, 0x5F

.equ iospl, 0x3D
.equ iosph, 0x3E
.equ iosreg, 0x3F

.equ timsk1, 0x6F
.equ tccr1a, 0x80
.equ tccr1b, 0x81
.equ tccr1c, 0x82

.equ tifr1, 0x36
.equ iotifr1,0x16

.equ mcucr, 0x55
.equ iomcucr,0x35

.equ tcnt1l, 0x84
.equ tcnt1h, 0x85
.equ ocr1al, 0x88
.equ ocr1ah, 0x89
.equ RAMEND, 0x8FF

.org 0x0
rjmp START ; Go to the begin of the program
.org 0x2C ; TIM1_COMPA interrupt
rjmp TOOGLE_LED ; Toogle LED if interrupt occurs

.org 0x68
START: ; Begin of the program, initialization part
; sei
cli ;
ldi r17, 0x0
in r16, iomcucr
ori r16, 0x1
out iomcucr, r16
out iomcucr, r17
ldi r16, hi8(RAMEND);
out iosph, r16 ;
ldi r16, lo8(RAMEND);
out iospl, r16 ;
ldi r16, 0; ;
sts tcnt1h, r16 ;
sts tcnt1l, r16 ;
ldi r16, 0x0 ;
out ioportc, r16 ;
ldi r16, 0xFF ;
out ioddrc, r16 ;
out ioddrb, r16
ldi r16, hi8(31250) ;
ldi r17, lo8(31250) ;
sts ocr1ah, r16 ;
sts ocr1al, r17 ;
ldi r16, 0x40 ;
sts tccr1a, r16 ;
ldi r16, 0x8 ;
sts tccr1b, r16 ;
ldi r16, 0x2 ;
sts timsk1, r16 ;
ldi r16, 0x0
sts tifr1, r16
ldi r16, 0x0
out ioportb, r16
lds r16, tccr1b ;
andi r16, 0xF8 ;
ori r16, 0x4 ;
sei ;
sts tccr1b, r16 ;
INFINITE_LOOP:
rjmp INFINITE_LOOP

TOOGLE_LED:
in r16, ioportb ;
ldi r17, 0x1 ;
eor r16, r17 ;
out ioportb, r16 ;
reti ;

Program v C (ano, hlavičkové soubory mám pojmenované hloupě, mea culpa):
Blinking_LED.c
Kód: [Vybrat]
#define __AVR_ATmega328P__
//#define __AVR_ATmega128__
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Initialization.c"
#include "XorLED.c"


void main(void){
    cli();
    init();
    sei();
    TCCR1B &= 0xFC;
    TCCR1B |= (1<<CS12);  // Start TCNT1
}

Initialization.c
Kód: [Vybrat]
#define __AVR_ATmega328P__
//#define __AVR_ATmega128__
#include <avr/io.h>
#include <avr/interrupt.h>

void init(){
    SP = RAMEND;
    DDRC = 0x4;
    PORTC = 0;
    DDRB = 0x2;
    PORTB = 0;


    TIFR1 = 0;
    TCNT1 = 0;
    TCCR1A = 0;
    TCCR1B = (1<<WGM12);
    TIMSK1 = 0x2; //(1<<OCIE1A);
    OCR1A = 31250;

    return;
}

XorLED.c
Kód: [Vybrat]
#define __AVR_ATmega328P__
//#define __AVR_ATmega128__
#include <avr/io.h>
#include <avr/interrupt.h>


ISR(TIMER1_COMPA_vect){
 PORTC ^= 0x4;
}
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: Jenda 29. 12. 2017, 10:23:32
Přiznám se, že mě ještě nikdy nenapadlo na baremetal vyskočit z mainu, ale tady http://www.avrfreaks.net/comment/619240#comment-619240 píšou, že se ti stane CLI.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: xdtgj 29. 12. 2017, 10:37:22
Přiznám se, že mě ještě nikdy nenapadlo na baremetal vyskočit z mainu, ale tady http://www.avrfreaks.net/comment/619240#comment-619240 píšou, že se ti stane CLI.

Díky za nápad, pročetl jsem diskusi, zkusil jsem na konec mainu přidat nekonečnou smyčku, jak doporučovali, ale bohužel beze změny.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: technik 29. 12. 2017, 16:31:54
Nevím, jestli ten řádek v Initialization.c

Kód: [Vybrat]
TCCR1B = (1<<WGM12);

Dělá přesně to, v co doufáte.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: technik 29. 12. 2017, 16:56:58
A ještě:
Kód: [Vybrat]
TIMSK1 = 0x2; //(1<<OCIE1A);

OCIE1A je v TIMSK1 bit 4 a vy tímhle nastavujete bit 1

Zkuste mrknout zde:
http://maxembedded.com/2011/07/avr-timers-ctc-mode/ (http://maxembedded.com/2011/07/avr-timers-ctc-mode/)
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: xdtgj 29. 12. 2017, 17:31:06
A ještě:
Kód: [Vybrat]
TIMSK1 = 0x2; //(1<<OCIE1A);

OCIE1A je v TIMSK1 bit 4 a vy tímhle nastavujete bit 1

Zkuste mrknout zde:
http://maxembedded.com/2011/07/avr-timers-ctc-mode/ (http://maxembedded.com/2011/07/avr-timers-ctc-mode/)

Díky za odpověď, vyzkoušel jsem vše, co jste navrhoval, ale bohužel bez výsledku.
Provedl jsem následující úpravy:
TCCR1B = 0x8;
TIMSK1 = 0x4;

Článek, který se Vám podařilo najít je velice přehledný, bohužel se obávám, že čerpá ze staršího datasheetu, týkajícího se pravděpodobně starší ATmega 8, jak předběžně vyvozuji z názvu registru TIMSK. Pro úplnost přikládám odkaz na aktuální datasheet: http://www.atmel.com/Images/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_datasheet.pdf#_OPENTOPIC_TOC_PROCESSING_d94e58732

Informace o uspořádání registrů by měly být na straně 429.

Každopádně díky, každá rada dobrá, tím spíše, že je jich málo.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: xdtgj 29. 12. 2017, 19:19:54
Tak jsem pokročil. :-D

Našel jsem si nějaký program, který je napsaný v tom C pro Arduino ( http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/ )a překopíroval ho do toho jejich vývojového prostředí. Program fungoval bezchybně. Přidal jsem k němu své vlastní úpravy co se týče nastavení portů, program funguje opět bez chyby.
Kusy kódu jsem fakticky nakopíroval z mého původního programu.
Kód: [Vybrat]
// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>

#define LEDPIN 2

void setup() {
    SP = RAMEND;
    DDRC = 0x4;
    PORTC = 0;
    DDRB = 0x2;
    PORTB = 0;

 
     // initialize Timer1
 cli();      // disable global interrupts
  TCCR1A = 0;   // set entire TCCR1A register to 0
  TCCR1B = 0;   // same for TCCR1B

  // set compare match register to desired timer count:
  OCR1A = 15624;
  // turn on CTC mode:
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR1B |= (1 << CS10);
  TCCR1B |= (1 << CS12);
  // enable timer compare interrupt:
  TIMSK1 |= (1 << OCIE1A);
  sei();      // enable global interrupts

}

void loop() {
  // put your main code here, to run repeatedly:

}

ISR(TIMER1_COMPA_vect){
  PORTC ^= 0x2;
}

Výše uvedený program jsem rozdělil na inicializační funkci a zbytek, viz. níže. Nejsem si vědom jakýchkoliv jiných změn. Program jsem zkompiloval, nefunguje. Nevíte, kde bych zjistil, jakým přesně způsobem vývojové prostředí arduina kompiluje kód, případně kde by jinde mohla být chyba? Díky za odpovědi.
Inicialization.c
Kód: [Vybrat]
#define __AVR_ATmega328P__
//#define __AVR_ATmega128__
#include <avr/io.h>
#include <avr/interrupt.h>

void init(){
    SP = RAMEND;
    DDRC = 0x4;
    PORTC = 0;
    DDRB = 0x2;
    PORTB = 0;


     // initialize Timer1
 cli();      // disable global interrupts
  TCCR1A = 0;   // set entire TCCR1A register to 0
  TCCR1B = 0;   // same for TCCR1B

  // set compare match register to desired timer count:
  OCR1A = 15624;
  // turn on CTC mode:
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR1B |= (1 << CS10);
  TCCR1B |= (1 << CS12);
  // enable timer compare interrupt:
  TIMSK1 |= (1 << OCIE1A);
  sei();      // enable global interrupts

    return;
}

Blinking_LED.c
Kód: [Vybrat]
#define __AVR_ATmega328P__
//#define __AVR_ATmega128__
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Initialization.c"



int main(void){
    init();
    while(1);
}


ISR(TIMER1_COMPA_vect){
  PORTC ^= 0x2;
}

Příkazy použité při kompilaci a nahrávání sw:
Kód: [Vybrat]
avr-gcc Blinking_LED.c -o Blinking_LED.elf

avr-objcopy -O ihex -R .eeprom Blinking_LED.elf Blinking_LED.hex

avrdude -p atmega328p -c arduino -P /dev/ttyACM0 -b 115200 -U flash:w:Blinking_LED.hex:i

Možná jsem z toho už trochu dezorientovaný, ale nějak netuším, co mi tady uniká.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: dword 29. 12. 2017, 20:10:05
Jak rikal kolega, nastav bit4 v TIMSK, tzn. bud tam vloz konstantu (1 << 4) nebo 0x10.

TIMSK = 0x2; nastavuje bit1
TIMSK = 0x4; nastavuje bit2
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: peterple 29. 12. 2017, 20:15:21
prečo nastavuješ v init SP. Jak sa potom chceš  vrátiť späť do hlavného programu. Prácu so zásobníkom nechaj na prekladač.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: dword 29. 12. 2017, 20:20:07
Aaa tak podle tveho datasheetu je hodnota 0x2 pro TIMSK1 dobre.

prečo nastavuješ v init SP. Jak sa potom chceš  vrátiť späť do hlavného programu. Prácu so zásobníkom nechaj na prekladač.
Hehehe dobry postreh :) rekl bych ze to bude ono.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: dword 29. 12. 2017, 20:31:52
Aaa tak podle tveho datasheetu je hodnota 0x2 pro TIMSK1 dobre.

prečo nastavuješ v init SP. Jak sa potom chceš  vrátiť späť do hlavného programu. Prácu so zásobníkom nechaj na prekladač.
Hehehe dobry postreh :) rekl bych ze to bude ono.
Zas mi tam ale nesedi jedna vec, ze teorieticky at se to do mainu teda uz nikdy nevrati, dejme tomu... porad by se melo volat preruseni.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: peterple 29. 12. 2017, 20:46:09
lenže globálne povolenie prerušení má až main kam sa ale nevráti.
Edit: teda v tom pôvodnom programe. Potom to akože opravil ale len akože.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: xdtgj 29. 12. 2017, 20:49:05
prečo nastavuješ v init SP. Jak sa potom chceš  vrátiť späť do hlavného programu. Prácu so zásobníkom nechaj na prekladač.

Díky, fakt hodně dobrý postřeh. Původně jsem to na překladači chtěl nechat, ale pokud to smažu, tak se mi Arduino opakovaně restartuje (bliká ta oranžová dioda na třináctce nebo jakém čísle). Ale je pravda, že se s tím budu muset vypořádat jinak.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: peterple 29. 12. 2017, 21:00:35
Vyprdni sa na arduino prostredie. Rob to v AtmelStudiu a krokuj si to v simulátore. Takto si slepý a nevieš kde sa ti to ako preháňa. Čo a kde nemáš nastavené a pod. Tam si presnoríš čo chceš. Nastavíš breakpointy. Na takétol low level pokusy ako sa snažíš najlepšia vec.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: xdtgj 29. 12. 2017, 21:04:26
Tak jsem vyřadil jak init(), tak ten SP, ale stejně to nefunguje. Alespoň se to dokolečka nerestartuje...
Každopádně díky za ten SP. To jsem si vůbec neuvědomil...

Kód: [Vybrat]
#define __AVR_ATmega328P__
//#define __AVR_ATmega128__
#include <avr/io.h>
#include <avr/interrupt.h>
//#include "Initialization.c"



int main(void){
   // SP = RAMEND;
    DDRC = 0x4;
    PORTC = 0;
    DDRB = 0x2;
    PORTB = 0;


     // initialize Timer1
 cli();      // disable global interrupts
  TCCR1A = 0;   // set entire TCCR1A register to 0
  TCCR1B = 0;   // same for TCCR1B

  // set compare match register to desired timer count:
  OCR1A = 15624;
  // turn on CTC mode:
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR1B |= (1 << CS10);
  TCCR1B |= (1 << CS12);
  // enable timer compare interrupt:
  TIMSK1 |= (1 << OCIE1A);
  sei();      // enable global interrupts

    while(1);
}


ISR(TIMER1_COMPA_vect){
  PORTC ^= 0x2;
}


Vyprdni sa na arduino prostredie. Rob to v AtmelStudiu a krokuj si to v simulátore. Takto si slepý a nevieš kde sa ti to ako preháňa. Čo a kde nemáš nastavené a pod. Tam si presnoríš čo chceš. Nastavíš breakpointy. Na takétol low level pokusy ako sa snažíš najlepšia vec.

Bohužel. :-( To bych musel mít Windows a kvůli Arduinu jsem ho nechtěl řešit. Ale jak to vidím, asi budu muset změnit názor...
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: peterple 29. 12. 2017, 21:05:47
To reštartovanie nebolo náhodou spôsobené tým že si nemal nekonečnú slučku na konci main? Lebo každý kompiler to robí inak. Niektorý keď vyletíš z mainu to zacyklí sám. Iný to reštartne lebo to považuje za chybu tvojho programu.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: xdtgj 29. 12. 2017, 21:10:30
To reštartovanie nebolo náhodou spôsobené tým že si nemal nekonečnú slučku na konci main? Lebo každý kompiler to robí inak. Niektorý keď vyletíš z mainu to zacyklí sám. Iný to reštartne lebo to považuje za chybu tvojho programu.

To si nemyslím. Sice jsem si teď pustil na Arduinu jenom tu samotnou smyčku, ale obecně když jsem programoval v Asembleru, restarty Arduina vždy znamenaly neinicializovaný SP (na nulové adrese je zkrátka vektor přerušení pro restart).
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: xdtgj 29. 12. 2017, 21:13:25
To reštartovanie nebolo náhodou spôsobené tým že si nemal nekonečnú slučku na konci main? Lebo každý kompiler to robí inak. Niektorý keď vyletíš z mainu to zacyklí sám. Iný to reštartne lebo to považuje za chybu tvojho programu.

To si nemyslím. Sice jsem si teď pustil na Arduinu jenom tu samotnou smyčku, ale obecně když jsem programoval v Asembleru, restarty Arduina vždy znamenaly neinicializovaný SP (na nulové adrese je zkrátka vektor přerušení pro restart).

Abych to doplnil - samotná smyčka se nerestartuje.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: peterple 29. 12. 2017, 21:24:09
Hodil som do simulátora tvoj posledný výtvor. Kód v ISR sa vykonáva. LED nebliká lebo ako výstup si si zapol PC2, ale v prerušení neguješ PC1.
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: xdtgj 29. 12. 2017, 21:50:16
Hodil som do simulátora tvoj posledný výtvor. Kód v ISR sa vykonáva. LED nebliká lebo ako výstup si si zapol PC2, ale v prerušení neguješ PC1.

No... Tak teď se cítím trochu trapně, ta chyba tam byla evidentní.

Program jsem podle té chyby opravil, ale stejně mi to nebliká. Asi si na tohle opravdu budu muset pořídit Windows...
Kód: [Vybrat]
#define __AVR_ATmega328P__
//#define __AVR_ATmega128__
#include <avr/io.h>
#include <avr/interrupt.h>
//#include "Initialization.c"



int main(void){
    cli();
    // SP = RAMEND;
    DDRC = 0xFF;
    PORTC = 0;
    DDRB = 0xFF;
    PORTB = 0;


     // initialize Timer1
       // disable global interrupts
  TCCR1A = 0;   // set entire TCCR1A register to 0
  TCCR1B = 0;   // same for TCCR1B

  // set compare match register to desired timer count:
  OCR1A = 15624;
  // turn on CTC mode:
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR1B |= (1 << CS10);
  TCCR1B |= (1 << CS12);
  // enable timer compare interrupt:
  TIMSK1 |= (1 << OCIE1A);
  sei();      // enable global interrupts

    while(1);
}


ISR(TIMER1_COMPA_vect){
  PORTC ^= 0x4;
}

}
Název: Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
Přispěvatel: xdtgj 29. 12. 2017, 21:56:47
Nahrál jsem to přes Arduino IDE a vše funguje bez problémů. Docela by mě zajímalo, v čem to je...
Každopádně díky za pomoc s tou chybou přes ten simulátor.