lee o se escribe un registro de la placa de red, se deja de atender las
interrupciones del timer de los leds para evitar una condición de carrera del
puerto 2. También se hacen otros cambios pequeños:
* Se hace un cheque sobre el tamaño de la matriz que viene de la red.
* Se cambia el intervalo del timer de los leds (cuanto más grande menos
interrupciones se saltea). Hay algo más de trabajo por hacer en este área.
* Se corrige un bug en leds.asm, en algún momento se borró el .ds 1 que
reservaba memoria para curr_col, que estaba tomando 'prestado' el 1er byte de
la matriz (o peor, tomando un byte de vaya uno a saber dónde).
static void write_reg(unsigned char reg, unsigned char wr_data)
{
static void write_reg(unsigned char reg, unsigned char wr_data)
{
// Select register address.
ADDR_PORT &= ~ADDR_PORT_MASK;
ADDR_PORT |= reg;
// Select register address.
ADDR_PORT &= ~ADDR_PORT_MASK;
ADDR_PORT |= reg;
// Set register data port as input again.
DATA_PORT = DATA_PORT_MASK;
// Set register data port as input again.
DATA_PORT = DATA_PORT_MASK;
}
static unsigned char read_reg(unsigned char reg)
{
}
static unsigned char read_reg(unsigned char reg)
{
// Select register address.
ADDR_PORT &= ~ADDR_PORT_MASK;
ADDR_PORT |= reg;
// Select register address.
ADDR_PORT &= ~ADDR_PORT_MASK;
ADDR_PORT |= reg;
*((byte*) &elp_command) = udp_read_byte();
netdev_read_end();
*((byte*) &elp_command) = udp_read_byte();
netdev_read_end();
- printb(*((byte*) &elp_command), 0x01);
-
// Si es un SET lo proceso
switch (elp_command.var)
{
// Si es un SET lo proceso
switch (elp_command.var)
{
i = udp_read_byte();
netdev_read_end();
// Verifico cantidad de columnas
i = udp_read_byte();
netdev_read_end();
// Verifico cantidad de columnas
- if ((LEDS_MIN_COLS < i) || (i < LEDS_MAX_COLS))
+ if ((i < LEDS_MIN_COLS) || (i > LEDS_MAX_COLS))
return 0;
leds_matrix_len = i;
netdev_read_start(leds_matrix_len * 2); // matriz
return 0;
leds_matrix_len = i;
netdev_read_start(leds_matrix_len * 2); // matriz
return len + 1 /* booleano de 1 byte */;
// Si es SET procesamos
netdev_read_start(1); // booleano de 1 byte
return len + 1 /* booleano de 1 byte */;
// Si es SET procesamos
netdev_read_start(1); // booleano de 1 byte
- //XXX if (udp_read_byte() == 0x00) // si viene 0 reanuda
- //XXX TR2 = 1;
- //XXX else
- if (udp_read_byte() != 0x00)
+ if (udp_read_byte() == 0x00) // si viene 0 reanuda
+ ET2 = 1;
+ else
leds_write(0x0000); // Si pausa apaga leds
}
netdev_read_end();
leds_write(0x0000); // Si pausa apaga leds
}
netdev_read_end();
case ELP_VAR_PAUSE:
netdev_write_start(1 /* booleano de 1 byte */);
case ELP_VAR_PAUSE:
netdev_write_start(1 /* booleano de 1 byte */);
netdev_write_end();
break;
netdev_write_end();
break;
.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_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_lock ; void leds_lock();
+.globl _leds_unlock ; void leds_unlock();
.globl _leds_timer2_isr ; void leds_timer2_isr() interrupt 5;
; Constantes
.globl _leds_timer2_isr ; void leds_timer2_isr() interrupt 5;
; Constantes
-; UN CICLO DE MAQUINA SON 1.6666 useg (clock 8MHz)
-INTERVAL = 65000 ; 0.05ms (por el clock de 8MHz)
+INTERVAL = 666 ; 0.1ms (por el clock de 8MHz)
LEDS_LOW = 0x0080
LEDS_HIGH = 0x00c0
LEDS_LOW = 0x0080
LEDS_HIGH = 0x00c0
-DELAY_BASE = 28 ; 16 columnas anda bien con 28 - (len / 2) == 20
+DELAY_BASE = 11 ; 16 columnas anda bien con 28 - (len / 2) == 20
; Área de bancos de registros
.area REG_BANK_0 (REL,OVR,DATA)
; Área de bancos de registros
.area REG_BANK_0 (REL,OVR,DATA)
; Variables es memoria RAM común
.area DSEG (DATA)
; Variables es memoria RAM común
.area DSEG (DATA)
+_leds_matrix_len:: ; Cantidad de columnas de la matriz
+_leds_delay:: ; Retardo de dibujado configurado
+delay: ; Contador del retardo actual
+ .ds 1
+curr_col: ; Columna que se está dibujando actualmente
; Variables en memoria RAM extendida indirecta (8052)
.area ISEG (DATA)
; Variables en memoria RAM extendida indirecta (8052)
.area ISEG (DATA)
+_leds_matrix:: ; Matriz a dibujar
.ds LEDS_MAX_COLS * 2 ; 2 bytes por columna
.ds LEDS_MAX_COLS * 2 ; 2 bytes por columna
+; Variables de bit
+.area BSEG (BIT)
+lock: ; Variable utilizada para el 'locking', indica si el timer
+ .ds 1 ; estaba andando al momento de lockear para que el unlock
+ ; pueda reactivarlo de ser necesario
; Configuramos el vector de interrupciones para atender el timer2
;.area INTV (ABS, CODE)
; Configuramos el vector de interrupciones para atender el timer2
;.area INTV (ABS, CODE)
mov rcap2h, #>(-INTERVAL) ; high byte del intervalo
mov t2con, #0x00; setup del timer2 (auto-reload), no lo arrancamos
mov rcap2h, #>(-INTERVAL) ; high byte del intervalo
mov t2con, #0x00; setup del timer2 (auto-reload), no lo arrancamos
- setb et2 ; habilito interrupcion timer2 (IE.5)
+ setb tr2 ; largo a correr el timer2
mov curr_col, #0 ; inicializo el contador de columna en 0
mov curr_col, #0 ; inicializo el contador de columna en 0
subb a, dpl
mov _leds_delay, a
ret
subb a, dpl
mov _leds_delay, a
ret
+
+
+; Bloquea el timer de los leds cuando se accede a una zona crítica (P0 y/o P2).
+; Primitiva de C:
+; void leds_lock();
+;
+; C se encarga de hacer push y pop del dptr, a y psw si lo necesita.
+_leds_lock::
+ mov c, et2 ; En lock me queda si está el timer andando o no.
+ mov lock, c
+ clr et2 ; Sea como sea, lo paro.
+ ret
+
+
+; Desbloquea el timer de los leds.
+; Primitiva de C:
+; void leds_unlock();
+;
+; C se encarga de hacer push y pop del dptr, a y psw si lo necesita.
+_leds_unlock::
+ jnb lock, 1$ ; Si no estába andando, no hago nada
+ setb et2 ; Si estaba andando lo prendo
+1$:
+ ret
; Manejador de la interrupción del timer2 para el uso de los leds.
; Manejador de la interrupción del timer2 para el uso de los leds.
; void leds_timer2_isr() interrupt 5;
;
_leds_timer2_isr::
; void leds_timer2_isr() interrupt 5;
;
_leds_timer2_isr::
+ ; limpiamos flag del timer2
+ clr tf2
; vemos si todavía hay que seguir esperando o si ya tenemos que leer
djnz delay, 255$
; vemos si todavía hay que seguir esperando o si ya tenemos que leer
djnz delay, 255$
/** Actualiza el delay al recomendado según el tamaño de la matriz */
void leds_delay_update();
/** Actualiza el delay al recomendado según el tamaño de la matriz */
void leds_delay_update();
+/** Bloquea timer de leds cuando se accede a una zona crítica (P0 y/o P2). */
+void leds_lock();
+
+/** Desbloquea el timer de los leds.
+ * @precond Se llamó a leds_lock();
+ */
+void leds_unlock();
+
/** Atiende interrupción del timer2 para 'dibujar' la matriz */
void leds_timer2_isr() interrupt 5;
/** Atiende interrupción del timer2 para 'dibujar' la matriz */
void leds_timer2_isr() interrupt 5;
// Comienza a 'dibujar'
EA = 1; // Habilita interrupciones globalmente
// Comienza a 'dibujar'
EA = 1; // Habilita interrupciones globalmente
- //XXX TR2 = 1; // Pone a correr el 'dibujado'
+ ET2 = 1; // Pone a correr el 'dibujado'
// Inicializo IP
ip_addr_local[0] = 10;
// Inicializo IP
ip_addr_local[0] = 10;
// Procesamos comando ELP y obtenemos tamaño de la
// respuesta
len = elp_read_process_command();
// Procesamos comando ELP y obtenemos tamaño de la
// respuesta
len = elp_read_process_command();
// Si el tamaño es 0, hubo error o no está soportado
if (!len)
goto drop;
// Si el tamaño es 0, hubo error o no está soportado
if (!len)
goto drop;
// FIXME por ahora no tenemos forma de 'abortar' el
// comando si el checksum es incorrecto, lo verificamos
// por deporte.
if (!udp_checksum_ok())
goto drop;
// FIXME por ahora no tenemos forma de 'abortar' el
// comando si el checksum es incorrecto, lo verificamos
// por deporte.
if (!udp_checksum_ok())
goto drop;
// Terminamos recepción
netdev_recv_end();
// Terminamos recepción
netdev_recv_end();
// Respuesta
netdev_send_start();
eth_write_frame_header();
ip_packet_len = UDP_HEADER_SIZE + len;
// Respuesta
netdev_send_start();
eth_write_frame_header();
ip_packet_len = UDP_HEADER_SIZE + len;
- printb(ip_packet_len, 0x20);
+ //printb(ip_packet_len, 0x20);
ip_write_packet_header();
udp_dgram_len = len;
ip_write_packet_header();
udp_dgram_len = len;
- printb(udp_dgram_len, 0x40);
+ //printb(udp_dgram_len, 0x40);
udp_write_dgram_header();
elp_write_response();
udp_write_checksum(ETH_HEADER_SIZE + IP_HEADER_SIZE);
netdev_send_end(ETH_HEADER_SIZE + IP_HEADER_SIZE
+ UDP_HEADER_SIZE + len);
udp_write_dgram_header();
elp_write_response();
udp_write_checksum(ETH_HEADER_SIZE + IP_HEADER_SIZE);
netdev_send_end(ETH_HEADER_SIZE + IP_HEADER_SIZE
+ UDP_HEADER_SIZE + len);
- printb(ETH_HEADER_SIZE + IP_HEADER_SIZE
- + UDP_HEADER_SIZE + len, 0x80);
- //XXX
- if (elp_command.set && (elp_command.var == ELP_VAR_PAUSE))
- TR2 = 1;
sbit ES = 0xAC;
sbit ET1 = 0xAB;
sbit EX1 = 0xAA;
sbit ES = 0xAC;
sbit ET1 = 0xAB;
sbit EX1 = 0xAA;
/* IE */
sbit at 0xAF EA;
/* IE */
sbit at 0xAF EA;
sbit at 0xAC ES;
sbit at 0xAB ET1;
sbit at 0xAA EX1;
sbit at 0xAC ES;
sbit at 0xAB ET1;
sbit at 0xAA EX1;