Mám problém zprovoznit TCNT0 dle svých představ

Just_assembly_arduino

Mám problém zprovoznit TCNT0 dle svých představ
« kdy: 17. 09. 2017, 11:11:07 »
Zdravím všechny místní programátory, potřeboval bych Vás jako začátečník v assembleru pro AVR poprosit o radu. Nedávno jsem si napsal program pro ATMEGA 328 P-PU, ve kterém se snažím s pomocí TCNT0 využít CTC cyklu naprogramovat zpoždění (původně 1s, nyní jakékoliv rozumně sledovatelné, protože nevím přesně, jaký má Arduino krystal). To jsem chtěl vytvořit tak, že bude přerušení od přetečení časovače na hodnotě dané OCR2A počítáno. Vypadá to zatím, že časovač nějak funguje, (výstup OC2A svítí), ale nedaří se mi program rozchodit jako celek. Dokážete najít, kde jsem udělal chybu? Program je níže, Díky předem za jakékoliv podněty.

PS: Víte někdo o nějakém triviálním způsobu debugování programů pro ATMEGA 328 P-PU?

Kód: [Vybrat]
; TCCR0 registers addresses
.equ tccr0a, 0x44
.equ tccr0b, 0x45
.equ tcnt0, 0x46
.equ ocr0a, 0x47
.equ ocr0b, 0x48
.equ tifr0, 0x35
.equ timsk0, 0x6E

.equ io_tccr0a, 0x24
.equ io_tccr0b, 0x25
.equ io_tcnt0, 0x26
.equ io_ocr0a, 0x27
.equ io_ocr0b, 0x28
.equ io_tifr0, 0x15

; PORT registers addresses
.equ pinb, 0x23
.equ io_pinb, 0x3
.equ ddrb, 0x24
.equ io_ddrb, 0x4
.equ portb, 0x25
.equ io_portb, 0x5

.equ pinc, 0x26
.equ io_pinc, 0x6
.equ ddrc, 0x27
.equ io_ddrc, 0x7
.equ portc, 0x28
.equ io_portc, 0x8

.equ pind, 0x29
.equ io_pind, 0x9
.equ ddrd, 0x2A
.equ io_ddrd, 0xA
.equ portd, 0x2B
.equ io_portd, 0xB

; SREG and STACK registers addresses
.equ sreg, 0x5F
.equ io_sreg, 0x3F

.equ sph, 0x5E
.equ io_sph, 0x3E
.equ spl, 0x5D
.equ io_spl, 0x3D

; Constants
.equ RAMEND, 0x8FF ; End of SRAM for ATMEGA328P
.equ MILIS_VALUE, 0x7C ; EDIT: FUCK THE TIME, TCNT0 HAS NO 128 PRESCALER, PRESCALER WILL BE 1024 JUST BECAUSE I WANT PREVIOUS COMMENT HAS NO MEANING NOW ---> ; Time in milisecond counted for 16MHz with 128 prescaler





.org 0 ; RESTART interupt vector
rjmp INITIALIZATION ; Go to the start of the program

.org 0x1C ; TOV0 interupt vector
rjmp DELAY ; Create visible delay from counter interval


.org 0x34 ; Start the program right behind interupt vector table
INITIALIZATION:
ldi r16, hi8(RAMEND) ; High 8 bit value for SPH
out io_sph, r16 ; Store SPH value to SRAM
ldi r16, lo8(RAMEND) ; Low 8 bit value for SPL
out io_spl, r16 ; Store SPL value to SRAM
clr r16 ; R16 = 0
out io_sreg, r16 ; SREG = 0

ldi r16, 0xF0 ; Only high nibble is set
out io_ddrc, r16 ; High nibble in PORTB is set as output because of possibility to check possible error with ease
ldi r16, 0xF0 ; Byte for Output
out io_ddrd, r16 ; Pin OC0A and other pins (PORTD.7-4 included) is set as output
rcall TOOGLE_LED ; Inicialization LED and delay register(s) to the start condition

TCNT_INIT: ; TCNT0 Initialization - not used label
clr r16 ; Prepare value for counter stop, no FOC, third mode bit WGM2 is 0
out io_tccr0b, r16 ; Stop counter
out io_tcnt0, r16 ; Counting register = 0
ldi r16, 0x42 ; Set OC0A to toogle and CTC mode for TCNT0
out io_tccr0a, r16 ; Set control register a for timer 0
ldi r16, 0x1 ; Interupt on TOV0
sts timsk0, r16 ; Enable overflow interupt
ldi r16, MILIS_VALUE ; Count number for 125 count cycles
out io_ocr0a, r16 ; Set top value for counter 0
sei ; Enable ingerupts globaly
out io_tccr0b, 0x05 ; Set divisor to 1024, counter is running now!

MAIN_LOOP:
rjmp MAIN_LOOP ; Infinite loop because of getting interupt from TCNT0

DELAY: ; TOV0 interupt subroutine
in r20, io_sreg
clr r21
out io_sreg, R21
inc r18
cpi r18, 100
brlt END_DELAY
out io_sreg, R21
clr r18
inc r17
cpi r17, 100
brlt END_DELAY
out io_sreg, R21
clr r17
inc r19
cpi r19, 1
brlt END_DELAY
rcall TOOGLE_LED
out io_sreg, r20
END_DELAY:
reti

TOOGLE_LED:
ldi r17, 0x8 ; The highest bit of the lowest nibble is set for xor mask
in r16, io_portc ; Get actual value of port B
eor r16, r17 ; Toogle the highest pin of port B
out io_portc, r16 ; write changed value to the port B
clr r17 ; R17 = 0 <--- register is used for delay so it must be reseted
clr r18 ; R18 = 0 <--- register is used for delay so it must be reseted
clr r19 ; R19 = 0 <--- register is used for delay so it must be reseted
ret


Cmato

Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #1 kdy: 17. 09. 2017, 11:30:58 »
Nerozumiem preco asm a nie C, asm ma vyznam pri presnom casovani, pokial vyuzivas casovace tak jedine mozno v obsluhe prerusenia par riadkov...

Avr studio ma softwarovy simulator, nainstaluj, hned najdes pricinu. Pokial chces realne vidiet hodnoty registrov, stavy pinov v mcu potrebujes avr dragon, stk500 .... Je viacero programatorov s podporou ladenia

Just_assembly_arduino

Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #2 kdy: 17. 09. 2017, 11:45:18 »
Nerozumiem preco asm a nie C, asm ma vyznam pri presnom casovani, pokial vyuzivas casovace tak jedine mozno v obsluhe prerusenia par riadkov...

Avr studio ma softwarovy simulator, nainstaluj, hned najdes pricinu. Pokial chces realne vidiet hodnoty registrov, stavy pinov v mcu potrebujes avr dragon, stk500 .... Je viacero programatorov s podporou ladenia

Díky za info, ale AVR studio je podle všeho pouze pro Windows, zatímco já pracuji na linuxu. Pro AVR je tady k dispozici nějaká sada toolů, ale nevšiml jsem si něčeho, co by se podobalo softwarovému simulátoru. Jinak v asm programuji, protože se jej chci naučit a dobře mu rozumět. Je mi jasné, že to má sva úskalí, stejně jako výhody, ostatně plánuji psát programy také v C.

JardaP .

  • *****
  • 11 064
    • Zobrazit profil
    • E-mail
Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #3 kdy: 17. 09. 2017, 12:10:02 »
... ale AVR studio je podle všeho pouze pro Windows, zatímco já pracuji na linuxu.

Zkousel jste, jestli nejede pod Wine?

Just_assembly_arduino

Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #4 kdy: 17. 09. 2017, 12:18:51 »
... ale AVR studio je podle všeho pouze pro Windows, zatímco já pracuji na linuxu.

Zkousel jste, jestli nejede pod Wine?

Zatím ne, protože jakkoliv se mi některé věci pod Wine rozchodit podařilo, bojím se trošku, aby to k mojim vlastním chybám nepřidalo další vrstvu problémů, ale už to stahuji a jakmile to bude hotové, zkusím to rozjet a dám vědět.


Just_assembly_arduino

Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #5 kdy: 17. 09. 2017, 12:43:59 »
... ale AVR studio je podle všeho pouze pro Windows, zatímco já pracuji na linuxu.

Zkousel jste, jestli nejede pod Wine?

Vypadá, že pod Wine se to jednoduchým způsobem nerozjede. Určitě můžu poslat, co se vypsalo na terminálu, ale primárně mě zajímá chyba v programu. Pokud byste někdo věděli, bylo by to super.

JardaP .

  • *****
  • 11 064
    • Zobrazit profil
    • E-mail
Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #6 kdy: 17. 09. 2017, 13:18:13 »
Asi by sla starsi verze, jestli se da nekestahnout: https://appdb.winehq.org/objectManager.php?sClass=application&iId=402

avr


Just_assembly_arduino

Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #8 kdy: 17. 09. 2017, 23:15:51 »
Tohle jsem zrovna nenašel, ale obecně mě v tomhle internet zatím zklamal. Vypadá, že vzniklo pár projektů, ale stránky, na které bylo odkazováno, už neexistovaly. Navíc jsem tak trochu vzdal hledání na internetu s tím, že to zvládnu sám poté, co mi ani do teď nikdo neodpověděl jako čerstvému uživateli ani na stack overflow  :D a při vyhledávání nějakého emulátoru jsem strávil asi hodinu https://stackoverflow.com/questions/46263623/creating-simple-tcnt0-program-atmega-328-p-pu

Ale při procházení různých příkladů a hlavičkových souborů pro programování avr v C jsem přišel na jednu možnou chybu. Program pro přerušení zarovnávám podle adres uvedených v datasheetu. Tam se pro TCNT0 uvádí následující.

15      0x001C      TIMER0      COMPA      Timer/Counter0 Compare Match A
16      0x001E      TIMER0      COMPB      Timer/Counter0 Compare Match B
17      0x0020      TIMER0      OVF           Timer/Counter0 Overflow

 Jenže někde na jeho konci je napsané, že paměť programu je adresovaná po šestnácti bitech, takže adresy přerušení musím pro potřeby zápisu násobit dvěma, což mi předběžně potvrzují i hlavičkové soubory avr/io.h a z toho plynoucí avr/iom328p.h. Jenže tuhle chybu jsem opravil a nevypadá to, že by se něco viditelně změnilo k lepšímu. Takže tam bude ještě nějaká další chyba/chyby o kterých nevím nebo je moje úvaha poněkud špatně. Původně jsem si to schovával, až se mi to podaří najít všechno, ale když už tady píšu...
Osobně si myslím, že bude zakopaný pes někde v těch přerušeních. Ale globálně vypadá, že ho mám povolené a zkouším různě přerušení jak od OCR0A, tak TOV0, takže už fakt nevím, kde bude chyba. Ale doufejme, že na to přijdu v nějaké rozumné době. Znalost správné práce přerušení a skoků je tak trošku základ.

Just_assembly_arduino

Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #9 kdy: 17. 09. 2017, 23:18:23 »
Jo a na ten program určitě mrknu, díky za info. Jen mě trošku pohltila práce, tak jsem se trošku rozepsal...

Just_assembly_arduino

Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #10 kdy: 18. 09. 2017, 23:55:59 »
LIDI, TAK JSEM KONEČNĚ NAŠEL TU POSLEDNÍ CHYBU!!!

V kódu jsem spouštěl čítač (cca okolo řádku 24) poněkud špatným příkazem:

   
Kód: [Vybrat]
out io_tccr0b, 0x05 ; Set divisor to 1024, counter is running now!
Místo konstanty tím do tccr0b načítám hodnotu registru 0x05, což bude nejspíše 0, takže čítač nikdy neběžel.  ;D

OC2A pravděpodobně svítil proto, že byl nastaven na toogle.

Po náležité opravě vše funguje, jak má.

   
Kód: [Vybrat]
                 ldi r16, 0x05
         out io_tccr0b, r16 ; Set divisor to 1024, counter is running now! <<<-------THERE WAS ANOTHER MISTAKE!!!!

DÍKY VŠEM, KDO SE MI ALESPOŇ POKUSILI POMOCT !!!

Just_assembly_arduino

Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #11 kdy: 19. 09. 2017, 00:03:10 »

Btw: Tahle úvaha se nakonec ukázala jako správná, takže v tomhle jsem měl od začátku chybu taky.


Ale při procházení různých příkladů a hlavičkových souborů pro programování avr v C jsem přišel na jednu možnou chybu. Program pro přerušení zarovnávám podle adres uvedených v datasheetu. Tam se pro TCNT0 uvádí následující.

15      0x001C      TIMER0      COMPA      Timer/Counter0 Compare Match A
16      0x001E      TIMER0      COMPB      Timer/Counter0 Compare Match B
17      0x0020      TIMER0      OVF           Timer/Counter0 Overflow

 Jenže někde na jeho konci je napsané, že paměť programu je adresovaná po šestnácti bitech, takže adresy přerušení musím pro potřeby zápisu násobit dvěma, což mi předběžně potvrzují i hlavičkové soubory avr/io.h a z toho plynoucí avr/iom328p.h. Jenže tuhle chybu jsem opravil a nevypadá to, že by se něco viditelně změnilo k lepšímu. Takže tam bude ještě nějaká další chyba/chyby o kterých nevím nebo je moje úvaha poněkud špatně. Původně jsem si to schovával, až se mi to podaří najít všechno, ale když už tady píšu...

Dan

Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #12 kdy: 19. 09. 2017, 17:12:06 »
mikrokontrolery a linux to je velký problém, ne všechno funguje pod wine úplně dobře a hledání chyb kdy nevím jestli chyba v zapojení hw, chybě v mém programu nebo protože něco pod wine funguje blbě. Asembler na AVR je fajn ale hrát si s tím bez debugeru/simulátoru je na houby. program v C si aspoň můžeš ladit výpisy na sériový port

RDa

  • *****
  • 2 467
    • Zobrazit profil
    • E-mail
Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #13 kdy: 19. 09. 2017, 18:25:43 »
Programuji na ATmega pres 10 let v Linuxu - doted cca 256K LoC (moje .c a .h), je to vse bez debuggeru nebo jinych nastroju, jenom gcc-avr + avrdude. V Gentoo se ten prekladac instaluje velice jednoduse skrze crossdev.

Jediny extra tool co jsem si dopsal (v PHP) je pro statickou analyzu kodu (vezme to asm dump a spocita kolik pameti pouzivaji funkce na stacku a spocita nejhlubsi zanoreni). Tohle jsem potreboval kdyz zacal malloc() kolidovat se stackem kvuli prilisnemu vnoreni funkci. Po analyze se nastavi heap na patricnou velikost a malloc se tim omezi.
« Poslední změna: 19. 09. 2017, 18:30:09 od RDa »

Just_assembly_arduino

Re:Mám problém zprovoznit TCNT0 dle svých představ
« Odpověď #14 kdy: 20. 09. 2017, 15:14:41 »
Jen tady ještě přidám opravený kód, aby to někomu, kdo to najde později, taky k něčemu bylo.

Kód: [Vybrat]


; TCCR0 registers addresses
.equ tccr0a, 0x44
.equ tccr0b, 0x45
.equ tcnt0, 0x46
.equ ocr0a, 0x47
.equ ocr0b, 0x48
.equ tifr0, 0x35
.equ timsk0, 0x6E

.equ io_tccr0a, 0x24
.equ io_tccr0b, 0x25
.equ io_tcnt0, 0x26
.equ io_ocr0a, 0x27
.equ io_ocr0b, 0x28
.equ io_tifr0, 0x15

; PORT registers addresses
.equ pinb, 0x23
.equ io_pinb, 0x3
.equ ddrb, 0x24
.equ io_ddrb, 0x4
.equ portb, 0x25
.equ io_portb, 0x5

.equ pinc, 0x26
.equ io_pinc, 0x6
.equ ddrc, 0x27
.equ io_ddrc, 0x7
.equ portc, 0x28
.equ io_portc, 0x8

.equ pind, 0x29
.equ io_pind, 0x9
.equ ddrd, 0x2A
.equ io_ddrd, 0xA
.equ portd, 0x2B
.equ io_portd, 0xB

; SREG and STACK registers addresses
.equ sreg, 0x5F
.equ io_sreg, 0x3F

.equ sph, 0x5E
.equ io_sph, 0x3E
.equ spl, 0x5D
.equ io_spl, 0x3D

.equ mcucr, 0x55
.equ io_mcucr, 0x35

; Constants
.equ RAMEND, 0x8FF ; End of SRAM for ATMEGA328P
.equ MILIS_VALUE, 0x7C ; EDIT: FUCK THE TIME, TCNT0 HAS NO 128 PRESCALER, PRESCALER WILL BE 1024 JUST BECAUSE I WANT PREVIOUS COMMENT HAS NO MEANING NOW ---> ; Time in milisecond counted for 16MHz with 128 prescaler





.org 0 ; RESTART interupt vector
jmp INITIALIZATION ; Go to the start of the program

.org 0x38 ; OCF0A interupt vector <--- IT LOOKS, THAT ADDRESSES FROM DATASHEET MUST BE DOUBLED BECAUSE OF CALL INSTRUCTION! SEE /usr/lib/avr/include/avr/iom328p.h ,io.h AND OTHER INCLUDE FILES! THIS INFORMATION MUST BE VERIFIED!
jmp DELAY ; Create visible delay from counter interval


.org 0x68 ; Start the program right behind interupt vector table
INITIALIZATION:
ldi r16, hi8(RAMEND) ; High 8 bit value for SPH
out io_sph, r16 ; Store SPH value to SRAM
ldi r16, lo8(RAMEND) ; Low 8 bit value for SPL
out io_spl, r16 ; Store SPL value to SRAM
clr r16 ; R16 = 0
out io_sreg, r16 ; SREG = 0
out io_mcucr, r16 ; MCUCR = 0

ldi r16, 0xFF ; Only high nibble is set
out io_ddrc, r16 ; High nibble in PORTB is set as output because of possibility to check possible error with ease
ldi r16, 0xF0 ; Byte for Output
out io_ddrd, r16 ; Pin OC0A and other pins (PORTD.7-4 included) is set as output
rcall DELAY_INIT ; Inicialization of DELAY subroutine

TCNT_INIT: ; TCNT0 Initialization - not used label
clr r16 ; Prepare value for counter stop, no FOC, third mode bit WGM2 is 0
out io_tccr0b, r16 ; Stop counter
out io_tcnt0, r16 ; Counting register = 0
ldi r16, 0x42 ; Set OC0A to toogle and CTC mode for TCNT0
out io_tccr0a, r16 ; Set control register a for timer 0
ldi r16, 0x2 ; Interupt on OCIE0A
sts timsk0, r16 ; Enable overflow created by OCR0A interupt
ldi r16, MILIS_VALUE ; Count number for 125 count cycles
out io_ocr0a, r16 ; Set top value for counter 0
sei ; Enable global interupts
ldi r16, 0x05
out io_tccr0b, r16 ; Set divisor to 1024, counter is running now! <<<-------THERE WAS ANOTHER MISTAKE!!!!
; in r16, io_sreg ; TEST ONLY !!!! SREG test, control of enabling interupts
; out io_portd, r16 ; TEST ONLY !!!! SREG test, control of enabling interupts
; sbi io_portc, 0 ; TEST ONLY !!!! Test of signal that DELAY subroutine was activated.

MAIN_LOOP:
rjmp MAIN_LOOP ; Infinite loop because of getting interupt from TCNT0

DELAY: ; TOV0 interupt subroutine
in r20, io_sreg
sbi io_portc, 0 ; Tell me, that this interupt was working one times at minimum!
clr r21
out io_sreg, R21
inc r18
cpi r18, 100
brlt END_DELAY
out io_sreg, R21
clr r18
inc r17
cpi r17, 1
brlt END_DELAY
out io_sreg, R21
clr r17
inc r19
cpi r19, 1
brlt END_DELAY
rcall TOOGLE_LED
out io_sreg, r20
END_DELAY:
reti

TOOGLE_LED:
ldi r17, 0x8 ; The highest bit of the lowest nibble is set for xor mask
in r16, io_portc ; Get actual value of port B
eor r16, r17 ; Toogle the highest pin of port B
out io_portc, r16 ; write changed value to the port B
DELAY_INIT:
clr r17 ; R17 = 0 <--- register is used for delay so it must be reseted
clr r18 ; R18 = 0 <--- register is used for delay so it must be reseted
clr r19 ; R19 = 0 <--- register is used for delay so it must be reseted
ret