Estoy desarrollando software para attiny88 con la cadena de herramientas avr-gcc. Este es un microcontrolador económico con memoria de programa de 8kB, SRAM de 512B y memoria de datos EEPROM no volátil de 64B. Todo esto es suficiente para la tarea que se supone que debe manejar. No tengo un depurador para este chip.
El dispositivo actúa como esclavo SPI y permite al maestro leer/programar la EEPROM y leer el estado del dispositivo (estado de algunas entradas analógicas y salidas digitales). El protocolo es simple: el primer byte de datos lleva la instrucción donde los dos bits más altos codifican la acción requerida (00-nada, 01-escribe eeprom, 10-lee eeprom, 11-lee estado) y el resto es dirección. El segundo byte siempre es cero, el tercer byte es el valor para leer o escribir, el cuarto byte siempre es cero.
El problema es que obtengo un comportamiento extraño del compilador. Es difícil poner un dedo en lo que está pasando, así que solo daré algunos ejemplos. Lo más llamativo es que sin la optimización -Os el dispositivo no responde sobre SPI. Esto no se debe a ninguna de las razones obvias: el programa se ajusta a la memoria y la pila no debe ejecutarse en secciones .bss/.data (el programa tiene ~700B, la SRAM está asignada entre 0x100 y 0x2ff, donde .bss_end está en 0x109; el montón está vacío; no hay llamadas de función anidadas, ni interrupciones anidadas).
Si enciendo la optimización -Os, entonces el programa responde según lo previsto. Aquí está el código de trabajo para manejar el ISR:
unsigned char state[8];
volatile unsigned char data;
ISR(SPI_STC_vect)
{
switch(data>>6) {
case 0:
data = SPDR;
break;
case 1: /* write eeprom */
while(EECR & (1<<EEPE));
EECR = (0<<EEPM1)|(0<<EEPM0);
EEARL = 0;
EEDR = SPDR;
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
data = 0;
break;
case 2: /* read eeprom */
EEARL = data & 0x1f; /* with 0x3f stops working (???) */
EECR |= (1<<EERE);
SPDR = EEDR;
data = 0;
break;
case 3: /* read state */
SPDR = state[data&7];
data = 0;
break;
}
}
Sin embargo, el programa se rompe cuando se escribe de forma semánticamente diferente:
Si cambio la línea "EEARL = data & 0x1f;" a "EEARL = data & 0x3f;", lo cual es deseable ya que permitiría abordar todo el espacio de direcciones de EEPROM, la escritura/lectura de ERPROM deja de funcionar (no necesito 64B completo, así que lo dejé como está)
La lectura de estado (caso 3) se interrumpe si reemplazo la línea "SPDR = state[data&7];" con una construcción switch-case que devuelve el valor del registro PORTD/PORTB cuando la dirección es 0 y 1 respectivamente (la solución actual es mantener el estado [0] y el estado [1] sincronizados con PORTB/PORTD en el bucle principal).
¿Me estoy perdiendo algo importante? Me parece que el compilador se estropea, pero no he encontrado ningún informe de error para avr-gcc o avr-libc (¿newlib?) que se ajuste a la factura.
La cadena de herramientas se instaló desde el paquete gcc-avr actual en los repositorios de aptitude. El archivo MAKE es bastante básico:
all: main.hex main.s
main.elf: main.o
avr-gcc -g -mmcu=attiny88 -o main.elf main.o
main.s: main.elf
avr-objdump -d main.elf > main.s
main.hex: main.elf
avr-objcopy -O ihex main.elf main.hex
main.o: main.c
avr-gcc -mmcu=attiny88 -Os -c main.c -Wall
ACTUALIZACIÓN : sigue siendo el mismo resultado con los últimos binutils, gcc y avr-libc (recompilado de las fuentes)
Deberá inspeccionar la salida de avr-objdump
para ver qué instrucciones exactas se generaron para su código. Por cierto, sería útil incluir su código C en el desmontaje a través de avr-objdump -S main.elf > main.s
. Dudo que todo el programa se vuelva diferente cuando reemplaza la 0x1F
constante por 0x3F
, aislar las diferencias en la lista y analizarlas cuidadosamente sería su próximo paso.
Tal análisis es lo más lejos que puede llegar sin las herramientas de desarrollo adecuadas. Obtener un depurador o un simulador le ahorraría mucho esfuerzo que se requiere cuando está limitado al análisis de listas estáticas.
PD: Supongo que aquí no recibe ninguna advertencia del compilador durante la compilación. Si tiene alguno, arreglarlos debería ser su primera prioridad. Los compiladores modernos hacen un trabajo bastante bueno al informarle sobre errores sutiles que pueden ser difíciles de encontrar de otra manera.
avr-gcc -mmcu=attiny88 -Os -S main.c
, . Eso debería dejar los literales de dirección en forma simbólica ( label_0001
etc.), por lo que producir una diferencia debería ser más fácil.
PlasmaHH
Lundin
data
variable? ¿Está confiando en la inicialización estática para darle "cero"? Eso siempre es una mala idea, ya que los microcontroladores a menudo se desvían del estándar C allí, para brindar una puesta en marcha más rápida.Lundin
alumno
Damián
alumno
alumno
alumno
carloc
alumno
marcelmo
while(EECR & (1<<EEPE));
antes de leer la eeprom. Observación #2: No veo cómo funciona el protocolo de 4 bytes que describiste con tu ISR - Ejemplo: eeprom write; el primer byte se leerá como comando/dirección, el segundo byte (cero) activará la escritura real y escribirá 0 en eeprom, el tercer byte (datos) se interpretará nuevamente como un comando. Eso no coincide con la intención descrita...alumno
alumno