From f5186e12ed5aedf98d0fa0d8299a73c830046c75 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Sun, 11 Dec 2005 07:40:16 +0000 Subject: [PATCH] Agrego ejemplo de los leds andando escrito en ASM para sdcc. Falta hacer el .h de C y probar de integrarlo. --- pruebas/sdcc/leds_asm/Makefile | 14 ++ pruebas/sdcc/leds_asm/leds.asm | 313 +++++++++++++++++++++++++++++++++ pruebas/sdcc/leds_asm/leds.lnk | 15 ++ 3 files changed, 342 insertions(+) create mode 100644 pruebas/sdcc/leds_asm/Makefile create mode 100644 pruebas/sdcc/leds_asm/leds.asm create mode 100644 pruebas/sdcc/leds_asm/leds.lnk diff --git a/pruebas/sdcc/leds_asm/Makefile b/pruebas/sdcc/leds_asm/Makefile new file mode 100644 index 0000000..1d4ec5c --- /dev/null +++ b/pruebas/sdcc/leds_asm/Makefile @@ -0,0 +1,14 @@ + +all: + @asx8051 -plosgff leds.asm + @aslink -nf leds.lnk + @packihx leds.ihx > leds.hex + +cleantmp: + @rm -f *.sym *.rel *.map *.ihx *.lst *.mem *.rst + +clean: cleantmp + @rm -f *.hex + +.PHONY: clean cleantmp + diff --git a/pruebas/sdcc/leds_asm/leds.asm b/pruebas/sdcc/leds_asm/leds.asm new file mode 100644 index 0000000..5fd5314 --- /dev/null +++ b/pruebas/sdcc/leds_asm/leds.asm @@ -0,0 +1,313 @@ +; vim: set filetype=asx8051 et sw=4 sts=4 : + +; Módulo y opciones +.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 +; 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 + +; Área de bancos de registros +.area REG_BANK_0 (REL,OVR,DATA) + .ds 8 + ; Usamos siempre banco 0 + ar0 = 0x00 + ar1 = 0x01 + ar2 = 0x02 + ar3 = 0x03 + ar4 = 0x04 + ar5 = 0x05 + ar6 = 0x06 + ar7 = 0x07 + +; Variables es memoria RAM común +.area DSEG (DATA) +_leds_matrix_len:: + .ds 1 +_leds_delay:: + .ds 1 +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 + + +; 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 + + +; Área de código del programa +.area CSEG (CODE) + +; Inicializa leds. +; Primitiva de C: +; void leds_init(); +; +; 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 + clr a + movc a, @a+dptr + mov _leds_matrix_len, a + clr c + rlc a ; multiplicamos por 2 porque hay 2 bytes por columna + mov r2, a ; tamaño en bytes de la matriz + + ; Cargo milisegundos + acall _leds_delay_update + mov delay, _leds_delay + + ; copio imagen por default de la ROM a la RAM + mov dptr, #MAT_D + mov r0, #0 ; indice del "array" en la ROM + mov r1, #_leds_matrix ; dirección de memoria de la RAM + mov a, r0 +seguir$: + 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 + + ; 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 curr_col, #0 ; inicializo el contador de columna en 0 + + ; Limpiamos stack + push ar2 + push ar1 + push ar0 + + 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:: + ; parte baja + mov a, dpl ; de C me viene la parte baja del argumento en el dpl + mov dptr, #LEDS0 + 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 + cpl a ; complemento para ver encendidos los "1" + movx @dptr, a + ret + + +; Escribe en los leds del primer latch. +; Primitiva de C: +; void leds_write0(unsigned char); +; +; C se encarga de hacer push y pop del dptr, a y psw si lo necesita. +_leds_write0:: + ; parte baja + mov a, dpl ; de C me viene el argumento en el dpl + mov dptr, #LEDS0 + cpl a ; complemento para ver encendidos los "1" + movx @dptr, a + ret + + +; Escribe en los leds del segundo latch. +; Primitiva de C: +; void leds_write1(unsigned char); +; +; C se encarga de hacer push y pop del dptr, a y psw si lo necesita. +_leds_write1:: + ; parte baja + mov a, dpl ; de C me viene el argumento en el dpl + mov dptr, #LEDS1 + cpl a ; complemento para ver encendidos los "1" + movx @dptr, a + ret + + +; Actualiza el retardo de la matriz según la cantidad de columnas +; Primitiva de C: +; void leds_delay_update(); +; +; La fórmula utilizada es: (DELAY_BASE - (leds_matrix_len / 2)) * 0.1 ms +; C se encarga de hacer push y pop del dptr, a y psw si lo necesita. +_leds_delay_update:: + mov a, _leds_matrix_len + clr c + rrc a ; divido por 2 + mov dpl, a + mov a, #DELAY_BASE + subb a, dpl + mov _leds_matrix_len, a + ret + + +; Manejador de la interrupción del timer2 +timer2_isr: + ; vemos si todavía hay que seguir esperando o si ya tenemos que leer + djnz delay, fin$ + + ; comenzamos realmente a leer la próxima columna + mov delay, _leds_delay + + ; guardamos en el stack el estado actual de los registros que vamos a usar + push acc + push psw + push ar0 + push dpl + push dph + + ; vemos si hay que empezar a leer por la 1ra columna de nuevo + mov a, curr_col + cjne a, _leds_matrix_len, continua$ + + ; hay que empezar de nuevo + mov curr_col, #0 + mov a, curr_col ; dejamos en a la columna actual + +continua$: + ; multiplicamos por 2 porque hay 2 bytes por columna + clr c + rlc a + + ; uso r0 como puntero al comienzo de la matriz + mov r0, #_leds_matrix + add a, r0 ; le sumo al puntero el offset actual segun la columna + mov r0, a + + ; imprimo en LEDS1 + mov a, @r0 ; leo el contenido de la matriz + mov dptr, #LEDS1 + cpl a ; complemento para ver encendidos los "1" + movx @dptr, a + + ; imprimo en LEDS0 + inc r0 ; busco proximo byte de la columna + mov a, @r0 ; leo el contenido de la matriz + mov dptr, #LEDS0 + cpl a ; complemento para ver encendidos los "1" + movx @dptr, a + + ; avanzamos a la proxima columna + mov a, curr_col + inc a + mov curr_col, a + + ; sacamos nuestra basura del stack + pop dph + pop dpl + pop ar0 + pop psw + pop acc + +fin$: + reti ; listo! seguimos viaje... + + +; Matriz por default +MAT_D_LEN: + .db 16 + ;.db 32 + +MAT_D: + .dw 0b0000111111110000 ; columna 0 + .dw 0b0011111111111100 ; columna 1 + .dw 0b0111000000001110 ; columna 2 + .dw 0b0110000000000110 ; columna 3 + .dw 0b1100001100000011 ; columna 4 + .dw 0b1100011000110011 ; columna 5 + .dw 0b1100110000110011 ; columna 6 + .dw 0b1100110000000011 ; columna 7 + .dw 0b1100110000000011 ; columna 8 + .dw 0b1100110000110011 ; columna 9 + .dw 0b1100011000110011 ; columna 10 + .dw 0b1100001100000011 ; columna 11 + .dw 0b0110000000000110 ; columna 12 + .dw 0b0111000000001110 ; columna 13 + .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 0b0000001111100000 ; columna 0 +; .dw 0b0000111110000000 ; columna 1 +; .dw 0b0111111000000000 ; columna 2 +; .dw 0b1111000000000000 ; columna 3 +; .dw 0b0111100000000000 ; columna 4 +; .dw 0b0011110000000000 ; columna 5 +; .dw 0b0001111000000000 ; columna 6 +; .dw 0b0000111100000000 ; columna 7 +; .dw 0b0000011110000000 ; columna 8 +; .dw 0b0000001111000000 ; columna 9 +; .dw 0b0000000111100000 ; columna 10 +; .dw 0b0000000011110000 ; columna 11 +; .dw 0b0000000001111000 ; columna 12 +; .dw 0b0000000000111100 ; columna 13 +; .dw 0b0000000000011110 ; columna 14 +; .dw 0b0000000000001111 ; columna 15 + +;end diff --git a/pruebas/sdcc/leds_asm/leds.lnk b/pruebas/sdcc/leds_asm/leds.lnk new file mode 100644 index 0000000..139fc87 --- /dev/null +++ b/pruebas/sdcc/leds_asm/leds.lnk @@ -0,0 +1,15 @@ +-myuxi +-Y +-b INTV = 0x0000 +-b CSEG = 0x0030 +-b ISEG = 0x0080 +-b BSEG = 0x0000 +-k /usr/share/sdcc/lib/small +-k /usr/share/sdcc/lib/small +-l mcs51 +-l libsdcc +-l libint +-l liblong +-l libfloat +leds.rel +-e -- 2.43.0