Forum: Compiler & IDEs kopieren von flash-bereichen


von kosmonaut_pirx (Gast)


Lesenswert?

hallo,
besitzt jemand erfahrung im kopieren von bereichen des flash in einen 
anderen bereich? plattform ist der avr (can128)

zum problem: ich lagere programmcode in einen zwischenpuffer im flash 
aus. ist der gesamte code übertragen, erfolgt das kopieren an die 
richtige adresse, damit der code zur ausführung kommt. bisher ist dies 
noch adresse 0.
im prinzip also wie ein bootloader.

schreibe ich immer die gleiche anwendung, läuft alles bestens. nun habe 
ich aber den effekt, dass es bei änderungen des puffers (sprich: 
komplett neues programm) zu kleinen unstimmigkeiten kommt. im 
zwischenpuffer liegt das richtige programm, das habe ich überprüft. an 
die ziel-adresse verschoben liegt aber code, bei dem an festgelegten 
positionen bits gekippt sind. das betrifft einzelne halb-bytes 
mittendrin.

sowohl für das schreiben in den zwischenpuffer als auch das verschieben 
benutze ich die gleiche routine. einziger unterschied ist die quelle der 
daten. beim puffern ist dies ein bereich aus dem sram (kommt übers 
netz), beim finalen verschieben an das ziel eben das flash. für 
letzteres kommt der zugriff per pgm_read_far_byte zur anwendung.

der code der routine:
1
memcpy_p(void_ptr_t dest, void_ptr_t src, size_t len, MEM mem)
2
{
3
        uint8_t sreg;
4
        // temporary data. avr requires 16 bit for page load accesses
5
        uint8_t tmp_data[2];
6
        // aligned destination pointer 
7
        void_ptr_t aligned_dest_ptr;
8
        // supports "only" 16-bit-size of pages
9
        uint16_t i;
10
11
    // store alignment difference
12
#ifdef MEM_PGM32    
13
        aligned_dest_ptr.pgm = dest.pgm & (~((uint32_t)SPM_PAGESIZE - 1));
14
#else
15
        aligned_dest_ptr.pgm = dest.pgm & (~((uint16_t)SPM_PAGESIZE - 1));
16
#endif
17
        
18
        sreg = SREG;
19
        cli();
20
        
21
        // await eeprom to become ready
22
        eeprom_busy_wait();
23
24
   while ( len ){
25
                /* 
26
                 * in general, we have to preserve the content of the flash,
27
                 * merge with new data, erase the flash and write the merged data 
28
                 * back.
29
                 */
30
                for ( i = 0; i < SPM_PAGESIZE; i++ ){
31
                        /* 
32
                         * fill temporary buffer
33
                         * 
34
                         * TAKE CARE: during page load do NOT enabe rww-section again, 
35
                         * as this will abort page load and data will be lost!
36
                         *  
37
                         */
38
                          
39
                        // look from where to take data
40
                        if ( len && (aligned_dest_ptr.pgm >= dest.pgm)){   
41
                                // still something to read, and aligned addr in src buffer
42
                                memcpy_d((void_ptr_t)((uint16_t)&(tmp_data[i & 0x01])), 
43
                                                 src, 
44
                                                 1, 
45
                                                 mem);
46
                                // decrement copied src number
47
                                len--;
48
                                // increment src: void_ptr_inc(&src, mem);
49
                                if ( mem == MEM_PGM ){
50
                                        src.pgm++;
51
                                }
52
                                else if ( mem == MEM_DATA ){
53
                                        src.data++;
54
                                }
55
                                else{
56
                                       break;//return 1;
57
                                }
58
                        }
59
                        else{
60
                                // take data from existing memory
61
                                memcpy_d((void_ptr_t)((uint16_t)&(tmp_data[i & 0x01])), 
62
                                         aligned_dest_ptr, 
63
                                                 1, 
64
                                                 MEM_PGM);
65
                        }
66
                        // every second read fill temporary buffer for the page
67
                        if ( i & 0x01 ){
68
                                // we're already one adress ahead
69
                        boot_page_fill_safe(aligned_dest_ptr.pgm - 1, 
70
                                                                *((uint16_t*)tmp_data));
71
                        boot_spm_busy_wait();                                   
72
                        }
73
                        // increment target address
74
                aligned_dest_ptr.pgm++;
75
                }
76
                // perform erase-write-cycle
77
                boot_page_erase_safe(aligned_dest_ptr.pgm - 1);
78
                // store buffer in flash page
79
                boot_page_write_safe(aligned_dest_ptr.pgm - 1);
80
                // reenable RWW-section again. necessary, if src is in RWW-section 
81
                boot_rww_enable_safe();
82
        }
83
        // restore SREG
84
    SREG = sreg;
85
    return dest;
86
}

beispiel für ein falsche bytes:

 :2010200099F1AE014F5F5F4F6DE972E0FC01838194810E94D70F882339F566E172E0C80 
19A
---                       ^ ^                                 ^
:2010200099F1AE014F5F5F4F61E872E0FC01838194810E94D70F882339F56AEF71E0C80 
196
                          ^ ^                                 ^

entnommen aus einem hex-diff.
meine einzige vermuting ist bisher, dass vielleicht der zugriff auf das 
flash (die quelle) beim kopieren nicht ganz sauber läuft. aus dem sram 
zu schreiben funktioniert tadellos. aber so richtig kann ich's mir nicht 
erklären. auf ein anderes board gewechselt habe ich auch schon 
testweise.

möglicherweise hat jemand schon mal erfahrungen mit dem thema gemacht 
und/oder hat eine idee. für jeden hinweis bin ich extremst zu dank 
verpflichtet.

bye kosmo

von Uhu U. (uhu)


Lesenswert?

Ist dein µC schon alt? Hast du ihn schon oft neu beschrieben?

Dann sieh mal nach, wieviele Schreibzyklen der Typ verträgt - das Flash 
hält nur eine begrenzte Anzahl Schreibzyklen aus.

von kosmonaut_pirx (Gast)


Lesenswert?

hallo,
ja, beide boards und uC's sind schon etwas älter. können die fehler 
ständig an den gleichen stellen auf ein versagen des flash hindeuten?

falls ja, muss ich wohl doch nochmal die reserve aus der ecke 
rauskramen.
bye kosmo

von Uhu U. (uhu)


Lesenswert?

Wenn es immer dieselben Bits sind, ist zu vermuten, daß die den Geist 
aufgegeben haben.

von Stefan K. (_sk_)


Lesenswert?

Hast Du zufällig Interrupts während dem Flashen aktiviert) (funktioniert 
ja auch im Bootloader, wenn die Boot-Vektoren benutzt werden).

Dann kann es sein, dass die Sequenzen zum Flash-Beschreiben (selten) von 
IRs unterbrochen werden. Da zum Schreiben des Flash 2 Befehle direkt 
hintereinander (4 Zyklen) gegeben werden können, kann es passieren, dass 
ein IR genau zwischen den beiden Befehlen auftritt - damit wird der 
Schreibbefehl als ungültig erkannt und nicht ausgeführt.

Bei mir half, während den Schreib-Funktionen die IRs zu sperren:
1
  cli();
2
  boot_page_erase(..);
3
  sei();
bzw.
1
  cli();
2
  boot_page_write(..);
3
  sei();

Die Funktionen brauchen nur ein paar Takte, das Sperren der IR ist also 
unkritisch. Das warten auf Flash-ready machst Du natürlich mit IRs 
eingeschaltet.

Das hat meine Probleme mit sporadischen Flash-Fehlern komplett behoben.

Gruß, Stefan

von kosmonaut pirx (Gast)


Lesenswert?

hallo,
dass die flash bzw. die kontroller defekt sind, kann ich so gut wie 
ausschliessen. habe nun alle drei boards ausprobiert, und jedes mal den 
gleichen fehler.

wie im code oben zu sehen, sind die interrupts aus während des 
kopierens. für die übertragung übers netz verwende ich interrupts, ja, 
aber wie gesagt, die routine macht sie für die dauer aus.

was ich festgestellt habe: der fehler tritt nur auf, wenn ich eine 
kleinere anwendung aufspiele, als vorher drauf war.

anwendung 1: 11k
anwendung 2: 9k

reihenfolge: erst 2 drauf, dann 1 drauf klappt.

reihenfolge: erst 1 drauf, dann 2 drauf klappt nicht.
hierzu muss gesagt werden, dass ich "alten" code nicht lösche, nur die 
pages, die ich eben brauche. (also kein chip-erase, wie's bei avrdude 
heißt). entsprechend hängt bei fall 2 an der anwendung (und auch im 
zwischenpuffer) noch was dran. was aber nicht bestandteil des programms 
ist und dementsprechend nicht verwendet wird.

bye kosmo

von kosmonaut pirx (Gast)


Lesenswert?

ok. avrdude über stk200 kriegt das auch nicht hin ohne voriges 
chip-erase.

von kosmonaut pirx (Gast)


Lesenswert?

hm, das problem scheint tatsächlich in der 64k-grenze zu liegen.

bisher hatte ich meinen zwischenpuffer genau in der mitte der 
RWW-section gelegt. bei adresse 0xF000 beginnend. bei 11k oder 9k 
programmcode wurde da leicht die adresse 0xFFFF überschritten. beim 
lesen des puffers für das kopieren kommt es nun dazu, dass mal lpm, mal 
elpm beutzt werden muss. das scheint nicht zu klappen wie gewünscht.

habe den zwischenpuffer bei 0x4000 beginnend gelegt, so dass er immer in 
die ersten 64k fällt. mit den beschriebenen programmgrößen wird die 
64k-grenze nicht erreicht. alles funktioniert bestens.

habe den zwischenpuffer bei 0x10000 gelegt, so dass er immer in die 
zweiten 64k fällt. alles funktioniert erneut bestens.

alles wieder kehrt marsch, kommando zurück und auf 0xF000 gelegt. das 
beschriebene verhalten kehrt zurück: der zwischenpuffer wird nicht 
richtig gelesen.

staun

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.