Hallo Miteinander Ich zerbreche mir gerade seit Tagen den Kopf, wie ich es wohl hinkriegen könnte, einem einfach PIC, dem PIC12F1501 einen Wert im eigenen Flash zu speichern. Hintergrund: Ich habe eine kleine Schaltung (Soft-power-latch) gelayoutet, in der ein Mikrokontroller die Betriebsspannung analysiert und bei zu niedriger Spannung sich selbst und den ganzen Rest abschaltet. Schlussendlich soll es ein Tiefentladeschutz für einen Akku sein. Der einzige Taster aktiviert die Schaltung und kann sogleich vom Mikrokontroller abgefragt werden. Zur einfachen Bedienung möchte ich: -Minimalspannung einstellen und speichern. -Maximalspannung einstellen und speichern (Dient nur dazu, mit einer LED den ungefähren Akkuzustand anzuzeigen Rot<25%, 25-50%Gelb, >50% Grün) Um die Einstellungen möglichst einfach vorzunehmen habe ich mir das wie folgt vorgestellt: Man stellt mit dem Netzteil die Untere Spannungsgrenze ein und speichert diesen Wert. Dann erhöht man die Spannung zum Maximalwert und speichert den auch. Problem: Ich habe keine Erfahrung darin, den nicht flüchtigen Flash-Speicher eines Mikrokontroller zu beschreiben und zu lesen. Dem Datenblatt entnehme ich die Speicheradressen für die Flashspeicher: Seite 13: High-Endurance Flash: Memory Address Range: 0380h-03FFh (Screenshot 1) Ich weiss nicht, ob welche dieser Speicheradressen für den normalen Programmspeicher genutzt werden und ich mit einer Modifikation mein eigenes Programm ruiniere. (Screenshot 2) Die Routinen, um den Flash-Speicher zu beschreiben finden sich im Datenblatt Kapitel 10, ab Seite 79. Daraus habe ich meine Funktionen abgeleitet: 1. Unlock-Sequenz um Änderungen zu erlauben: [c] void fFlash_Unlock (void) // Funktion geprüft { PMCON2=0x55; // Notwendig PMCON2=0xAA; // Notwendig PMCON1bits.WR=1; // Ausführen NOP(); // Notwendig NOP(); // Notwendig }[c] 2. Notwendige Löschsequenz, die vor dem Beschreiben aufgerufen wird: [c] void fFlash_Clear(unsigned char address_l, unsigned char address_h) { PMADRH = address_h; // Adresse MSB PMADRL = address_l; // Adresse LSB (4letzte bit = 0000) PMCON1bits.CFGS = 0; // select the Flash address space PMCON1bits.FREE = 1; // Erase operation PMCON1bits.WREN = 1; // enable Flash memory write/erase fFlash_Unlock(); // Ausführen PMCON1bits.WREN = 0; // enable Flash memory write/erase }[c] 3. Die Funktion, mit der die Daten geschrieben werden sollen: [c] void fFlash_Write (unsigned char address_l, unsigned char address_h,unsigned char data_l,unsigned char data_h) { fFlash_Clear(address_l,address_h); PMCON1bits.CFGS = 0; // Access Flash program memory PMCON1bits.FREE = 0; // Performs a write operation on the next WR command PMCON1bits.WREN = 1; // Allows program/erase cycles PMADRH = address_h; // Adresse MSB 0b00AAAAAA A: ROW Adresse PMADRL = address_l; // Adresse LSB 0bAAAABBBB B: LATCH Adresse PMDATH = data_h; // Daten Laden 6Bit MSB PMDATL = data_l; // Daten Laden 8Bit LSB PMCON1bits.LWLO = 1; // Only the addressed program memory write latch is loaded/updated on the next WR command fFlash_Unlock(); // Ausführen PMDATH = data_h; PMDATL = data_l; PMCON1bits.LWLO = 0; // The addressed program memory write latch is loaded/updated and a write of all program memory write latches will be initiated on the next WR command fFlash_Unlock(); // Aktion ausführen*/ PMCON1bits.WREN = 0; // Schreibzugriff sperren } [c] 4. Um den Beschriebenen Speicher auszulesen: [c] unsigned int fFlash_Read(unsigned char address_l, unsigned char address_h) { PMCON1bits.CFGS = 0; // select the Flash address space PMADRH = address_h; // Adresse MSB 0b00AAAAAA PMADRL = address_l; // Adresse LSB 0bAAAABBBB (B=latch=irrelevant?) PMCON1bits.RD=1; // Lesevorgang initiieren while(RD); NOP(); NOP(); return ((PMDATH<<8)+PMDATL); //Dateien per int zurückgeben }[c] Ich bin mir ziemlich sicher, dass die Funktionen zum Lesen, Löschen und Unlock funktionieren. Wenn ich nun in der Main Schlaufe probehalber drei Adressen zu programmieren versuche: [c] unsigned int universal=0; // Opfervariable ;) fFlash_Write(0b1111000,0,255,63); fFlash_Write(0b1111100,0,255,62); fFlash_Write(0b1111010,0,255,61); universal=fFlash_Read(0b1111100,0); if(universal==16383) { LED_GN=0; } universal=fFlash_Read(0b1111100,0); if(universal==16382) { LED_RT=0; } universal=fFlash_Read(0b1111100,0); if(universal==16381) { LED_BL=0; } [c] Wird dieser Code ausgeführt, leuchtet nur die Grüne LED, um mir anzuzeigen, dass sich in ihrer Adresse der gespeicherte Wert befindet (1.Mal=erfolgreich). Werden in alle Adresse dieselben Daten geschrieben, so leuchten alle LEDs und man könnte meinen, es hätte funktioniert. Dem Aufmerksamen Leser wird nicht entgangen sein, dass ich die Datenadresse (Das LSB) in die Funktion mitgebe, als wären es die MSB. Wenn ich das umkehre und die Adressierung so vornehme, wie vom Degenblatt gefordert (LSB=0, MSB=11, das müsste die kleineste verfügbare Adresse (380h) sein) dann bleibt der Mikrokontroller in einer endlosschleife ( das grüne LED leuchtet halbstark, wird wohl dauernd ein und ausgeschalten). Ich weiss nicht, was der uP mach, aber ganz sicher nicht das, was ich von ihm will. Ich vermute, ich habe einen Fehler in der fFlash_Write-Funktion, aber ich finde in leider einfach nicht. Oder ich adressiere vollkommen falsch. Ich wäre ausserordentlich dankbar, wenn sich jemand die mühe machen würde, und mir vielleicht weiterhelfen könnte. (Die Hardware ist geprüft und funktioniert einwandfrei)
Was soll das denn werden ? Willst du Werte fest speichern die auch nach unterbrechen des Stromes noch da sind ? Wenn ja dann geht das mit diesem Pic nicht, dafür brauchst du einen Pic der ein EEprom hat.
Stefan schrieb: > Was soll das denn werden ? > Willst du Werte fest speichern die auch nach > unterbrechen des Stromes noch da sind ? > Wenn ja dann geht das mit diesem Pic nicht, dafür brauchst > du einen Pic der ein EEprom hat. Doch es geht.
Stefan schrieb: > Wenn ja dann geht das mit diesem Pic nicht Quark, dafür ist das doch da. @Zerlihetzer du kennst die AN https://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en569403 Und das Prinzip mit der Reihe hast du auch drin? Du musst immer 16 Bytes auf einmal löschen und beim schreiben afaik auch komplett schreiben, btw. auch nur das L-Byte für den HEF-Teil. Zum testen ein ICD hast du nicht zufällig? Edit: außerdem ist mir aufgefallen, das du zweimal unlockst. Bei nur einem Bytewrite reicht LWLO1-PMDAT-LWLO0-unlock, zumindest bei meinen Versuchen damals Unlock löst ja den Schreibvorgang aus, je nach LWLO eben ins Latch oder echt. Und: es gibt de "high" und "low"-operator, damit kannst du die Adresse in 16-Bit angeben und trotzdem 2x8bit laden. Ist einfacher zu lesen.
:
Bearbeitet durch User
Wenn man es sich einfach machen will, nimmt man einen MC mit Daten-EEPROM, z.B. ATtiny25. Da kann man auf jedes Byte direkt schreiben und es wird automatisch gelöscht. Man kann dann auch festlegen, daß der EEPROM bei einem FW-Update nicht mit gelöscht wird. Bei Flash muß man vorher immer eine ganze Page löschen. Als Adresse nimmt man irgendwas hinter dem Programm, z.B. die letzte Page des Flash. Der MC muß außerdem IAP (in application programming) unterstützen. Nur mit den LEDs wirst Du nicht weit kommen. Zum Debuggen nimm irgendwas, mit dem man Text und Zahlen ausgeben kann, z.B. ein Text-LCD oder eine SW-UART. Notfalls kann man auch mit dem Programmer den Flash zurücklesen.
Hallo und danke schonmal für die Hinweis =D Ich bitte um Entschuldigung, dass ich oben den Code falsch eingebunden habe. @Stefan: Genau, ich möchte zwei Spannungswerte (also 10Bit) im nicht flüchtigen Speicher Ablegen. Gemäss Datenblatt soll das auch gehen, zumindest gehe ich davon aus, weil folgendes auf Seite 1 zu finden ist: Memory: • 1 Kwords Linear Program Memory Addressing • 64 bytes Linear Data Memory Addressing • High-Endurance Flash Data Memory (HEF) - 128 bytes if nonvolatile data storage - 100k erase/write cycles @Jens M.: Ja, damit habe ich mich auch länger auseinandergesetzt und habe versucht nachzuvollziehen was dort genau passiert. (PIC10_PIC12_HEFlash.c / PIC10_PIC12_HEFlash.h / Example_main.c) Wenn ich mit dieser Funktion versuche daten zu schreiben / lesen erhalte ich nicht die gewünschten Resultate (Ich bin mir bewusst, dass mein «debuggen» mit 3 Leds Mist ist, aber ich wüsste wenigstens ob’s funktionieren täte.) Zum Löschen, ich glaube da haben Sie einen wunden Punkt getroffen, den ich nicht ganz verstanden habe. Ich dachte, es ist im mindestens eine einzelne Zeile (Row) zu löschen. Sie schreiben 16Bytes, das wäre ja 16 x 8Bit korrekt? Gemäss meiner Interpretation des Datenblatts handle ich den Löschprozess wie folgt ab, aber nur eine Zeile (Row) mache ich hier meinen Fehler, lösche ich zu wenig, oder löscht es mehr, als ich annehme?:
1 | void fFlash_Clear(unsigned char address_l, unsigned char address_h) |
2 | {
|
3 | PMADRH = address_h; // Adresse 6 MSB |
4 | PMADRL = address_l; // Adresse 2 LSB (4letzte bit = 0000) |
5 | PMCON1bits.CFGS = 0; // select the Flash address space (nicht Konfiguration ändern) |
6 | PMCON1bits.FREE = 1; // Erase operation (Es ist ein Löschzyklus) |
7 | PMCON1bits.WREN = 1; // enable Flash memory write/erase (Aktion legitimieren) |
8 | fFlash_Unlock(); // Ausführen |
9 | PMCON1bits.WREN = 0; // disable Flash memory write/erase (zugriff verweigern) |
10 | }
|
Zum Schreiben: Da ich zweimal 10Bit schreiben möchte, habe ich mir gedacht, würde ich einfach zwei Zeilen (Row) beschreiben, und die überzähligen offenlassen (Performance ist das sicher nicht, hier aber egal) Müssen denn die oberen Bits explizit gelöscht werden? Wenn ich die Register mit den Daten zum schreiben Fülle <PMDATH&PMDATL> und ich nur eine 1 schreiben will ist es doch ausreichend, wenn ich schreibe:
1 | PMDATH=0; |
2 | PMDATL=1; |
Die Unlock-Sequenz führe ich absichtlich zweimal aus, weil das Degenblatt dies so vorgibt. Das erste Mal um das Latch Register zu laden, und das zweite mal um sie vom Latch ins Flash zu schreiben. Hier der Auszug: Load the PMADRH:PMADRL register pair with the address of the location to be written. 5. Load the PMDATH:PMDATL register pair with the program memory data to be written. -> 6. Execute the unlock sequence The write latch is now loaded. 7. Increment the PMADRH:PMADRL register pair to point to the next location. 8. Repeat steps 5 through 7 until all but the last write latch has been loaded. (Diese Schlaufe erspare ich mir, da ich nur eine Row schreiben möchte) 9. Clear the LWLO bit of the PMCON1 register. When the LWLO bit of the PMCON1 register is ‘0’, the write sequence will initiate the write to Flash program memory. 10. Load the PMDATH:PMDATL register pair with the program memory data to be written. -> 11. Execute the unlock sequence The entire program memory latch content is now written to Flash program memory. Können Sie mir weiterführende Informationen bezüglich dem "high" und "low"-operator zukommen lassen? Das Thema kenne ich noch nicht. Bei diesem PIC ist die Adresse zum Speicherort ja in den Registern <PMADRL & PMADRH> zu finden, wobei das Low-Register vollwertig alle 8Bit beinhaltet und das obere H-Register nur 5Bit. Vom Low-Register gehen im übrigen 4 für die Latch-Adressen drauf, und eins ist einfach nicht genutzt, wenn ich das richtig sehe (was irgendwie seltsam ist). @Peter D. Ja, wenn ich im Vornhinein schlauer gewesen bin, hätte ich auf EEPROM geachtet, damit habe ich schon gute Erfahrungen gemacht. IAP ist nehme ich an ein Synonym zu ICSP? (Ich habe bisher nur mit Pics gearbeitet). Und wie es scheint komme ich nicht ums Debuggen rum, mal sehen ob ich das mit dem PicKit hinbekomme. Bezüglich der Speicheradresse: Soll ich da grundsätzlich die Letzen möglichen verwenden? Also diejenigen am ende der vorgeschlagenen Auswahl im Datenblatt Seite 13, das Wäre 03FFh Oder wäre das Ende des Programmspeichers besser geeignet, also die Adresse 3FFh. Wobei es mich irritiert, das MPLABX anzeigt, dass es den Speicher von unten her beschreibt (Siehe Screenshot). Danke euch allen für die Kommentare.
Zerlihetzer schrieb: > Ich dachte, es ist im mindestens eine > einzelne Zeile (Row) zu löschen. Sie schreiben 16Bytes, das wäre ja 16 x > 8Bit korrekt? 16 Words, weil das Latch 16 Words breit ist. Ist im Dabla eigentlich toll zu sehen, schön als Diagramm aufgemalt. Zerlihetzer schrieb: > Zum Schreiben: Da ich zweimal 10Bit schreiben möchte, habe ich mir > gedacht, würde ich einfach zwei Zeilen (Row) beschreiben Warum nicht zwei aufeinanderfolgende Words? Dürfte einfacher zu adressieren sein. Technisch isses egal, ja. Du kannst eh nur das untere Byte eines Words nutzen, denn HEF besteht immer auf 8Bit HEF und das HByte ist normaler Flash, den solltest du auf FF lassen. Zerlihetzer schrieb: > Die Unlock-Sequenz führe ich absichtlich zweimal aus, weil das > Degenblatt dies so vorgibt. Das Ablaufdiagramm biegt bei nur einem Byte vorher ab, der Unlock kommt erst wenn man ein weiteres Byte latchen will. Kann mich aber nicht mehr erinnern, ist ewig her das ich das getestet habe. Der "Stall" während der Zugriff war für mich kritisch, daher ist ein I²C-EEPROM dran. Zerlihetzer schrieb: > Können Sie mir weiterführende Informationen bezüglich dem "high" und > "low"-operator zukommen lassen? Manual zum Assembler/Compiler. x=low(word) liefert das Lowbyte, x=high(word) das Highbyte. Ist keine echte Funktion sondern ein Assemblermakro, d.h. für direkt übergebene Adressen spart's dir das rechnen. Zerlihetzer schrieb: > Vom Low-Register gehen im > übrigen 4 für die Latch-Adressen drauf Jein. Der Speicher wird halt in 16-Word breite Rows geteilt, und wenn du in den unteren 4 bit ein bestimmtes Word ansprichst, ist das eben ein Word einer Row. Zerlihetzer schrieb: > eins ist einfach nicht > genutzt, wenn ich das richtig sehe What? ADRH/ADRL ist ein 13-bit breiter Zugriff, so wie der PC auch. Zerlihetzer schrieb: > Also diejenigen am ende der vorgeschlagenen Auswahl > im Datenblatt Seite 13, das Wäre 03FFh > Oder wäre das Ende des Programmspeichers besser geeignet, also die > Adresse 3FFh. Wo ist der Unterschied 3FF zu 3FF? ;) Und ja, von hinten anfangen ist besser, denn von vorne kommt dein Programm. Hast du kein Org oder so? Meine Programme fangen bei 0 an, da ist ja auch der Reset und Interruptvektor.
Zerlihetzer schrieb: > Ich zerbreche mir gerade seit Tagen den Kopf, wie ich es wohl hinkriegen > könnte, einem einfach PIC, dem PIC12F1501 einen Wert im eigenen Flash zu > speichern. Ich hab hier einen PIC12F1501 habe abe noch nie den Flash memory als EEpromersatz benutzt.Mir ging es lediglich um den NCO..... Vielleicht hilft dir das hier weiter: https://microchipdeveloper.com/tip:22 Application Note AN1673
Heureka! Es hat funktioniert! Vielen Lieben Dank Jens M. und Toxic!!! Ich war schon das ganze Wochenende am Verzweifeln und hab schon nicht mehr daran geglaubt, das ich das mit meinem bescheidenen Intellekt doch noch hinbekomme. DANKE! Ich habe bislang geglaubt, dass die Speichermatrix aus Zeilen und Reihen nur einzelne Bits beinhaltet. Das habe ich falsch interpretiert! Nun habe ich meine Funktionen so abgeändert, dass ich nur das LOW-Byte schreibe und auslese, da man ja das obere gescheiterweise in Ruhe lässt. So kann man ein Byte speichern und erfolgreich auslese. Ich bin zwar noch ein wenig im Ungewissen, warum es nicht mehr funktioniert, wenn wie vorhin noch die MSB dazukommen, aber vorab reicht mir das. Wie auch immer. Sollte später mal jemand mit demselben Problem auf diese Forenseite Treffen, hier das Erarbeitete: Funktionen:
1 | /******************************************************************************/
|
2 | /* Speicherfunktionen */
|
3 | /******************************************************************************/
|
4 | void fFlash_Unlock (void) |
5 | {
|
6 | PMCON2=0x55; |
7 | PMCON2=0xAA; |
8 | PMCON1bits.WR=1; |
9 | NOP(); |
10 | NOP(); |
11 | }
|
12 | |
13 | void fFlash_Clear(unsigned char address_l, unsigned char address_h) |
14 | {
|
15 | PMADRH = address_h; // Adresse MSB |
16 | PMADRL = address_l; // Adresse LSB |
17 | PMCON1bits.CFGS = 0; // select the Flash address space |
18 | PMCON1bits.FREE = 1; // Erase operation |
19 | PMCON1bits.WREN = 1; // enable Flash memory write/erase |
20 | fFlash_Unlock(); // Ausführen |
21 | PMCON1bits.WREN = 0; // enable Flash memory write/erase |
22 | }
|
23 | |
24 | void fFlash_Write (unsigned char address_l,unsigned char address_h, unsigned char data_l) |
25 | {
|
26 | |
27 | fFlash_Clear(address_l,address_h); |
28 | PMCON1bits.CFGS = 0; // Access Flash program memory |
29 | PMCON1bits.FREE = 0; // Performs a write operation on the next WR command |
30 | PMCON1bits.WREN = 1; // Allows program/erase cycles |
31 | PMCON1bits.LWLO = 1; // Only the addressed program memory write latch is loaded/updated on the next WR command |
32 | PMADRL = address_l; // ADRESSE LSB |
33 | PMADRH = address_h; // ADRESSE LSB |
34 | PMDATL = data_l; |
35 | PMCON1bits.LWLO = 0; // The addressed program memory write latch is loaded/updated and a write of all program memory write latches will be initiated on the next WR command |
36 | fFlash_Unlock(); // Aktion ausführen |
37 | PMCON1bits.WREN = 0; // Schreibzugriff sperren |
38 | }
|
39 | |
40 | unsigned int fFlash_Read(unsigned char address_l, unsigned char address_h) |
41 | {
|
42 | PMCON1bits.CFGS = 0; // select the Flash address space |
43 | PMADRH = address_h; // |
44 | PMADRL = address_l; // |
45 | PMCON1bits.RD=1; // Lesevorgang initieren |
46 | while(RD); |
47 | NOP(); |
48 | NOP(); |
49 | return PMDATL; |
50 | }
|
Ein Beispiel um zu Schreiben und lesen:
1 | fFlash_Write(0xff,0xfe,10); // Schreiben: in die Zeile definiert per Adresse MSB, LSB, den Wert 10 (dezimal) |
2 | universal=fFlash_Read(0xff,0xfe); // Lesen: Die Variabel universal erhält die Gespeicherten Werte der Adressen (MSB, LSB) |
Bei der Adressenvergabe ist folgendes zu beachten: Der Programmspeicher besteht aus einer Matrix aus Zeilen und spalten. In jeder Zelle hat ein Byte Platz (eigentlich noch mehr, aber das wird hier nicht genutzt). Die Zeilen werden durch die Register PMADRH und PMADRL adressiert. Hierfür ist das schöne Diagramm auf Seite 86 hilfreich. Alle Bits von PMADRH, also <MSB7...0> und 4Bit von PMADRL <7...4LSB> ergeben die Zeilenadresse. Die Spalte wird mit den verbleibenden Bits von PMADRL <3...0> definiert. Wichtig: Beim Speichern wird immer die gesamte Zeile gelöscht. (Das könnte insofern wichtig sein, wenn mehrere Zellen in einer Zeile beschrieben sind/werden). Letzen Endes muss sichergestellt sein, dass der Programmspeicher nicht vom üblichen Programm genutzt wird. Hierfür kann in den Projekteinstellungen eine Speicherreservierung vorgenommen werden, siehe Screenshot. Liebe Grüsse Zerlihetzer
Zerlihetzer schrieb: > Wie auch immer. Sollte später mal jemand mit demselben Problem auf diese > Forenseite Treffen, hier das Erarbeitete: Ich werde mir das auch mal zu Gemuete fuehren.Hatte bisher nur noch nie einen Grund gehabt Programm-Flashspeicher zu benutzen,da mir die EEpromkapazitaeten immer ausreichten. Der Pic PIC12F1840 waere fuer dich wahrscheinlich die bessere Loesung gewesen.Hat 4k-Speicher (statt 1k im Pic12f1501) und 256 EEprom bytes. 1k sind etwas knapp wenn man mit der freien Version (keine C-Optimierung)von MPLABX arbeitet.Solange dein Code ueberschaubar klein bleibt(keine Displayansteuerung etc..) sind die 1k allerding ausreichend.
Toxic schrieb: > 1k sind etwas knapp wenn man mit der freien Version (keine > C-Optimierung)von MPLABX arbeitet dagegen gibt es Medizin/Patch!
Zerlihetzer schrieb: > Die Spalte wird mit den verbleibenden Bits von PMADRL <3...0> definiert. > Wichtig: Beim Speichern wird immer die gesamte Zeile gelöscht. Und genau dewegen ist es pures Glück, das deine Routine zum Schreiben so funktioniert. Du speicherst ein Byte in den Latches und schreibst die ganze Row. Dann speicherst du ein anderes Byte in einem anderen Latch und schreibst wieder die ganze Row, nachdem du sie gelöscht hast. Das verschleißt dir zum einen die Zellen, da du für jeden Write eines Bytes die ganze Row löscht und wieder neu beschreibst, zum anderen ist es pures Glück, das die Latches den Wert des anderen Bytes der Row noch beinhalten. Wenn du zwei Rows bedienst, bekommst du Kauderwelsch raus! Also - Row löschen - 1-16 Byte zusammensuchen - Row schreiben Wenn du ein Byte (über-)schreiben willst, musst du - erst die ganze Row lesen - ein Byte ändern - die Row wieder schreiben aber da gilt das oben gesagte. Außerdem solltest du das H-Byte der Daten in deiner Funktion auf FF setzen, damit die Zellen nicht so gestresst werden. Jetzt ist es undefiniert, nicht schön.
:
Bearbeitet durch User
Zerlihetzer schrieb: > void fFlash_Unlock (void) > { > PMCON2=0x55; > PMCON2=0xAA; > PMCON1bits.WR=1; > NOP(); > NOP(); > } ... die zwei nop() sind fragwürdig, weil der PIC die NOPs selber forced und durchführt, besser ist das WR Flag abzufragen. Also PMCON2=0x55; PMCON2=0xAA; WR = 1; while(WR); WREN = 0;
Falsch! Die beiden Instruktionen nach dem WR=1 werden als NOP ausgeführt, egal was da steht, erst die dritte Speicherstelle nach dem WR=1 wird wieder normal ausgeführt. Zumindest lese ich den Text "NOP instructions are forced as processor starts row erase of program memory. The processor stalls until the erase process is complete, after erase processor continues with 3rd instruction" so. Gleiches gilt für Write. Das "2 Takte nix und dann fortsetzen ab der 3. Instruktion" ist per design, ein While ist da sinnlos, denn der Prozessor steht so lange der Write (in ms, nicht Takten) dauert. Dein While könnte 2 Instruktionen lang sein, je nach Compiler, dann würde es nie ausgeführt. Ist es länger oder kürzer, gibt's Chaos.
:
Bearbeitet durch User
Jens M. schrieb: > Die beiden Instruktionen nach dem WR=1 werden als NOP ausgeführt, egal > was da steht, erst die dritte Speicherstelle nach dem WR=1 wird wieder > normal ausgeführt. Guter Punkt, habe genauer nachgelesen und denke du hast recht. ... ich habe C Source Code von Microchip, wo die das dann echt falsch machen.
Deine Methode ist der Standard für EEPROM-Write. HEF ist ja Programmspeicher, d.h. während des Zugriffs ist der Prozessor definitiv nicht lauffähig, selbst Lesend muss er einfach warten. Aber eben "ich weiß nicht das ich warte, weil ich keinen Takt bekomme" nicht "ich warte bis ein Flag kommt und dreh so lange Däumchen"...
Jens M. schrieb: > "NOP instructions are forced as processor > starts row erase of program memory. The processor stalls until the erase > process is complete, after erase processor continues with 3rd > instruction" Wer denkt sich denn blos sowas verrücktes aus. Ich vermute mal, das ist ein Bugfix. Der PIC kann sich wohl je nach CPU-Takt nicht so richtig entscheiden, wann er mit dem Flashen eigentlich anfängt. Daher gibt man ihm 2 Takte zum Nachdenken. Die AVRs ohne Bootsektion halten auch an, machen dann aber normal mit dem nächsten Befehl weiter. Die AVRs mit Bootsektion müssen das Ready-Bit abwarten, ehe sie wieder in die Applikation springen dürfen.
Das hat mit der 4-Taktigen Pipeline zu tun, er weiß erst beim 3. Takt was da los ist, und die Schreib/Lese-Mimik nutzt den normalen Programmablaufleser, d.h. die Pipeline wird teilweise zerstört.
Ich finde, das "Böse" an High-Endurance Flash ist, dass dieser zum Program Flash Adressbereich dazu gehört und daher bei Benutzung den Programbereich reduziert - was bei kleinen PIC mit 0.5/1K weh tut.
Peter D. schrieb: > Wenn man es sich einfach machen will, nimmt man einen MC mit > Daten-EEPROM, z.B. ATtiny25. Du nervst mit deinem ständigen "nimm AVR". Und dir ist es bloß noch nicht aufgefallen, daß es seit rund 20 Jahren oder noch länger PIC's gibt, die EEPROM drin haben. Aber manchmal muß es wegen irgend einer Spezialität eben ein bestimmter PIC sein und wenn dieser kein EE drin hat, dafür aber Daten im Flash ablegen kann, dann ist es ja auch OK - solange man nicht darauf so oft herumhackt wie ein Raspberry auf der SD-Karte. Der EE bei den PIC's hält nämlich weitaus mehr Schreib- und Lösch-Vorgänge aus als der Flash. W.S.
W.S. schrieb: > Der EE bei den PIC's hält nämlich weitaus mehr Schreib- und > Lösch-Vorgänge aus als der Flash. HEF immerhin 100k, normales Flash 10k, EE allerdings 1Mio. Spart halt die zusätzlichen Teile (und Fertigungsschritte?) für die wenigen Fälle in denen jemand eine Konfig abspeichern will in so einem kleinen Ding. Und dank SelfWrite kann man endlich einen Bootloader mit reinmachen ;) Damit man mal einen Maßstab bekommt: 10k heißt 1x pro Minute für knapp eine Woche und das war's.
:
Bearbeitet durch User
W.S. schrieb: > Du nervst mit deinem ständigen "nimm AVR". Du nervst mit deinen PICs, Debugger gehate und deiner Lernbetty. Im Gegensatz zu dir kommen vom Peda gute Libs und gute Tipps.
W.S. schrieb: > Du nervst mit deinem ständigen "nimm AVR". Mw E. schrieb: > W.S. schrieb: >> Du nervst mit deinem ständigen "nimm AVR". > > Du nervst mit deinen PICs, Debugger gehate und deiner Lernbetty. > Im Gegensatz zu dir kommen vom Peda gute Libs und gute Tipps. Nun ganz so unrecht hat W.S. nicht: @PeDa's Wissen steht ausser Frage aber speziell in diesem Thread kann man davon ausgehen ,dass der TO ein PicKit3 und sich schon laengst mit MPLABX vertraut gemacht hat. Da macht ein AVR-uc keinen Sinn,ausser der TO will lernen wie man auf 2 Gaeulen gleichzeitig reitet
Was auffällt ist, dass du beim Write keine Latches verwendest.
1 | while (--count) FLASH_write (add++, ~((unsigned) *data++), 1); FLASH_write (add, ~((unsigned) *data), 0); // NOTE: 2ms typ. delay here!!! return PMCON1bits.WRERR ; // 0 = success ; 1 = write erro |
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.