PIC-Mikrocontroller-Speicherbeschränkungen

Ich versuche, einen PIC10f202 mit dem XC8-Compiler zu programmieren, um den Wert eines Timers mit einer Variablen zu vergleichen, die eine Funktion einer Nachschlagetabelle sein wird. Hier ist ein Beispielcode:

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

Die Nachschlagetabelle hat 250 Zeichen, da dies die maximale Größe ist, die vom Compiler zugelassen wurde, bevor er mir den Fehler „Can’t find x0FF words (x0ff withtotal) for psect „stringtext1“ in class „Entry““ ausgab. Der Code lässt sich gut kompilieren, wobei MPLAB X 55 % Flash-Speichernutzung und 0 % RAM-Nutzung angibt. Wenn ich die Bedingung "while" so ändere:

while(TMR0 > cnt1)

Der Compiler gibt mir wieder einen ähnlichen Fehler: "Kann x0FA-Wörter (x0fa withtotal) für psect "stringtext1" in der Klasse "Entry" nicht finden". Ich verstehe, dass der Compiler nicht genug Speicher finden kann, um den Code zu schreiben, aber ich sehe nicht, dass 45 % freier Speicherplatz für diese Aufgabe nicht ausreichen. Warum kann ich auch kein Array mit 255 Elementen erstellen? Der PIC10f202 hat 512 Worte Speicher, das sollte möglich sein.

Warum gibt der Compiler diese Fehler aus?

Es ist mit Fakten zu beantworten. Bearbeitete die Frage, um es klarer zu machen.
Und meine Meinung (und Tatsache) ist, dass der von Ihnen gewählte PIC nicht für das geeignet ist, was Sie versuchen zu tun. Das ist auch der Grund, warum ich mich weigere, PICs mehr zu verwenden. Jede Art von Datenstruktur zu erstellen, die größer als etwa 16 Bytes ist, ist zu schmerzhaft, und es gibt viele andere MCUs, die ebenso kostengünstig und viel leistungsfähiger sind.

Antworten (4)

Dies ist ein perfektes Beispiel dafür, wie die blinde Verwendung eines Compilers auf einem kleinen System mit begrenzten Ressourcen, ohne die Einschränkungen der Maschine wirklich zu verstehen, Sie in Schwierigkeiten bringen wird.

Sehen Sie sich zunächst an, wie eine Tabelle mit Konstanten im Programmspeicher implementiert werden müsste. Lesen Sie das Datenblatt. Nein, wirklich, geh und lies es. Wie müsste das auch gemacht werden? Sehen Sie eine Möglichkeit, den Programmspeicher zu lesen, wie einen Tabellenlesemechanismus, den einige andere PICs haben? Die einzige Möglichkeit, Konstanten aus dem Programmspeicher zu bekommen, sind Anweisungen, die Literale enthalten. Wie implementiert man damit eine Tabelle? Nein, eigentlich denkendarüber, bevor Sie weiterlesen. Werfen Sie einen Blick auf die Liste der Anweisungen. Die einzige Möglichkeit, eine Nachschlagetabelle zu implementieren, ist die RETLW-Anweisung. Das bedeutet, dass Sie im Grunde einen Subroutinenaufruf an den Tabelleneintrag ausführen, der den Wert für diesen Eintrag in W zurückgibt. Sehen Sie sich nun den Subroutinenaufrufmechanismus an. Nachdem Sie das gelesen haben, was Sie vor dem Schreiben der ersten Codezeile haben sollten, sollte es offensichtlich sein, warum Sie möglicherweise nicht mehr als 256 Tabelleneinträge haben können, wobei einige dieser möglichen Tabelleneinträge für Code verwendet werden müssen.

Zeigen Sie, dass Sie das Datenblatt gelesen haben und ich auf weitere Details eingehen kann.

Wenn man knifflig sein wollte, könnte man eine 256-Byte-Tabelle verwenden, wenn man das Kalibrierungswort bei 0x1FF ausliest und es an eine andere Stelle verschiebt und dann ein GOTO an diese Stelle setzt. Verwenden Sie dann so etwas wie lp: call retAddr/ retAddr: btfsc temp,7/ goto gotValue/ decfsz temp/ goto lp, um alle Stack-Slots auf bekannte retAddr zu zwingen. Das Setzen von Bit 7 von tempund das Schreiben in PCL würde dann einen Wert in W lesen und zu springen gotValue. Nicht das, was ich von einem Compiler erwarten würde, aber möglich.

Da die Zahlen in der LUT nicht eindeutig sind, die Zahlen monoton ansteigen und die Änderungen tatsächlich ziemlich spärlich aussehen, ist es möglich, eine kleine Funktion zu schreiben, um die LUT zu ersetzen?

zB y= x>=1 + x>=23 + .....

Ich überlasse es Ihnen, herauszufinden, wie viel Speicher, wenn überhaupt, auf diese Weise eingespart werden kann.

Es gibt vielleicht andere Algs, die Sparse-Techniken verwenden, die ebenfalls hilfreich sein könnten, vielleicht das Speichern der eindeutigen unterschiedlichen Werte und der Werte von x, wo die Übergänge auftreten.

PIC10f202 verfügt laut dieser Zusammenfassung von Microchip über 24 Byte RAM und 750 Byte Flash . Wenn es möglich ist, eine Tabelle im Flash zu behalten und auszuführen, können Sie möglicherweise ein kleines Programm unter Verwendung des verbleibenden Programmspeichers anpassen. Aber ich sehe in Ihrer Tabellendeklaration nichts, was wie eine Anweisung zur Verwendung von Flash aussieht, und die Tabelle ist jetzt etwa 12-mal so groß wie der verfügbare RAM, selbst wenn keine anderen Anforderungen an sie gestellt wurden (z. B. Stack ...). .

const unsigned char platziert es normalerweise im Flash.
Die LUT ist deklariert als const. In einigen C-Compilern für PIC wird die Konstante dadurch in Flash eingefügt. Aber ich weiß nicht, ob dies für XC8 gilt, weil ich es nie benutzt habe.
Nein, das ist falsch. Er hat das Schlüsselwort CONST verwendet, das dem Compiler die Berechtigung gibt, die Werte in den Programmspeicher zu stellen (der zur Laufzeit nicht geändert werden kann). Die Angabe von 750 Bytes Flash ist irreführend, da Programmspeicherwörter keine Bytes sind. Trotzdem hält Ihre Logik nicht, da diese Maschine 512 Programmspeicherwörter hat.
@olin Ich akzeptiere, dass es falsch sein kann, aber das Schlüsselwort const hat (gemäß dem Standard) keine Auswirkungen auf die Verknüpfung. Siehe z. B. The C Book, Abschnitt 8.4.1, 1. Absatz, bezüglich: Einen Port als 'const' deklarieren. Wenn Sie wissen, dass dieser Compiler Konstanten ins ROM steuert - eine nicht standardmäßige Verwendung, wie nützlich sie auch sein mag -, dann wäre das Anbieten einer Quelle etwas hilfreicher als eine einfache Deklaration der Unrichtigkeit.
@JRobert: Wie gesagt, CONST gibt dem Compiler die Erlaubnis , die Daten in den Nur-Lese-Speicher zu legen. Dies gilt natürlich für ein kleines System, und dieser Compiler verwendet CONST, damit Sie in diesem Fall angeben können, dass Daten in den Programmspeicher gehen. Der Standard ist nur ein grober Leitfaden für C auf Architekturen, für die C nie entwickelt wurde, wie die PICs der Harvard-Architektur. Auf solch kleinen Systemen müssen Sie wissen, was der Compiler tatsächlich tut, nicht, was der Standard sagt, dass er tun darf oder sollte. Die Tatsache, dass es bis zu 250 Bytes funktionierte, ist ein Beweis dafür, dass der Compiler die Daten in den Programmspeicher gelegt hat.

Ich habe nicht alle Einträge in der Tabelle überprüft, aber es scheint, dass sich die Einträge nur um 1 ändern (nach mehreren Einträgen hintereinander, die gleich sind). Ich glaube, Sie könnten stattdessen die Tabelle wie folgt neu organisieren, wobei jede Zahl der Punkt ist, an dem der Wert in der alten Tabelle erhöht wird.

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

Der Index in der neuen Tabelle ist der Wert, mit dem Sie vorher abgeglichen hätten (jetzt ist es eine Tabellensuche), und der von der Tabelle zurückgegebene Wert ist derselbe wie der Index, der in der alten Tabelle gewesen wäre.

Sollte viel schneller sein, und der Tisch wird viel kürzer sein.