lentejanumerica/src/avr-asm.gmo

325 lines
7.6 KiB
Plaintext

# avr-asm
explorando programación de microcontroladores avr a través de asm, en attiny85. {s-camino}
# attiny85
## diagrama de pines
```diagrama de pines
┌──────┐
PB5 │1 8│ VCC
PB3 │2 7│ PB2
PB4 │3 6│ PB1
GND │4 5│ PB0
└──────┘
```
además, cada pin es:
* 1: PB5 / PCINT5 / ~RESET / ADC0 / dW
* 2: PB3 / PCINT3 / XTAL1 / CLKI / ~OC1B / ADC3
* 3: PB4 / PCINT4 / XTAL2 / CLKO / OC1B / ADC2
* 5: PB0 / MOSI / DI / SDA / AIN0 / OC0A / ~OC1A / AREF / PCINT0
* 6: PB1 / MISO / DO / AIN1 / OC0B / OC1A / PCINT1
* 7: PB2 / SCK / USCK / SCL / ADC1 / T0 / INT0 / PCINT2
para flashear nos interesan los pines desde el punto de vista de SPI:
```pines spi
┌──────┐
~RESET │1 8│ VCC
│2 7│ SCK
│3 6│ MISO
GND │4 5│ MOSI
└──────┘
```
## programador
=> https://www.fischl.de/usbasp/ USBasp - USB programmer for Atmel AVR controllers (web)
## makefile
para ensamblar y flashear
```makefile
# Makefile
# nombre del programa sin .S :
PROG = test
# config hardware
BOARD = attiny85
PROGRAMMER = usbasp
# ensambla programa a .hex
hex:
avr-gcc -Os -DF_CPU=8000000 -mmcu=$(BOARD) -c $(PROG).S
avr-ld -o $(PROG).elf $(PROG).o
avr-objcopy $(PROG).elf -O ihex $(PROG).hex
rm $(PROG).o $(PROG).elf
# flashea
flash:
avrdude -c $(PROGRAMMER) -p $(BOARD) -U flash:w:$(PROG).hex:i
# lee la memoria flash a read.hex
read:
avrdude -c $(PROGRAMMER) -p $(BOARD) -U flash:r:read.hex:i
# prueba conexión con programador y micro
test:
avrdude -c $(PROGRAMMER) -p $(BOARD)
```
# programas
software experimental, compartido como referencia y sin garantía de ningún tipo :)
## test.S
enciende un el pin PB0 — conecta un led
```
; test.S
; enciende un pin
#include <avr/io.h>
.org 0x0000
ldi r17, (1<<DDB0) ; configura al PB0 como salida
sts DDRB, r17
ldi r16, (1<<PB0) ; enciende el bit correspondiente al PB0
sts PORTB, r16 ; actualiza el puerto
sleep ; duerme por siempre (?)
```
## blink.S
parpadea el pin PB0 usando el timer/counter0 — conecta un led
```
; blink.S
; parpadea el pin PB0 (OC0A)!
; r16 y r17 se usan como registros auxiliares
; el programa usa el timer/counter 0 con:
; * waveform generation mode (WGM0): 2, que es CTC (clear timer on compare match)
; * compare match output A mode (COM0A): 1, que es toggle en compare match
; * clock select (CS0): 5, que utiliza el reloj i/o dividido entre 1024
; notas sobre el reloj:
; por default el attiny85 va a 8MHz, y el reloj i/o va a 1MHz
; 1MHz/1024 ~= 967 Hz
#include <avr/io.h>
; ***********************
; vectores de interrupts:
; ***********************
; Reset
.org 0x0000
rjmp main
; ***********************
; Main
; ***********************
.org 0x0010
main:
; pin PB0 (OC0A) como pin de salida
ldi r16, (1<<DDB0) ; pin de salida
sts DDRB, r16
; togglea OC0A en Compare match (1 en COM0A[1:0])
; y usa modo Clear Timer on Compare Match (2 en WGM0[2:0])
ldi r16, (0<<COM0A1) | (1<<COM0A0) | (1<<WGM01) | (0<<WGM00)
sts TCCR0A, r16
; completa el modo WGM (waveform generaton mode, bit 2)
; establece el tipo de reloj: 0b101 en CS0 es clk/1024
ldi r16, (0<<WGM02) | (1<<CS02) | (0<<CS01) | (1<<CS00)
sts TCCR0B, r16
; el TOP es el valor en OCR0A
ldi r16, 0x80
sts OCR0A, r16
loop:
sleep
rjmp loop
```
## buzz.S
zumba el pin PB0 — conecta un buzzer
```
; buzz.S
; haz zumbar el pin PB0 (OC0A)!
; el código es igual a blink.S, pero con diferentes frecuencias
; r16 y r17 se usan como registros auxiliares
; el programa usa el timer/counter 0 con:
; * waveform generation mode (WGM0): 2, que es CTC (clear timer on compare match)
; * compare match output A mode (COM0A): 1, que es toggle en compare match
; * clock select (CS0): 4, que utiliza el reloj i/o dividido entre 256
; notas sobre el reloj:
; por default el attiny85 va a 8MHz, y el reloj i/o va a 1MHz
; 1MHz/256 ~= 3906 Hz (/2 para el periodo completo ~=1953Hz)
#include <avr/io.h>
; ***********************
; vectores de interrupts:
; ***********************
; Reset
.org 0x0000
rjmp main
; ***********************
; Main
; ***********************
.org 0x0010
main:
; pin PB0 (OC0A) como pin de salida
ldi r16, (1<<DDB0) ; pin de salida
sts DDRB, r16
; togglea OC0A en Compare match (1 en COM0A[1:0])
; y usa modo Clear Timer on Compare Match (2 en WGM0[2:0])
ldi r16, (0<<COM0A1) | (1<<COM0A0) | (1<<WGM01) | (0<<WGM00)
sts TCCR0A, r16
; completa el modo WGM (waveform generaton mode, bit 2)
; establece el tipo de reloj: 0b100 en CS0 es clk/256
ldi r16, (0<<WGM02) | (1<<CS02) | (0<<CS01) | (0<<CS00)
sts TCCR0B, r16
; el TOP es el valor en OCR0A
ldi r16, 0x02
sts OCR0A, r16
loop:
sleep
rjmp loop
```
## alarm.S
zumbido intermitente en el pin PB0 — conecta un buzzer
```
; alarm.S
; zumbido intermitente en el pin PB0 (OC0A)!
; r16 y r17 se usan como registros auxiliares
; r20 tiene el valor de TCCR0A para apagar sonido
; r21 tiene el valor de TCCR0A para encenderlo
; el programa usa el timer/counter 0 con:
; * waveform generation mode (WGM0): 2, que es CTC (clear timer on compare match)
; * compare match output A mode (COM0A): 1, que es toggle en compare match
; * clock select (CS0): 3, que utiliza el reloj i/o dividido entre 64
; y el timer/counter 1 con:
; * clock select (CS1): 0b1010, que es clk/512
; * interrupciones de overflow y de compare match A:
; - en compare match A el zumbido se apaga
; - en overflow el zumbido inicia
; notas sobre el reloj:
; por default el attiny85 va a 8MHz, y el reloj i/o va a 1MHz
; 1MHz/256 ~= 3906 Hz (/2 para el periodo completo ~=1953Hz)
#include <avr/io.h>
; ***********************
; vectores de interrupts:
; ***********************
; Reset
.org 0x0000
rjmp main
; dirección 0x0003 * 2
.org 0x0006
rjmp timer1compareA_isr
; dirección 0x0004 * 2
.org 0x0008
rjmp timer1overflow_isr
; ***********************
; Main
; ***********************
.org 0x001E
main:
;----------------------------------
; configuración general
;----------------------------------
; habilita interrupciones
sei
; pin PB0 (OC0A) como pin de salida
ldi r16, (1<<DDB0) ; pin de salida
sts DDRB, r16
; valores de TCCR0A para encender o apagar sonido
ldi r20, (0<<COM0A1) | (0<<COM0A0) | (1<<WGM01) | (0<<WGM00)
ldi r21, (0<<COM0A1) | (1<<COM0A0) | (1<<WGM01) | (0<<WGM00)
;----------------------------------
; configuración TIMER0 para buzzer
;----------------------------------
; togglea OC0A en Compare match (1 en COM0A[1:0])
; y usa modo Clear Timer on Compare Match (2 en WGM0[2:0])
sts TCCR0A, r21
; completa el modo WGM (waveform generaton mode, bit 2)
; establece el tipo de reloj: 0b011 en CS0 es clk/64
ldi r16, (0<<WGM02) | (0<<CS02) | (1<<CS01) | (1<<CS00)
sts TCCR0B, r16
; el TOP es el valor en OCR0A
; más pequeño es más agudo
ldi r16, 0x06
sts OCR0A, r16
;----------------------------------
; configuración TIMER1 para alternar entre sonido on/off
;----------------------------------
; CS1 en 0b1010 es CK/512
ldi r16, (1<<CS13) | (0<<CS12) | (1<<CS11) | (0<<CS10)
sts TCCR1, r16
; establece el valor A al que cuenta el timer1 antes de apagar sonido
; menor valor, menor tiempo de sonido (duty cycle)
ldi r16, 0x30
sts OCR1A, r16
; set Timer overflow interrupt enable 1
; y timer output compare A interrupt enable 1
ldi r16, (1<<TOIE1) | (1<<OCIE1A)
sts TIMSK, r16
loop:
sleep
rjmp loop
timer1compareA_isr:
; apaga la salida
sts TCCR0A, r20
reti
timer1overflow_isr:
; enciende la salida
sts TCCR0A, r21
; regresa de la interrupción
reti
```
## llega(n) aquí
=> ./s-camino.gmi {s-camino}