www.mikrocontroller.net

Forum: Compiler & IDEs kopieren von flash-bereichen


Autor: kosmonaut_pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
memcpy_p(void_ptr_t dest, void_ptr_t src, size_t len, MEM mem)
{
        uint8_t sreg;
        // temporary data. avr requires 16 bit for page load accesses
        uint8_t tmp_data[2];
        // aligned destination pointer 
        void_ptr_t aligned_dest_ptr;
        // supports "only" 16-bit-size of pages
        uint16_t i;

    // store alignment difference
#ifdef MEM_PGM32    
        aligned_dest_ptr.pgm = dest.pgm & (~((uint32_t)SPM_PAGESIZE - 1));
#else
        aligned_dest_ptr.pgm = dest.pgm & (~((uint16_t)SPM_PAGESIZE - 1));
#endif
        
        sreg = SREG;
        cli();
        
        // await eeprom to become ready
        eeprom_busy_wait();

   while ( len ){
                /* 
                 * in general, we have to preserve the content of the flash,
                 * merge with new data, erase the flash and write the merged data 
                 * back.
                 */
                for ( i = 0; i < SPM_PAGESIZE; i++ ){
                        /* 
                         * fill temporary buffer
                         * 
                         * TAKE CARE: during page load do NOT enabe rww-section again, 
                         * as this will abort page load and data will be lost!
                         *  
                         */
                          
                        // look from where to take data
                        if ( len && (aligned_dest_ptr.pgm >= dest.pgm)){   
                                // still something to read, and aligned addr in src buffer
                                memcpy_d((void_ptr_t)((uint16_t)&(tmp_data[i & 0x01])), 
                                                 src, 
                                                 1, 
                                                 mem);
                                // decrement copied src number
                                len--;
                                // increment src: void_ptr_inc(&src, mem);
                                if ( mem == MEM_PGM ){
                                        src.pgm++;
                                }
                                else if ( mem == MEM_DATA ){
                                        src.data++;
                                }
                                else{
                                       break;//return 1;
                                }
                        }
                        else{
                                // take data from existing memory
                                memcpy_d((void_ptr_t)((uint16_t)&(tmp_data[i & 0x01])), 
                                         aligned_dest_ptr, 
                                                 1, 
                                                 MEM_PGM);
                        }
                        // every second read fill temporary buffer for the page
                        if ( i & 0x01 ){
                                // we're already one adress ahead
                        boot_page_fill_safe(aligned_dest_ptr.pgm - 1, 
                                                                *((uint16_t*)tmp_data));
                        boot_spm_busy_wait();                                   
                        }
                        // increment target address
                aligned_dest_ptr.pgm++;
                }
                // perform erase-write-cycle
                boot_page_erase_safe(aligned_dest_ptr.pgm - 1);
                // store buffer in flash page
                boot_page_write_safe(aligned_dest_ptr.pgm - 1);
                // reenable RWW-section again. necessary, if src is in RWW-section 
                boot_rww_enable_safe();
        }
        // restore SREG
    SREG = sreg;
    return dest;
}

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

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: kosmonaut_pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Uhu Uhuhu (uhu)
Datum:

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

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht 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:
  cli();
  boot_page_erase(..);
  sei();
bzw.
  cli();
  boot_page_write(..);
  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

Autor: kosmonaut pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: kosmonaut pirx (Gast)
Datum:

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

Autor: kosmonaut pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.