Usar una variable como índice de matriz - ¿Error de optimización?

Descubrí un error en mi código que solo aparece si se usa la optimización avr-gcc.

¿Alguien puede explicar cuál es el problema aquí?

Soy consciente de que hay varias formas inteligentes de lograr algo de PWM, pero ese no es el punto aquí.

Información de contexto

Juego con un LED y lo atenúo con PWM. Para hacer una corrección de gamma simple, uso una matriz predefinida con los valores correctos.

Código

Este es el código que uso, Main contiene solo el inicio de interrupción y un ciclo while(1) vacío:

volatile size_t fade;
volatile uint16_t counter = 0;

const uint16_t PROGMEM pwmtable_10[64] = {
    0, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10,
    11, 12, 13, 15, 17, 19, 21, 23, 26, 29, 32, 36, 40, 44, 49, 55,
    61, 68, 76, 85, 94, 105, 117, 131, 146, 162, 181, 202, 225, 250,
    279, 311, 346, 386, 430, 479, 534, 595, 663, 739, 824, 918, 1023
};

ISR(TIMER0_OVF_vect) {
 // fade is set in the main loop or somewhere else
    if(counter < pwmtable_10[fade]) {
        counter=counter+1;
        PORTB = 0;
    } else {
        counter=0;
        PORTB |= RED;
    }
}

Un valor de 1 da una luz muy brillante, un valor de 1023 da una luz muy tenue. Se puede acceder al valor 1023 a través del índice de matriz 63.

El problema

No importa en qué valor establezca el desvanecimiento, el LED siempre está brillante, si compilo mi código con avr-gcc -Os. Al usar avr-gcc -O0el código funciona.

Cambiar al código no funciona incluso configurando el desvanecimiento a 63 dentro de la interrupción:

ISR(TIMER0_OVF_vect) {
    fade=63;
    if(counter < pwmtable_10[fade]) {
    //[..]

Esto es lo que funciona:

  • Reemplazando pwmtable_10[fade]con 1023.
  • reemplazando pwmtable_10[fade]conpwmtable_10[63]
  • Reemplazar fadecon una nueva variable declarada directamente antes de la comparación

Información adicional

Plataforma: Atmega 168

% avr-gcc --version
avr-gcc (GCC) 4.8.2

Comandos para construir y flashear el código:

avr-gcc -Wall -Wextra -Os -mmcu=atmega168 -DF_CPU=16000000 -o moody.elf moody.c
avr-objcopy -j .text -j .data -O ihex moody.elf moody.hex
avrdude -b4 -c usbasp -v -p m168 -P usb -U flash:w:moody.hex
¿Qué sucede cuando haces que el pwmtable sea volátil?
El mismo problema :-/
¿Qué pasa cuando haces fadevolátiles? (@TomL. está en el camino correcto, variable incorrecta)
Parece que fade ya es volátil
Es volátil (vea la primera línea del ejemplo de código :-))
Sugerencia estúpida, pero ¿por qué no declarar fade a uint8_t en lugar de size_t?
Tienes razón, esto es más o menos un sobrante de la depuración :-) Traté de jugar con eso, pero no obtuve ningún efecto.
¿Puedes oler el valor que realmente devuelve pwmtable_10[fade], tal vez con un printf?

Respuestas (1)

Creo que el problema está en el atributo PROGMEM que guarda la matriz const en la memoria flash. Para obtener valores, necesita un memcpy_P() más o menos. Para acceso directo intente evitar el atributo PROGMEM. pwmtable_10[fade] obtiene un valor de RAM aleatorio.

Consulte http://www.nongnu.org/avr-libc/user-manual/pgmspace.html

gracias tienes razon! Esto funciona ahora. Edité su respuesta y agregué una referencia a la documentación. :-)