lentejanumerica/web/avr-asm.html

343 lines
9.2 KiB
HTML

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml' lang='es-MX,en'>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
<meta content='initial-scale=1.0, maximum-scale=1.0, user-scalable=yes' name='viewport'/>
<link rel='stylesheet' href='./static/estilo.css'>
<title>🥭 &mdash; avr-asm</title>
</head>
<body>
<header>
<p><a href='./index.html'>{🥭}</a></p>
<h1>avr-asm</h1>
</header>
<nav><ul><li><a href='#attiny85'>attiny85</a></li>
<li><a href='#programas'>programas</a></li>
</ul></nav>
<main><section><p>
explorando programación de microcontroladores avr a través de asm, en attiny85. <a href='./s-camino.html'>{s-camino}</a>
</p>
</section><section>
<h1 id='attiny85'>attiny85</h1>
<h2 id='diagrama de pines'>diagrama de pines</h2>
<pre>
┌──────┐
PB5 │1 8│ VCC
PB3 │2 7│ PB2
PB4 │3 6│ PB1
GND │4 5│ PB0
└──────┘
</pre>
<p>
además, cada pin es:
</p>
<ul>
<li>1: PB5 / PCINT5 / ~RESET / ADC0 / dW</li>
<li>2: PB3 / PCINT3 / XTAL1 / CLKI / ~OC1B / ADC3</li>
<li>3: PB4 / PCINT4 / XTAL2 / CLKO / OC1B / ADC2</li>
<li>5: PB0 / MOSI / DI / SDA / AIN0 / OC0A / ~OC1A / AREF / PCINT0</li>
<li>6: PB1 / MISO / DO / AIN1 / OC0B / OC1A / PCINT1</li>
<li>7: PB2 / SCK / USCK / SCL / ADC1 / T0 / INT0 / PCINT2</li>
</ul>
<p>
para flashear nos interesan los pines desde el punto de vista de SPI:
</p>
<pre>
┌──────┐
~RESET │1 8│ VCC
│2 7│ SCK
│3 6│ MISO
GND │4 5│ MOSI
└──────┘
</pre>
<h2 id='programador'>programador</h2>
<p><a href='https://www.fischl.de/usbasp/' rel=external target=_blank>USBasp - USB programmer for Atmel AVR controllers (web)</a></p>
<h2 id='makefile'>makefile</h2>
<p>
para ensamblar y flashear
</p>
<pre>
# 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)
</pre>
</section><section>
<h1 id='programas'>programas</h1>
<p>
software experimental, compartido como referencia y sin garantía de ningún tipo :)
</p>
<h2 id='test.S'>test.S</h2>
<p>
enciende un el pin PB0 — conecta un led
</p>
<pre>
; test.S
; enciende un pin
#include &lt;avr/io.h&gt;
.org 0x0000
ldi r17, (1&lt;&lt;DDB0) ; configura al PB0 como salida
sts DDRB, r17
ldi r16, (1&lt;&lt;PB0) ; enciende el bit correspondiente al PB0
sts PORTB, r16 ; actualiza el puerto
sleep ; duerme por siempre (?)
</pre>
<h2 id='blink.S'>blink.S</h2>
<p>
parpadea el pin PB0 usando el timer/counter0 — conecta un led
</p>
<pre>
; 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 &lt;avr/io.h&gt;
; ***********************
; vectores de interrupts:
; ***********************
; Reset
.org 0x0000
rjmp main
; ***********************
; Main
; ***********************
.org 0x0010
main:
; pin PB0 (OC0A) como pin de salida
ldi r16, (1&lt;&lt;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&lt;&lt;COM0A1) | (1&lt;&lt;COM0A0) | (1&lt;&lt;WGM01) | (0&lt;&lt;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&lt;&lt;WGM02) | (1&lt;&lt;CS02) | (0&lt;&lt;CS01) | (1&lt;&lt;CS00)
sts TCCR0B, r16
; el TOP es el valor en OCR0A
ldi r16, 0x80
sts OCR0A, r16
loop:
sleep
rjmp loop
</pre>
<h2 id='buzz.S'>buzz.S</h2>
<p>
zumba el pin PB0 — conecta un buzzer
</p>
<pre>
; 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 &lt;avr/io.h&gt;
; ***********************
; vectores de interrupts:
; ***********************
; Reset
.org 0x0000
rjmp main
; ***********************
; Main
; ***********************
.org 0x0010
main:
; pin PB0 (OC0A) como pin de salida
ldi r16, (1&lt;&lt;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&lt;&lt;COM0A1) | (1&lt;&lt;COM0A0) | (1&lt;&lt;WGM01) | (0&lt;&lt;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&lt;&lt;WGM02) | (1&lt;&lt;CS02) | (0&lt;&lt;CS01) | (0&lt;&lt;CS00)
sts TCCR0B, r16
; el TOP es el valor en OCR0A
ldi r16, 0x02
sts OCR0A, r16
loop:
sleep
rjmp loop
</pre>
<h2 id='alarm.S'>alarm.S</h2>
<p>
zumbido intermitente en el pin PB0 — conecta un buzzer
</p>
<pre>
; 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 &lt;avr/io.h&gt;
; ***********************
; 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&lt;&lt;DDB0) ; pin de salida
sts DDRB, r16
; valores de TCCR0A para encender o apagar sonido
ldi r20, (0&lt;&lt;COM0A1) | (0&lt;&lt;COM0A0) | (1&lt;&lt;WGM01) | (0&lt;&lt;WGM00)
ldi r21, (0&lt;&lt;COM0A1) | (1&lt;&lt;COM0A0) | (1&lt;&lt;WGM01) | (0&lt;&lt;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&lt;&lt;WGM02) | (0&lt;&lt;CS02) | (1&lt;&lt;CS01) | (1&lt;&lt;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&lt;&lt;CS13) | (0&lt;&lt;CS12) | (1&lt;&lt;CS11) | (0&lt;&lt;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&lt;&lt;TOIE1) | (1&lt;&lt;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
</pre>
<h2 id='llega(n) aquí'>llega(n) aquí</h2>
<p><a href='./s-camino.html'>{s-camino}</a></p>
</section>
</main>
<footer>
<p><a href='./index.html'>{🥭}</a></p>
<p>página actualizada en:
<time datetime='2021-05-20'>sejmana-1660, día 1</time>
(12021-05-20)
</p>
<a href='https://endefensadelsl.org/ppl_es.html' rel=external target=_blank>ppl: licencia de producción de pares</a></p>
</footer>
</body>
</html>