Problémy při programování ATmega328p, TCNT1 v CTC módu

xdtgj

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;
}


Jenda

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #1 kdy: 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.

xdtgj

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #2 kdy: 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.

technik

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #3 kdy: 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.

technik

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #4 kdy: 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/


xdtgj

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #5 kdy: 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/

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.

xdtgj

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #6 kdy: 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á.

dword

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #7 kdy: 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

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #8 kdy: 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č.

dword

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #9 kdy: 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.

dword

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #10 kdy: 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.

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #11 kdy: 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.
« Poslední změna: 29. 12. 2017, 20:48:20 od peterple »

xdtgj

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #12 kdy: 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.

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #13 kdy: 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.

xdtgj

Re:Problémy při programování ATmega328p, TCNT1 v CTC módu
« Odpověď #14 kdy: 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...