From 773b061d16e9be2c9ee5f5a9d417108a9e972842 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Sun, 11 Dec 2005 22:02:43 +0000 Subject: [PATCH] =?utf8?q?Ejemplo=20completo=20del=20m=C3=B3dulo=20de=20le?= =?utf8?q?ds=20implementado=20en=20assembly=20y=20llamado=20desde=20un=20p?= =?utf8?q?rograma=20en=20C.=20Est=C3=A1=20bastante=20prolijo=20y=20complet?= =?utf8?q?o,=20e=20incluso=20incluye=20funciones=20para=20escribir=20en=20?= =?utf8?q?los=20leds=20y=20para=20hacer=20testeo.=20Lo=20=C3=BAnico=20que?= =?utf8?q?=20no=20hubo=20manera=20de=20hacer=20es=20configurar=20el=20vect?= =?utf8?q?or=20de=20interrupciones=20desde=20asm,=20porque=20se=20pisaba?= =?utf8?q?=20con=20el=20de=20C,=20as=C3=AD=20que=20lejo=20esa=20parte=20so?= =?utf8?q?lita=20al=20C=20(hay=20que=20incluir=20s=C3=B3lo=20la=20declarac?= =?utf8?q?i=C3=B3n=20del=20ISR).?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- pruebas/sdcc/leds_asm/Makefile | 22 +++- pruebas/sdcc/leds_asm/leds.asm | 199 ++++++++++++++++++++------------- pruebas/sdcc/leds_asm/leds.h | 45 ++++++++ pruebas/sdcc/leds_asm/leds.lnk | 4 +- pruebas/sdcc/leds_asm/main.c | 18 +++ 5 files changed, 202 insertions(+), 86 deletions(-) create mode 100644 pruebas/sdcc/leds_asm/leds.h create mode 100644 pruebas/sdcc/leds_asm/main.c diff --git a/pruebas/sdcc/leds_asm/Makefile b/pruebas/sdcc/leds_asm/Makefile index 1d4ec5c..6b43a5d 100644 --- a/pruebas/sdcc/leds_asm/Makefile +++ b/pruebas/sdcc/leds_asm/Makefile @@ -1,14 +1,24 @@ -all: - @asx8051 -plosgff leds.asm - @aslink -nf leds.lnk - @packihx leds.ihx > leds.hex +all: leds.hex + +leds.rel: leds.asm + asx8051 -plosgff leds.asm + +main.asm: main.c leds.h + sdcc -c main.c + +main.rel: main.asm + asx8051 -plosgff main.asm + +leds.hex: main.rel leds.rel leds.lnk + aslink -nf leds.lnk + packihx main.ihx > leds.hex cleantmp: - @rm -f *.sym *.rel *.map *.ihx *.lst *.mem *.rst + @rm -vf *.sym *.rel *.map *.ihx *.lst *.mem *.rst main.asm clean: cleantmp - @rm -f *.hex + @rm -vf *.hex .PHONY: clean cleantmp diff --git a/pruebas/sdcc/leds_asm/leds.asm b/pruebas/sdcc/leds_asm/leds.asm index 5fd5314..bc729f1 100644 --- a/pruebas/sdcc/leds_asm/leds.asm +++ b/pruebas/sdcc/leds_asm/leds.asm @@ -4,25 +4,30 @@ .module leds .optsdcc -mmcs51 --model-small -; Variables globales -.globl _leds_matrix -.globl _leds_matrix_len -.globl _leds_delay - -; Funciones globales -.globl _leds_init -.globl _leds_write -.globl _leds_write0 -.globl _leds_write1 -.globl _leds_delay_update +; Constantes "públicas" +LEDS_MAX_COLS = 32 ; Cantidad máxima de columnas + +; Variables públicas +.globl _leds_matrix_len ; unsigned char +.globl _leds_matrix ; unsigned int[LEDS_MAX_COLS] +.globl _leds_delay ; unsigned char + +; Funciones públicas +.globl _leds_init ; void leds_init(); +.globl _leds_test ; void leds_test(); +.globl _leds_write ; void leds_write(unsigned int); +.globl _leds_write_low ; void leds_write_low(unsigned char); +.globl _leds_write_high ; void leds_write_high(unsigned char); +.globl _leds_delay_update ; void leds_delay_update(); +.globl _leds_timer2_isr ; void leds_timer2_isr() interrupt 5; + ; Constantes ; UN CICLO DE MAQUINA SON 1.6666 useg (clock 8MHz) -INTERVAL = 66 ; 0.1ms (por el clock de 8MHz) -LEDS0 = 0x0080 -LEDS1 = 0x00c0 -MAX_COLS = 64 -DELAY_BASE = 28 +INTERVAL = 33 ; 0.05ms (por el clock de 8MHz) +LEDS_HIGH = 0x0080 +LEDS_LOW = 0x00c0 +DELAY_BASE = 28 ; 16 columnas anda bien con 28 - (len / 2) == 20 ; Área de bancos de registros .area REG_BANK_0 (REL,OVR,DATA) @@ -46,23 +51,18 @@ _leds_delay:: delay: .ds 1 curr_col: -__stack: ; XXX - .ds 1 ; Variables en memoria RAM extendida indirecta (8052) .area ISEG (DATA) _leds_matrix:: - .ds MAX_COLS * 2 ; 2 bytes por columna + .ds LEDS_MAX_COLS * 2 ; 2 bytes por columna ; Configuramos el vector de interrupciones para atender el timer2 -.area INTV (ABS, CODE) - .org 0x0000 ; XXX - ljmp _leds_init ; XXX - - .org 0x002b - clr tf2 ; limpio bit de interrupción porque para el timer2 no es autom. - ljmp timer2_isr +;.area INTV (ABS, CODE) +; .org 0x002b +; clr tf2 ; limpio bit de interrupción porque para el timer2 no es autom. +; ljmp timer2_isr ; Área de código del programa @@ -74,14 +74,13 @@ _leds_matrix:: ; ; C se encarga de hacer push y pop del dptr, a y psw si lo necesita. _leds_init:: - mov sp, #__stack ; XXX ; guardo registros que uso push ar0 push ar1 push ar2 ; leo de la ROM el tamaño por default - mov dptr, #MAT_D_LEN + mov dptr, #DEFAULT_MATRIX_LEN clr a movc a, @a+dptr mov _leds_matrix_len, a @@ -94,66 +93,94 @@ _leds_init:: mov delay, _leds_delay ; copio imagen por default de la ROM a la RAM - mov dptr, #MAT_D + mov dptr, #DEFAULT_MATRIX mov r0, #0 ; indice del "array" en la ROM mov r1, #_leds_matrix ; dirección de memoria de la RAM mov a, r0 -seguir$: +proximo$: movc a, @a+dptr ; leo de la ROM con el índice mov @r1, a ; escribo en el puntero a la RAM inc r1 ; incremento puntero inc r0 ; incremento índice mov a, r0 ; para comparar - cjne a, ar2, seguir$ ; veo si quedan más bytes por leer + cjne a, ar2, proximo$ ; veo si quedan más bytes por leer ; cargo los capture registers mov rcap2l, #<(-INTERVAL) ; low byte del intervalo mov rcap2h, #>(-INTERVAL) ; high byte del intervalo - mov ie, #0b10100000 ; habilito interrupcion timer 2 - ; bits de IE (interrupt enable) en 1: - ; IE.7 (Global enable/disable) - ; IE.5 (Enable timer 2 interrupt) - mov t2con, #0b00000100 ; setup timer 2 (auto-reload y start) + mov t2con, #0x00; setup del timer2 (auto-reload), no lo arrancamos + setb et2 ; habilito interrupcion timer2 (IE.5) mov curr_col, #0 ; inicializo el contador de columna en 0 ; Limpiamos stack - push ar2 - push ar1 - push ar0 + pop ar2 + pop ar1 + pop ar0 ret +; Hace una prueba simple de los leds +; Primitiva de C: +; void leds_test(); +; +; C se encarga de hacer push y pop del dptr, a y psw si lo necesita. +_leds_test:: + ; escribo patrones en los leds + mov dptr, #0xffff + acall _leds_write + acall sleep + + mov dptr, #0xaaaa + acall _leds_write + acall sleep + + mov dptr, #0x5555 + acall _leds_write + acall sleep + + mov dptr, #0x0000 + acall _leds_write + acall sleep + + ret + + ; Escribe en los leds. ; Primitiva de C: ; void leds_write(unsigned int); ; ; C se encarga de hacer push y pop del dptr, a y psw si lo necesita. _leds_write:: + ; guardamos en r0 la parte alta que imprimimos despues + push ar0 + mov r0, dph ; parte baja mov a, dpl ; de C me viene la parte baja del argumento en el dpl - mov dptr, #LEDS0 + mov dptr, #LEDS_LOW cpl a ; complemento para ver encendidos los "1" movx @dptr, a ; parte alta - mov a, dph ; de C me viene la parte alta del argumento en el dph - mov dptr, #LEDS1 + mov a, r0 ; de C me viene la parte alta del argumento en el dph + mov dptr, #LEDS_HIGH cpl a ; complemento para ver encendidos los "1" movx @dptr, a + ; devolvemos r0 + pop ar0 ret ; Escribe en los leds del primer latch. ; Primitiva de C: -; void leds_write0(unsigned char); +; void leds_write_low(unsigned char); ; ; C se encarga de hacer push y pop del dptr, a y psw si lo necesita. -_leds_write0:: +_leds_write_low:: ; parte baja mov a, dpl ; de C me viene el argumento en el dpl - mov dptr, #LEDS0 + mov dptr, #LEDS_LOW cpl a ; complemento para ver encendidos los "1" movx @dptr, a ret @@ -161,13 +188,13 @@ _leds_write0:: ; Escribe en los leds del segundo latch. ; Primitiva de C: -; void leds_write1(unsigned char); +; void leds_write_high(unsigned char); ; ; C se encarga de hacer push y pop del dptr, a y psw si lo necesita. -_leds_write1:: +_leds_write_high:: ; parte baja mov a, dpl ; de C me viene el argumento en el dpl - mov dptr, #LEDS1 + mov dptr, #LEDS_HIGH cpl a ; complemento para ver encendidos los "1" movx @dptr, a ret @@ -190,10 +217,13 @@ _leds_delay_update:: ret -; Manejador de la interrupción del timer2 -timer2_isr: +; Manejador de la interrupción del timer2 para el uso de los leds. +; Primitiva de C: +; void leds_timer2_isr() interrupt 5; +; +_leds_timer2_isr:: ; vemos si todavía hay que seguir esperando o si ya tenemos que leer - djnz delay, fin$ + djnz delay, 255$ ; comenzamos realmente a leer la próxima columna mov delay, _leds_delay @@ -207,13 +237,13 @@ timer2_isr: ; vemos si hay que empezar a leer por la 1ra columna de nuevo mov a, curr_col - cjne a, _leds_matrix_len, continua$ + cjne a, _leds_matrix_len, 1$ ; hay que empezar de nuevo mov curr_col, #0 mov a, curr_col ; dejamos en a la columna actual -continua$: +1$: ; multiplicamos por 2 porque hay 2 bytes por columna clr c rlc a @@ -223,16 +253,16 @@ continua$: add a, r0 ; le sumo al puntero el offset actual segun la columna mov r0, a - ; imprimo en LEDS1 + ; imprimo en LEDS_LOW mov a, @r0 ; leo el contenido de la matriz - mov dptr, #LEDS1 + mov dptr, #LEDS_LOW cpl a ; complemento para ver encendidos los "1" movx @dptr, a - ; imprimo en LEDS0 + ; imprimo en LEDS_HIGH inc r0 ; busco proximo byte de la columna mov a, @r0 ; leo el contenido de la matriz - mov dptr, #LEDS0 + mov dptr, #LEDS_HIGH cpl a ; complemento para ver encendidos los "1" movx @dptr, a @@ -248,16 +278,30 @@ continua$: pop psw pop acc -fin$: +255$: reti ; listo! seguimos viaje... +; Provoca un retardo corto. +; Usamos dpl y dph porque son "C-safe". +sleep: + mov a, #0xff +2$: + mov dph, #0xff +1$: + mov dpl, #0xff + djnz dpl, . + djnz dph, 1$ + djnz acc, 2$ + ret + + ; Matriz por default -MAT_D_LEN: +DEFAULT_MATRIX_LEN: .db 16 ;.db 32 -MAT_D: +DEFAULT_MATRIX: .dw 0b0000111111110000 ; columna 0 .dw 0b0011111111111100 ; columna 1 .dw 0b0111000000001110 ; columna 2 @@ -275,24 +319,23 @@ MAT_D: .dw 0b0011111111111100 ; columna 14 .dw 0b0000111111110000 ; columna 15 -; .dw 0b0000111111110000 ; columna 0 -; .dw 0b0011111111111100 ; columna 1 -; .dw 0b0111000000001110 ; columna 2 -; .dw 0b0110000000000110 ; columna 3 -; .dw 0b1100110000000011 ; columna 4 -; .dw 0b1100011000110011 ; columna 5 -; .dw 0b1100001100110011 ; columna 6 -; .dw 0b1100001100000011 ; columna 7 -; .dw 0b1100001100000011 ; columna 8 -; .dw 0b1100001100110011 ; columna 9 -; .dw 0b1100011000110011 ; columna 10 -; .dw 0b1100110000000011 ; columna 11 -; .dw 0b0110000000000110 ; columna 12 -; .dw 0b0111000000001110 ; columna 13 -; .dw 0b0011111111111100 ; columna 14 -; .dw 0b0000111111110000 ; columna 15 - -;MAT_D: + .dw 0b1111000000001111 ; columna 0 + .dw 0b1100000000000011 ; columna 1 + .dw 0b1000111111110001 ; columna 2 + .dw 0b1001111111111001 ; columna 3 + .dw 0b0011001111111100 ; columna 4 + .dw 0b0011100111001100 ; columna 5 + .dw 0b0011110011001100 ; columna 6 + .dw 0b0011110011111100 ; columna 7 + .dw 0b0011110011111100 ; columna 8 + .dw 0b0011110011001100 ; columna 9 + .dw 0b0011100111001100 ; columna 01 + .dw 0b0011001111111100 ; columna 00 + .dw 0b1001111111111001 ; columna 01 + .dw 0b1000111111110001 ; columna 03 + .dw 0b1100000000000011 ; columna 04 + .dw 0b1111000000001111 ; columna 05 + ; .dw 0b0000001111100000 ; columna 0 ; .dw 0b0000111110000000 ; columna 1 ; .dw 0b0111111000000000 ; columna 2 diff --git a/pruebas/sdcc/leds_asm/leds.h b/pruebas/sdcc/leds_asm/leds.h new file mode 100644 index 0000000..188978b --- /dev/null +++ b/pruebas/sdcc/leds_asm/leds.h @@ -0,0 +1,45 @@ +/* vim: set et sw=4 sts=4 : */ + +#ifndef _LEDS_H_ +#define _LEDS_H_ + +/** Cantidad máxima de columnas */ +#define LEDS_MAX_COLS 32 + +/** Tamaño de la matriz de leds, en cantidad de columnas */ +extern unsigned char leds_matrix_len; + +/** Matriz de leds, cada elemento del array es una columna */ +extern unsigned int leds_matrix[LEDS_MAX_COLS]; + +/** Retardo de refresco de la matriz (en múltiplos de 0.1ms) */ +extern unsigned char leds_delay; + +/** Inicializa leds + * + * El 'dibujado' de la matriz se puede controlar fácilmente parando y/o + * iniciando el timer2. Para comenzar a 'dibujar' la matriz sólo es necesario + * setear el bit TR2 del registro T2CON (y habilitar las interrupciones + * globalmente si aún no se hizo, bit EA del registro IE). + */ +void leds_init(); + +/** Realiza un testeo simple de los leds */ +void leds_test(); + +/** Escribe un word (16 bits) en la columna de leds */ +void leds_write(unsigned int); + +/** Escribe un byte en la parte baja de la columna de leds */ +void leds_write_low(unsigned char); + +/** Escribe un byte en la parte alta de la columna de leds */ +void leds_write_high(unsigned char); + +/** Actualiza el delay al recomendado según el tamaño de la matriz */ +void leds_delay_update(); + +/** Atiende interrupción del timer2 para 'dibujar' la matriz */ +void leds_timer2_isr() interrupt 5; + +#endif /* _LEDS_H_ */ diff --git a/pruebas/sdcc/leds_asm/leds.lnk b/pruebas/sdcc/leds_asm/leds.lnk index 139fc87..a5ce4ef 100644 --- a/pruebas/sdcc/leds_asm/leds.lnk +++ b/pruebas/sdcc/leds_asm/leds.lnk @@ -1,7 +1,6 @@ -myuxi -Y --b INTV = 0x0000 --b CSEG = 0x0030 +-b CSEG = 0x0000 -b ISEG = 0x0080 -b BSEG = 0x0000 -k /usr/share/sdcc/lib/small @@ -11,5 +10,6 @@ -l libint -l liblong -l libfloat +main.rel leds.rel -e diff --git a/pruebas/sdcc/leds_asm/main.c b/pruebas/sdcc/leds_asm/main.c new file mode 100644 index 0000000..0667f27 --- /dev/null +++ b/pruebas/sdcc/leds_asm/main.c @@ -0,0 +1,18 @@ + +#include "leds.h" + +sbit at 0xaf ea; +sbit at 0xca tr2; + +void main() +{ + /* inicializo leds */ + leds_init(); + /* los pruebo */ + leds_test(); + /* empiezo a atender todas las interrupciones */ + ea = 1; + /* largo a correr el timer 2 */ + tr2 = 1; +} + -- 2.43.0