You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
339 lines
8.0 KiB
339 lines
8.0 KiB
# avr-asm |
|
lang=es |
|
explorando programación de microcontroladores avr a través de asm, en attiny85. {s-camino} |
|
|
|
# herramientas |
|
|
|
en debian-based: |
|
|
|
``` |
|
sudo apt install gcc-avr avrdude avr-libc |
|
``` |
|
|
|
# attiny85 |
|
|
|
=> https://ww1.microchip.com/downloads/en/devicedoc/atmel-2586-avr-8-bit-microcontroller-attiny25-attiny45-attiny85_datasheet.pdf datasheet |
|
|
|
## 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) |
|
|
|
### udev rule |
|
|
|
possible udev rule for e.g. /etc/udev/rules.d/80-usbasp.rules, por si las dudas. en principio no se debería necesitar. |
|
|
|
``` |
|
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="16c0", |
|
ATTRS{idProduct}=="05dc", OWNER="user", GROUP="dialout", |
|
MODE="0777" |
|
``` |
|
|
|
## 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 |
|
```
|
|
|