Limitaciones de memoria del microcontrolador PIC

Estoy tratando de programar un PIC10f202 usando el compilador XC8 para comparar el valor de un temporizador con una variable que será una función de una tabla de búsqueda. Aquí hay un código de muestra:

#include <xc.h>

#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config WDTE = OFF

Init(void){
    TRIS=0;
    GPIO=0;
    TMR0 = 0;
    OPTION = 0b00000011;
}

const unsigned char LUT[250] = {
0b00000000, 0b00000001, 0b00000001, 0b00000001, 0b00000001,
0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001,
0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001,
0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001,
0b00000001, 0b00000001, 0b00000001, 0b00000010, 0b00000010,
0b00000010, 0b00000010, 0b00000010, 0b00000010, 0b00000011,
0b00000011, 0b00000011, 0b00000011, 0b00000011, 0b00000100,
0b00000100, 0b00000100, 0b00000101, 0b00000101, 0b00000101,
0b00000110, 0b00000110, 0b00000110, 0b00000111, 0b00000111,
0b00001000, 0b00001000, 0b00001001, 0b00001001, 0b00001010,
0b00001010, 0b00001011, 0b00001100, 0b00001100, 0b00001101,
0b00001101, 0b00001110, 0b00001111, 0b00010000, 0b00010000,
0b00010001, 0b00010010, 0b00010011, 0b00010011, 0b00010100,
0b00010101, 0b00010110, 0b00010111, 0b00011000, 0b00011001,
0b00011010, 0b00011011, 0b00011100, 0b00011101, 0b00011110,
0b00011111, 0b00100000, 0b00100001, 0b00100010, 0b00100100,
0b00100101, 0b00100110, 0b00100111, 0b00101001, 0b00101010,
0b00101011, 0b00101100, 0b00101110, 0b00101111, 0b00110000,
0b00110010, 0b00110011, 0b00110101, 0b00110110, 0b00111000,
0b00111001, 0b00111011, 0b00111100, 0b00111110, 0b00111111,
0b01000001, 0b01000010, 0b01000100, 0b01000110, 0b01000111,
0b01001001, 0b01001011, 0b01001100, 0b01001110, 0b01010000,
0b01010001, 0b01010011, 0b01010101, 0b01010111, 0b01011000,
0b01011010, 0b01011100, 0b01011110, 0b01100000, 0b01100001,
0b01100011, 0b01100101, 0b01100111, 0b01101001, 0b01101010,
0b01101100, 0b01101110, 0b01110000, 0b01110010, 0b01110100,
0b01110110, 0b01111000, 0b01111001, 0b01111011, 0b01111101,
0b01111111, 0b10000001, 0b10000011, 0b10000101, 0b10000111,
0b10001000, 0b10001010, 0b10001100, 0b10001110, 0b10010000,
0b10010010, 0b10010100, 0b10010110, 0b10010111, 0b10011001,
0b10011011, 0b10011101, 0b10011111, 0b10100000, 0b10100010,
0b10100100, 0b10100110, 0b10101000, 0b10101001, 0b10101011,
0b10101101, 0b10101111, 0b10110000, 0b10110010, 0b10110100,
0b10110101, 0b10110111, 0b10111001, 0b10111010, 0b10111100,
0b10111110, 0b10111111, 0b11000001, 0b11000010, 0b11000100,
0b11000101, 0b11000111, 0b11001000, 0b11001010, 0b11001011,
0b11001101, 0b11001110, 0b11010000, 0b11010001, 0b11010010,
0b11010100, 0b11010101, 0b11010110, 0b11010111, 0b11011001,
0b11011010, 0b11011011, 0b11011100, 0b11011110, 0b11011111,
0b11100000, 0b11100001, 0b11100010, 0b11100011, 0b11100100,
0b11100101, 0b11100110, 0b11100111, 0b11101000, 0b11101001,
0b11101010, 0b11101011, 0b11101100, 0b11101101, 0b11101101,
0b11101110, 0b11101111, 0b11110000, 0b11110000, 0b11110001,
0b11110010, 0b11110011, 0b11110011, 0b11110100, 0b11110100,
0b11110101, 0b11110110, 0b11110110, 0b11110111, 0b11110111,
0b11111000, 0b11111000, 0b11111001, 0b11111001, 0b11111010,
0b11111010, 0b11111010, 0b11111011, 0b11111011, 0b11111011,
0b11111100, 0b11111100, 0b11111100, 0b11111101, 0b11111101,
0b11111101, 0b11111101, 0b11111101, 0b11111110, 0b11111110,
0b11111110, 0b11111110, 0b11111110, 0b11111110, 0b11111111};

unsigned char cnt1=0;

void main(){
        Init();
        for(;;){
            cnt1 = LUT[100];
            while(TMR0 > 100){
            GPIO=0b00000001;
            }
            GPIO=0b00000000;
        }
}

La tabla de búsqueda tiene 250 caracteres porque este es el tamaño máximo permitido por el compilador antes de que me diera un error "No se pueden encontrar palabras x0FF (x0ff con total) para psect "stringtext1" en la clase "Entrada"". El código se compila bien, con MPLAB X indicando un uso de memoria flash del 55 % y un uso de RAM del 0 %. Si cambio la condición "mientras" a esto:

while(TMR0 > cnt1)

El compilador volverá a darme un error similar: "No se pueden encontrar palabras x0FA (x0fa con total) para psect "stringtext1" en la clase "Entrada"". Entiendo que el compilador no puede encontrar suficiente memoria para escribir el código, pero no veo cómo el 45 % de espacio libre no es suficiente para esta tarea. Además, ¿por qué no puedo crear una matriz con 255 elementos? El PIC10f202 tiene 512 palabras de memoria, debería ser posible.

¿Por qué el compilador da esos errores?

Se responde con hechos. Edité la pregunta para que quede clara.
Y mi opinión (y hecho) es que el PIC que eligió no es adecuado para lo que está tratando de hacer. Esta es también la razón por la que me niego a usar PIC nunca más. Hacer cualquier tipo de estructura de datos de más de 16 bytes es demasiado doloroso, y hay muchas otras MCU que son tan económicas y mucho más capaces.

Respuestas (4)

Este es un ejemplo perfecto de cómo usar un compilador a ciegas en un sistema pequeño con recursos limitados sin comprender realmente las limitaciones de la máquina puede causarle problemas.

Primero, observe cómo se necesitaría implementar una tabla de constantes en la memoria del programa. Vaya a leer la hoja de datos. No, de verdad, ve a leerlo. ¿Cómo se necesitaría hacer esto también? ¿Ve alguna forma de leer la memoria del programa, como un mecanismo de lectura de tablas que tienen algunos otros PIC? La única forma de sacar constantes de la memoria del programa es con instrucciones que contengan literales. ¿Cómo se implementa una tabla con eso? No, en realidad piensaal respecto antes de seguir leyendo. Echa un vistazo a la lista de instrucciones. La única forma de implementar una tabla de búsqueda es con la instrucción RETLW. Eso significa que básicamente realiza una llamada de subrutina a la entrada de la tabla, que devuelve el valor de esa entrada en W. Ahora mire el mecanismo de llamada de subrutina. Después de haber hecho la lectura que debe tener antes de escribir la primera línea de código, debería ser obvio por qué no puede tener más de 256 entradas de tabla con algunas de esas posibles entradas de tabla que deben usarse para el código.

Muestre que ha leído un poco la hoja de datos y puedo entrar en más detalles.

Si uno quisiera ser engañoso, creo que podría usar una tabla de 256 bytes si leyera la palabra de calibración en 0x1FF y la moviera a otro lugar, luego pusiera un GOTO en ese lugar. Luego use algo como lp: call retAddr/ retAddr: btfsc temp,7/ goto gotValue/ decfsz temp/ goto lppara forzar todas las ranuras de pila a retAddr conocido. Establecer el bit 7 tempy escribir en PCL leería un valor en W y saltaría a gotValue. No es lo que esperaría de un compilador, pero es posible.

Como los números en la LUT no son únicos, los números aumentan de forma monótona y, de hecho, los cambios parecen bastante escasos, ¿es posible escribir una pequeña función para reemplazar la LUT?

por ejemplo, y= x>=1 + x>=23 + .....

Te dejaré a ti determinar cuánta memoria, si es que hay alguna, se puede guardar de esta manera.

Quizás haya otras algs que usen técnicas dispersas que también podrían ayudar, tal vez almacenando los diferentes valores únicos y los valores de x donde ocurren las transiciones.

PIC10f202 tiene 24 bytes de RAM y 750 bytes de flash, según este resumen de Microchip. Si es posible mantener y ejecutar una tabla en flash, es posible que pueda instalar un programa pequeño utilizando el resto de la memoria del programa. Pero no veo nada en la declaración de su tabla que parezca una directiva para usar flash, y la tabla ahora tiene aproximadamente 12 veces el tamaño de la RAM disponible, incluso si no hubiera ninguna otra demanda (como la pila...) .

const unsigned char normalmente lo coloca en flash.
La LUT se declara como const. En algunos compiladores de C para PIC, esto coloca la constante en Flash. Pero no sé si esto se aplica a XC8, porque nunca lo he usado.
No, esto está mal. Usó la palabra clave CONST, que le da permiso al compilador para poner los valores en la memoria del programa (que no se puede modificar en tiempo de ejecución). Decir 750 bytes de flash es engañoso ya que las palabras de la memoria del programa no son bytes. Aún así, su lógica no se sostiene ya que esta máquina tiene 512 palabras de memoria de programa.
@olin Acepto que PUEDE estar mal, pero la palabra clave const no (según el estándar) tiene implicaciones de vinculación. Ver f/ex The C Book, sección 8.4.1, 1er párrafo, re: declarar un puerto 'const'. Si sabe que este compilador dirige constantes a ROM, un uso no estándar, aunque útil, entonces ofrecer una fuente sería algo más útil que una declaración de incorrección.
@JRobert: Como dije, CONST le da permiso al compilador para colocar los datos en la memoria de solo lectura. Por supuesto, esto es en un sistema pequeño, y este compilador usa CONST para permitirle especificar que datos van a la memoria del programa en este caso. El estándar es solo una guía aproximada para C sobre arquitecturas para las que C nunca fue diseñado, como los PIC de la arquitectura de Harvard. En sistemas tan pequeños, necesita saber qué hace realmente el compilador, no qué dice el estándar que puede o debe hacer. El hecho de que funcionó hasta 250 bytes es una prueba de que el compilador puso los datos en la memoria del programa.

No he verificado todas las entradas en la tabla, pero parece que las entradas solo cambian en 1 (después de varias entradas seguidas que son iguales). Creo que, en cambio, podría reorganizar la tabla de la siguiente manera, en la que cada tnery es el punto en el que se incrementa el valor en la tabla anterior.

const unsigned char LUT[nn] = {
0, 23, 29, 34, ...

El índice en la nueva tabla es el valor con el que habría hecho coincidir antes (ahora es una búsqueda de tabla), y el valor devuelto por la tabla es el mismo que el índice que habría estado en la tabla anterior.

Debería ser mucho más rápido, y la tabla será mucho más corta.