Serie inDetail - komplexe Themen verständlich dargestellt

Lesen und Beschreiben des Flash Programmspeichers

Über SPI lässt sich sowohl das eingebaute EEPROM als auch der Programmspeicher (FLASH) beschreiben. Die Befehle dazu sind sind im Datenblatt beschrieben. Im Folgenden versuchen wir den FLASH zu beschreiben. Auf diese Weise wird dann in den folgenden Kapiteln auch das Programm übertragen.

Der Flash Speicher

Der 1K Byte FLASH des ATtiny13A ist unterteilt in 512 Speicherbereiche zu je 2 Byte. Die zusammengehörenden 2 Byte nennt man "Word". In einem Word lassen sich dann die 16 Bit Instructions (Machinecode-Befehle) der AVR Mikrocontroller speichern. Die 512 Speicheradressen lassen sich von 0-511 (0x00 -0x01FF) auswählen.

Das Programmieren des FLASH erfolgt lt. Datenblatt Pageweise. Je 16 Words werden zu einer "Page" zusammengefasst. Zuerst werden die 16 Words auf den ATtiny in einen Buffer geladen und dann mit einem anschließenden Write-Befehl zusammen in den FLASH übertragen (32 Pages je 16 Words mit jeweils 2 Byte)

Schreiben in eine Speicheradresse

Mit der Funktion loadWordToBuffer() wird ein Word (2 Byte) an einer bestimmten Stelle in ein Buffer auf dem ATtiny geladen (0-15). Der gesamte Buffer wird anschließend mit der Funktion writeBufferToFlash() in den Flash Programmspeicher geschrieben.

void loadWordToBuffer(byte pos, word data) { // Loading a Word to the ATtiny Buffer // pos = position of the word in the Page (0-15) // data = 16 bit of Data (1 word) */ // Instruction to load the Low Byte of the Word to the buffer SPI.transfer(0b01000000); SPI.transfer(0b00000000); SPI.transfer(pos); SPI.transfer(data); // Instruction to load the High Byte of the Word to the buffer SPI.transfer(0b01001000); SPI.transfer(0b00000000); SPI.transfer(pos); SPI.transfer(data >> 8); delay(1); } void writeBufferToFlash(byte pageAdr) { // Writing to prior loaded Buffer in page size to the FLASH // pageAdr = page adress to store the 16 words of the buffer (0-31) */ SPI.transfer(0b01001100); SPI.transfer(pageAdr >> 4); SPI.transfer(pageAdr << 4); SPI.transfer(0b00000000); delay(5); }

Lesen einer Speicheradresse

Mit der Funktion readFlashMemory() lässt sich eine Speicheradresse (0-511) auslesen. Der Rückgabewert der Funktion ist das bei der Adresse gespeicherte Word (16 Bit).

word readFlashMemory(int wordAdr) { // Reading a 16 bit word (one Instruction) from the FLASH // wordAdr = word address (0-511) */ // Instruction to read the Low Byte of the word SPI.transfer(0b00100000); SPI.transfer(wordAdr >> 8); SPI.transfer(wordAdr); byte lb = SPI.transfer(0x00); // Instruction to read the High Byte of the word SPI.transfer(0b00101000); SPI.transfer(wordAdr >> 8); SPI.transfer(wordAdr); byte hb = SPI.transfer(0x00); return (hb << 8) | lb; }

Programmcode

Folgendes Programm basiert auf dem Programm zu Auslesen der Signature Bytes. Ergänzt durch die drei oben gezeigten Funktionen und einen Abschnitt mit einem Löschbefehl des kompletten Flash-Speichers.

Versuchsweise wird die Flash-Speicheradresse 0, 1, 18 und 22 beschrieben. Anschließend wird zur Überprüfung der Funktionsweise der komplette Programmspeicherinhalt auf dem seriellen Monitor ausgegeben.

Info: Bei gelöschten Speicheradressen sind alle bits auf '1' gesetzt (0xFFFF).

Komplettes Programm #include #define CS 10 void setup() { Serial.begin(115200); pinMode(CS, OUTPUT); SPI.begin(); SPI.beginTransaction(SPISettings(125000, MSBFIRST, SPI_MODE0)); // Start Programming digitalWrite(CS, LOW); delay(5); digitalWrite(CS, HIGH); // Kurzer RESET Impuls lt. Datenblatt delay(1); digitalWrite(CS, LOW); delay(20); // Wartezeit lt. Datenblatt // Instruction 'Programming Enable' SPI.transfer(0b10101100); SPI.transfer(0b01010011); SPI.transfer(0b00000000); SPI.transfer(0b00000000); delay(10); // Instruction 'Chip Erase' SPI.transfer(0b10101100); SPI.transfer(0b10000000); SPI.transfer(0b00000000); SPI.transfer(0b00000000); delay(10); // Versuchsweises Schreiben in die Speicheradressen 0, 1, 18,22 loadWordToBuffer(0, 0xABCD); loadWordToBuffer(1, 0xCCCC); writeBufferToFlash(0); loadWordToBuffer(2, 0xAAAA); loadWordToBuffer(6, 0xBBBB); writeBufferToFlash(1); // Anzeigen des kompletten Flash Speichers und Pageweise (in Zeilen) Darstellung for (int a = 0; a < 512; a++) { Serial.print(readFlashMemory(a), HEX); Serial.print(" | "); if (a % 16 == 15 ) { Serial.println(); } } // Stop Programming delay(5); digitalWrite(CS, HIGH); } void loop() { } void loadWordToBuffer(byte pos, word data) { // Loading a Word to the ATtiny Buffer // pos = position of the word in the Page (0-15) // data = 16 bit of Data (1 word) */ // Instruction to load the Low Byte of the Word to the buffer SPI.transfer(0b01000000); SPI.transfer(0b00000000); SPI.transfer(pos); SPI.transfer(data); // Instruction to load the High Byte of the Word to the buffer SPI.transfer(0b01001000); SPI.transfer(0b00000000); SPI.transfer(pos); SPI.transfer(data >> 8); delay(1); } void writeBufferToFlash(byte pageAdr) { // Writing to prior loaded Buffer in page size to the FLASH // pageAdr = page address to store the 16 words of the buffer (0-31) */ SPI.transfer(0b01001100); SPI.transfer(pageAdr >> 4); SPI.transfer(pageAdr << 4); SPI.transfer(0b00000000); delay(5); } word readFlashMemory(int wordAdr) { // Reading a 16 bit word (one Instruction) from the FLASH // wordAdr = word address (0-511) */ // Instruction to read the Low Byte of the word SPI.transfer(0b00100000); SPI.transfer(wordAdr >> 8); SPI.transfer(wordAdr); byte lb = SPI.transfer(0x00); // Instruction to read the High Byte of the word SPI.transfer(0b00101000); SPI.transfer(wordAdr >> 8); SPI.transfer(wordAdr); byte hb = SPI.transfer(0x00); return (hb << 8) | lb; }
Anzeige des kompletten Flash Speicherinhaltes

Nach dem nun das Speichern des Programmcodes auf dem FLASH funktioniert, wird im folgenden Kapitel ein erstes sehr einfaches Programm entwickelt und auf den ATtiny übertragen.