Ограничения памяти микроконтроллера PIC

Я пытаюсь запрограммировать PIC10f202 с помощью компилятора XC8, чтобы сравнить значение таймера с переменной, которая будет функцией справочной таблицы. Вот пример кода:

#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;
        }
}

Таблица поиска составляет 250 символов, потому что это максимальный размер, разрешенный компилятором до того, как он выдал мне ошибку «Не удается найти слова x0FF (x0ff withtotal) для psect «stringtext1» в классе «Entry»». Код компилируется нормально, MPLAB X показывает 55% использования флэш-памяти и 0% использования ОЗУ. Если я изменю условие "пока" на это:

while(TMR0 > cnt1)

Компилятор снова выдаст мне аналогичную ошибку: «Не удается найти слова x0FA (x0fa withtotal) для psect «stringtext1» в классе «Entry»». Я понимаю, что компилятору не хватает памяти для написания кода, но я не понимаю, почему 45% свободного места недостаточно для этой задачи. Кроме того, почему я не могу создать массив из 255 элементов? PIC10f202 имеет 512 слов памяти, это должно быть возможно.

Почему компилятор выдает эти ошибки?

На это можно ответить фактами. Отредактировал вопрос, чтобы было понятно.
И мое мнение (и факт) в том, что выбранный вами PIC не подходит для того, что вы пытаетесь сделать. По этой же причине я отказываюсь больше использовать PIC. Создание какой-либо структуры данных размером более 16 байт слишком болезненно, и существует множество других микроконтроллеров, которые столь же недороги и гораздо более функциональны.

Ответы (4)

Это прекрасный пример того, как слепое использование компилятора в небольшой системе с ограниченными ресурсами без фактического понимания ограничений машины может привести к неприятностям.

Во-первых, посмотрите, как должна быть реализована таблица констант в памяти программы. Иди читай даташит. Нет, правда, иди читай. Как это тоже нужно сделать? Видите ли вы какой-либо способ чтения памяти программы, например, механизм чтения таблицы, который есть в некоторых других PIC? Единственный способ получить константы из памяти программы — это использовать инструкции, содержащие литералы. Как вы реализуете таблицу с этим? Нет, на самом деле думаюоб этом, прежде чем читать дальше. Взгляните на список инструкций. Единственный способ реализовать интерполяционную таблицу — использовать инструкцию RETLW. Это означает, что вы в основном выполняете вызов подпрограммы для записи в таблице, которая возвращает значение для этой записи в W. Теперь посмотрите на механизм вызова подпрограммы. После того, как вы прочитали то, что должны были сделать перед написанием первой строки кода, должно быть очевидно, почему у вас не может быть более 256 записей в таблице, причем некоторые из этих возможных записей таблицы необходимо использовать для кода.

Покажите, что вы немного прочитали техническое описание, и я смогу углубиться в подробности.

Если кто-то хочет быть хитрым, я думаю, что можно использовать 256-байтовую таблицу, если прочитать слово калибровки в 0x1FF и переместить его в другое место, а затем поставить GOTO в этом месте. Затем используйте что-то вроде lp: call retAddr/ retAddr: btfsc temp,7/ goto gotValue/ decfsz temp/ goto lp, чтобы заставить все слоты стека использовать известный retAddr. Установка бита 7 tempи запись в PCL приведет к считыванию значения в W и переходу к gotValue. Не то, что я ожидал от компилятора, но возможно.

Поскольку числа в LUT не уникальны, числа монотонно возрастают, а изменения на самом деле выглядят довольно скудно, можно ли написать небольшую функцию для замены LUT?

например, у= х>=1 + х>=23 + .....

Я оставлю это на ваше усмотрение, чтобы выяснить, сколько памяти, если таковая имеется, можно сэкономить таким образом.

Возможно, есть и другие алгоритмы, использующие разреженные методы, которые также могут помочь, возможно, сохраняя уникальные различные значения и значения x, в которых происходят переходы.

PIC10f202 имеет 24 байта оперативной памяти и 750 байт флэш-памяти, согласно этой сводке от Microchip. Если возможно сохранить и запустить таблицу во флэш-памяти, вы сможете разместить небольшую программу, используя оставшуюся часть программной памяти. Но я не вижу в объявлении вашей таблицы ничего похожего на директиву по использованию флэш-памяти, и теперь таблица примерно в 12 раз превышает размер доступной оперативной памяти, даже если к ней не было никаких других требований (таких как стек...) .

const unsigned char обычно помещает его во flash.
LUT объявляется как const. В некоторых компиляторах C для PIC это помещает константу во Flash. Но, я не знаю, относится ли это к XC8, потому что я никогда не использовал его.
Нет, это неправильно. Он использовал ключевое слово CONST, которое дает компилятору разрешение помещать значения в память программы (которую нельзя изменить во время выполнения). Заявление о 750 байтах флэш-памяти вводит в заблуждение, поскольку слова памяти программ не являются байтами. Тем не менее, ваша логика не работает, так как у этой машины 512 слов памяти программ.
@olin Я согласен, что это МОЖЕТ быть неправильным, но ключевое слово const (согласно стандарту) не имеет последствий для связи. См., например, The C Book, раздел 8.4.1, 1-й абзац, относительно объявления порта «const». Если вы знаете, что этот компилятор направляет константы в ПЗУ - нестандартное использование, однако полезное - тогда предложение исходного кода будет несколько полезнее, чем заявление о неправильности.
@JRobert: Как я уже сказал, CONST дает компилятору разрешение помещать данные в постоянную память. Конечно, это в небольшой системе, и этот компилятор использует CONST, чтобы вы могли указать, что в этом случае данные попадают в память программы. Стандарт представляет собой лишь приблизительное руководство по C для архитектур, для которых C никогда не разрабатывался, например PIC для гарвардской архитектуры. В таких небольших системах вам нужно знать, что на самом деле делает компилятор, а не то, что согласно стандарту он может или должен делать. Тот факт, что он работал до 250 байт, является доказательством того, что компилятор поместил данные в память программы.

Я не проверял все записи в таблице, но кажется, что записи меняются только на 1 (после нескольких одинаковых записей подряд). Я полагаю, что вы могли бы вместо этого реорганизовать таблицу следующим образом, где каждая точка является точкой, в которой увеличивается значение в старой таблице.

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

Индекс в новой таблице — это значение, с которым вы сопоставлялись ранее (теперь это поиск по таблице), и значение, возвращаемое из таблицы, совпадает с индексом, который был бы в старой таблице.

Должно быть намного быстрее, и таблица будет намного короче.