Source file: /~heha/basteln/PC/FunkUsb/FunkUsb.zip/FunkUsb/ve/flash_rw.h

/*****************************************\
 * Flash-Speicher mit wahlfreiem Zugriff *
\*****************************************/
#ifndef _FLASH_RW_H_
#define _FLASH_RW_H_

/* Für ATtiny85: Die SELFPRGEN-Fuse muss gebrannt (=0) sein!
 * ATtiny haben keinen Bootloader-Bereich! (Genauer: RWW-Sektion.)
 * Daher blockiert das Flash-Schreiben immer die CPU.
 * 
 * Eignet sich durchaus für eine Art Mini-Massenspeicher im AVR.
 * Denn der Flash ist viel schneller beim Schreiben als der EEPROM.
 * Bedenke, auch die Lunte in der Hand zu haben, den Kode zu überschreiben.
 * Oder aber gezielt selbstmodifizierenden Kode zu schreiben.
 *
 * Beim Startup muss GPIOR0 Bit 6 gelöscht werden!!
 * (Dies ist das Dirty-Flag.)
 * Bei allen Routinen wird sei() vorausgesetzt.
 * Die Routinen sind (erwartungsgemäß?) nicht multithread-sicher.
 */

#include <avr/pgmspace.h>

/* Der Zugriff erfolgt solange über einen (nur einen!) Hilfspuffer im RAM,
 * bis ein anderer Sektor gelesen werden muss.
 * Somit kann man kleine Datenportionen schreiben,
 * ohne den Flash zu stark zu verbrauchen
 * Besonders bei sequenziellem Zugriff.

			┌───────┐
			│Sektor3│		RAM
			└───────┘
┌───────┬───────┬───────┬───────┬───────┬────\
│Sektor0│Sektor1│Sektor2│XXXXXXX│Sektor4│Sekt/	Flash
└───────┴───────┴───────┴───────┴───────┴────\
		FlashPtr↑

 * Man darf aber kein memcpy_P u.a. auf den infrage
 * kommenden Flash-Bereich benutzen!
 * Sondern muss flash_read() verwenden, es klammert den gerade ungültigen
 * Flash-Bereich aus und liest aus dem Hilfspuffer.
 * Oder man stellt mit flash_flush() sicher, dass der Flash ausgeschrieben ist.
 *
 * flash_write() kümmert sich automatisch um Pufferaktualisierungen
 * und kann daher für einige Millisekunden blockieren.
 * Es wird nichts unternommen, wenn sich nichts ändert!
 * Alle Arten von Überlappungen und Grenzübergängen sind erlaubt.
 *
 * flash_flush() „leert“ den Puffer (wenn gefüllt, sonst passiert nichts),
 * und blockiert in diesem Fall immer für ca. 7 ms.
 */

void flash_read(void *dst, PGM_VOID_P src, size_t len);
void flash_write(PGM_VOID_P dst, const void *src, size_t len);
void flash_flush(void);

/* Die lange Unterbrechungszeit verschlechtert die Impulslängenmessung.
 * Da ohnehin kein Hardware-Capture zur Verfügung steht,
 * sollte Timer1 den Wert von T0NT korrigieren,
 * damit wenigstens die Differenzen stimmen.
 * Daher wird von flash_write() bei Bedarf extern_flash_flush() aufgerufen.
 * Jene Prozedur muss zumindest flash_flush() aufrufen.
 */
void extern_flash_flush(void);

/* Eine Aktualisierungsroutine für den EEPROM:
 * Kann man immer wieder (gelegentlich) aufrufen,
 * um persistende Daten, die als Kopie im RAM stehen,
 * automatisch rückschreiben zu lassen.
 * Etwa für USB-HID-Feature-Reports, die Einstellungen vornehmen.
 * (Damit schafft man sich so etwas wie ein Stück ferroelektrischen RAM,
 *  der ordentlich adressierbar ist und schnell beim Schreiben ist.)
 * Liefert die Stelle in <src>, die gerade gebrannt wird.
 * NULL wenn alles gleich ist ODER gerade gebrannt wird.
 * Diese Routine blockiert nicht, im Gegensatz zu eeprom_write_block().
 */
void*eeprom_update(void*dst, const void*src, size_t len);

#endif//_FLASH_RW_H_
Detected encoding: UTF-80