Forum: Mikrocontroller und Digitale Elektronik Flash Speicher beschreiben PIC12F1501


von Zerlihetzer (Gast)


Angehängte Dateien:

Lesenswert?

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)

von Stefan (Gast)


Lesenswert?

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.

von Teddy (Gast)


Lesenswert?

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.

von Jens M. (schuchkleisser)


Lesenswert?

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
von Peter D. (peda)


Lesenswert?

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.

von Zerlihetzer (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Jens M. (schuchkleisser)


Lesenswert?

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.

von Toxic (Gast)


Lesenswert?

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

von Zerlihetzer (Gast)


Angehängte Dateien:

Lesenswert?

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

von Toxic (Gast)


Lesenswert?

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.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Toxic schrieb:
> 1k sind etwas knapp wenn man mit der freien Version (keine
> C-Optimierung)von MPLABX arbeitet

dagegen gibt es Medizin/Patch!

von Jens M. (schuchkleisser)


Lesenswert?

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
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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;

von Jens M. (schuchkleisser)


Lesenswert?

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
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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.

von Jens M. (schuchkleisser)


Lesenswert?

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"...

von Peter D. (peda)


Lesenswert?

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.

von Jens M. (schuchkleisser)


Lesenswert?

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.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Jens M. (schuchkleisser)


Lesenswert?

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
von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

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.

von Toxic (Gast)


Lesenswert?

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

von chris (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.