Forum: Mikrocontroller und Digitale Elektronik Bootloader "temporary page buffer"


von Mark (Gast)


Angehängte Dateien:

Lesenswert?

Hallo die Herren,

leider ist mein letzter Beitrag auf wenig Aufmerksamkeit gestoßen.
War zugegeben auch schon etwas unübersichtlich.

Ich würde gerne einen Bootloader in Codevison schreiben, soweit klappt 
auch alles bis auf die Befüllung des "temporary page buffers".

Zum Debuggen möchte ich nur die ersten 2 Words der ersten Page befüllen 
und ins Flash schreiben.
1
#pragma regalloc-        /* Deaktivierung der automatischen Vergabe von Adressen an Variablen*/
2
register unsigned int    daten                      @0x0002;
3
unsigned char            PAGE_BUFFER[128]           @0x008A;
4
register unsigned int    daten                      @0x0002;
5
register unsigned int    CurrentAdress              @0x0006; //CurrentAdress in Register 6 speichern      
6
#pragma regalloc+        /* Aktivierung der automatischen Vergabe von Adressen an Variablen*/
7
8
     PAGE_BUFFER[0]=0x0C; 
9
     PAGE_BUFFER[1]=0x94;
10
     PAGE_BUFFER[2]=0x68;
11
     PAGE_BUFFER[3]=0x00; 
12
13
void DO_SPM(void)
14
{
15
     #asm
16
     WAIT_SPM:
17
          in   r16,0x37;            //SPMCR in Register r16 einlesen   37= Address von SPMCR, passt für ATmega32 
18
          sbrc r16,0x01;            //Skip if Bit in Register is Cleared 
19
                                    //The SPMEN bit will auto-clear upon completion of an SPM instruction,
20
                                    //or if no SPM instruction is executed within four clock cycles. During page erase and page write,
21
                                    //the SPMEN bit remains high until the operation is completed.
22
          rjmp WAIT_SPM;
23
          out  0x37,r17;           //schreibe in SPMCR-Register und führe aus
24
          spm;
25
     #endasm
26
} 
27
28
29
void RAM_2_TEMP_PAGE(void)
30
{
31
     CurrentAdress =0;
32
     #asm ("movw r30,r6"); //move  CurrentAddress to Z pointer   
33
     
34
     daten=PAGE_BUFFER[0]+256*PAGE_BUFFER[0+1];
35
     #asm("movw  r0,r2");   //kopiert wert r3+r2 in r1+r0
36
     #asm("ldi r17,0x01");  //If only SPMEN is written, the following SPM instruction will store the value in R1:R0 in the temporary page buffer addressed by the Z-pointer.
37
     DO_SPM();   
38
     
39
     CurrentAdress =2;
40
     #asm ("movw r30,r6");
41
     daten=PAGE_BUFFER[2]+256*PAGE_BUFFER[2+1];
42
     #asm("movw  r0,r2"); 
43
     #asm("ldi r17,0x01"); 
44
     DO_SPM(); 
45
46
}

Meines Erachtens sollte das Programm nun folgendes machen:
1.) z-Pointer auf Adresse 0 setzten
2.) PAGE_BUFFER[0] und PAGE_BUFFER[1] in R0 bzw. R1 übernehmen
3.) R0 bzw. R1 in den "temporary page buffer" ab Adresse 0 schreiben
4.) zPointer auf Adresse 2 setzten
5.) PAGE_BUFFER[2] und PAGE_BUFFER[3] in R0 bzw. R1 übernehmen
6.) R0 bzw. R1 in den "temporary page buffer" ab Adresse 2 schreiben


Wenn ich nun aber nach dem Schreiben der Page den Flash Speicher auslese 
stehen die an ganz anderen Adressen. Siehe Anhang Bild1.

Ich versteh einfach nicht was ich falsch mache.
Bitte um Tipps wo der Fehler liegen könnte. Danke

von Paulchen Panther (Gast)


Lesenswert?

Welcher Controller?

von Mark (Gast)


Lesenswert?

ATmega32

von Mark (Gast)


Lesenswert?

hat den keiner nur auch einen kleinen Tipp?

von Mario G. (mario)


Lesenswert?

Hast du schon mal geschaut, ob es unter codevision eine 
bootloader-unterstützung gibt. vielleicht mußt du gar nicht alles selbst 
machen, vielleicht gibt es schon funktionen dafür.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Guck dir doch mal das Disassembler-Listing an, nicht dass dir der
Compiler irgendwas von deinen Registern wieder zerwurschtelt hat.

von Mark (Gast)


Lesenswert?

Meinst du mit Disassembler-Listing dies hier, falls ja muss ich mich 
erstmal einlesen. Davon hab ich noch wenig Ahnung.

Falls es sich beim Disassembler-Listing um etwas anders handelt bitte um 
Aufklärung.
1
;void RAM_2_TEMP_PAGE(void)
2
; 0000 017D {
3
_RAM_2_TEMP_PAGE:
4
; 0000 017E      CurrentAdress =0;
5
  CLR  R6
6
  CLR  R7
7
; 0000 017F      #asm ("movw r30,r6"); //move  CurrentAddress to Z pointer
8
  movw r30,r6
9
; 0000 0180 
10
; 0000 0181      daten=PAGE_BUFFER[0]+256*PAGE_BUFFER[0+1];
11
  LDS  R26,_PAGE_BUFFER
12
  CLR  R27
13
  __GETB1HMN _PAGE_BUFFER,1
14
  LDI  R30,LOW(0)
15
  ADD  R30,R26
16
  ADC  R31,R27
17
  MOVW R2,R30
18
; 0000 0182      #asm("movw  r0,r2");   //kopiert wert r3+r2 in r1+r0
19
  movw  r0,r2
20
; 0000 0183      #asm("ldi r17,0x01");  //If only SPMEN is written, the following SPM instruction will store the value in R1:R0 in the temporary page buffer addressed by the Z-pointer.
21
  ldi r17,0x01
22
; 0000 0184      DO_SPM();
23
  CALL _DO_SPM
24
; 0000 0185 
25
; 0000 0186      CurrentAdress =2;
26
  LDI  R30,LOW(2)
27
  LDI  R31,HIGH(2)
28
  MOVW R6,R30
29
; 0000 0187      #asm ("movw r30,r6");
30
  movw r30,r6
31
; 0000 0188      daten=PAGE_BUFFER[2]+256*PAGE_BUFFER[2+1];
32
  __GETB2MN _PAGE_BUFFER,2
33
  CLR  R27
34
  __GETB1HMN _PAGE_BUFFER,3
35
  LDI  R30,LOW(0)
36
  ADD  R30,R26
37
  ADC  R31,R27
38
  MOVW R2,R30
39
; 0000 0189      #asm("movw  r0,r2");
40
  movw  r0,r2
41
; 0000 018A      #asm("ldi r17,0x01");
42
  ldi r17,0x01
43
_0x2060001:
44
; 0000 018B      DO_SPM();
45
  CALL _DO_SPM
46
; 0000 018C 
47
; 0000 018D }
48
  RET

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Mark schrieb:

> Meinst du mit Disassembler-Listing dies hier

Ja.

Und da siehst du auch schon, wo der Pfeffer im Hasen liegt.
1
; 0000 017E      CurrentAdress =0;
2
  CLR  R6
3
  CLR  R7
4
; 0000 017F      #asm ("movw r30,r6"); //move  CurrentAddress to Z pointer
5
  movw r30,r6

Damit willst du den Z-Zeiger vorbereiten.  Du hast aber die Rechnung
ohne den Wirt, ähem, den Compiler gemacht, denn:
1
  __GETB1HMN _PAGE_BUFFER,1
2
  LDI  R30,LOW(0)
3
  ADD  R30,R26
4
  ADC  R31,R27
5
  MOVW R2,R30
6
; 0000 0182      #asm("movw  r0,r2");   //kopiert wert r3+r2 in r1+r0
7
  movw  r0,r2

... der zerpopelt dir danach deinen Z-Zeiger wieder für seine eigenen
Berechnungen.

Ich glaube, mit dieser Art Inline-Assembler bist du da aufgeschmissen,
da du dem Compiler nicht genau genug mitteilen kannst, wie sich dein
Assemblercode in die C-Umgebung einfügen soll ("constraining").
Vielleicht kannst du ja eine ganze Funktion stattdessen in Assembler
implementieren und mit dazu linken.
1
; 0000 0186      CurrentAdress =2;
2
  LDI  R30,LOW(2)
3
  LDI  R31,HIGH(2)
4
  MOVW R6,R30
5
; 0000 0187      #asm ("movw r30,r6");
6
  movw r30,r6

Mit ein paar ordentlichen constraints beim Inline-Assembler hätte man
sich auch diese Hin- und Herschubserei sparen können.

von Mark (Gast)


Angehängte Dateien:

Lesenswert?

Recht Herzlichen Danke für die Unterstützung Jörg.
Mit diesen Informationen hat es dann geklappt.
Kann jetzt prinzipiell die Daten auf die entsprechende Seite im Falsh 
schreiben.

Nun muss ich nur noch den Ablauf des Bootloaders schreiben.
Die einzelnen Funktionen funktionieren mal alle. JUHU

Anbei noch ein Foto meines ersten richtigen Mikrocontroller Projektes.
Bin ja schon ein klein wenig stolz darauf.

Bin selbst gespannt mit welchen Problem ich als nächster komme. (-:

mfg
Mark

von Mark (Gast)


Lesenswert?

Hallo die Herren,

Habe nun mit Hilfe des Beitrages:
http://www.mikrocontroller.net/articles/AVR_Bootloader_in_C_-_eine_einfache_Anleitung

den Ablauf meines Bootloaders  geschrieben.

Dies funktioniert auch alles soweit. Er empfängt die Daten, bildet 
Checksummen, schreibt die erste Flash Seite.
Danach geht es  aber nicht mehr weiter, weil er über die RS232 falsche 
Daten empfängt -> dadurch Checksummenfehler.

Nach dem Aufruf des folgendem Programmabschnitt funktioniert die 
Kommunikation nicht mehr richtig.
1
//Aufruf
2
program_page((unsigned int)flash_page, flash_data);
3
4
void program_page (unsigned long int page, unsigned char buf[SPM_PAGESIZE])
5
{
6
    unsigned char sreg;
7
 
8
    /* Disable interrupts.*/
9
      sreg = SREG; 
10
      #asm ("cli"); 
11
    
12
    //Page löschen 
13
    PAGE_ERASE (page);
14
    //Reaktivierung des RWW-Bereichs
15
    REENABLE_RWW();
16
17
 
18
    for (j=0; j<SPM_PAGESIZE; j+=2)
19
    {  
20
        daten=buf[j]+256*buf[j+1];
21
        #asm("movw  r0,r2");   //kopiert wert r3+r2 in r1+r0    
22
        CurrentAdress =j;
23
        #asm ("movw r30,r6"); //move  CurrentAddress to Z pointer
24
        #asm("ldi r17,0x01");  //If only SPMEN is written, the following SPM instruction will store the value in R1:R0 in the temporary page buffer addressed by the Z-pointer.
25
        DO_SPM();
26
    }
27
    CurrentAdress=page;
28
    PAGE_WRITE ();     /* Store buffer in flash page.    */
29
    
30
 
31
    /* Reenable RWW-section again. We need this if we want to jump back */
32
    /* to the application after bootloading. */
33
    REENABLE_RWW ();
34
 
35
    /* Re-enable interrupts (if they were ever enabled). */ 
36
    SREG = sreg; 
37
   
38
} 
39
40
41
42
void PAGE_WRITE(void)
43
{   
44
     #asm
45
          movw r30,r6;   //move  CurrentAddress to Z pointer  
46
          ldi r17,0x05;  //Bit 0 – SPMEN: Store Program Memory Enable, Bit 2 – PGWRT: Page Write
47
     #endasm
48
     DO_SPM();
49
}

Wenn ich das PAGE_WRITE (); auskommentiere,
empfängt er wieder alle Daten richtig.

Woran könnte dies liegen?

von Andreas (Gast)


Lesenswert?

Mark schrieb:
> program_page((unsigned int)flash_page, flash_data);
>
> void program_page (unsigned long int page, unsigned char buf[SPM_PAGESIZE])

Warum wird flash_page auf unsigned int gecastet, wenn die Funktion doch 
ein unsigned long int erwartet? Wieso ist flash_page nicht gleich als 
unsigned long int definiert, wenn dieser Typ nötig ist?
Hast Du geprüft, dass flash_page auch beim 2. Aufruf die richtige 
Adresse enthält? Wenn nicht, schreibst Du vielleicht irgendwo in den 
Flashspeicher, was erklären könnte, warum dein Programm anschließend 
nicht mehr funktioniert - es wurde überschrieben.

von Stefan E. (sternst)


Lesenswert?

Wo ist denn der Code von REENABLE_RWW? Ist dort ein Busy-Waiting 
enthalten?

von Mark (Gast)


Lesenswert?

1
void REENABLE_RWW(void)
2
{
3
     #asm("ldi r17,0x11");    //Bit 0 – SPMEN: Store Program Memory Enable, Bit 4 – RWWSRE: Read-While-Write Section Read Enable
4
     DO_SPM();
5
}
6
7
void DO_SPM(void)
8
{
9
     #asm
10
     WAIT_SPM:
11
          in   r16,0x37;            //SPMCR in Register r16 einlesen   37= Address von SPMCR, passt für ATmega32 
12
          sbrc r16,0x01;            //Skip if Bit in Register is Cleared 
13
                                    //The SPMEN bit will auto-clear upon completion of an SPM instruction,
14
                                    //or if no SPM instruction is executed within four clock cycles. During page erase and page write,
15
                                    //the SPMEN bit remains high until the operation is completed.
16
          rjmp WAIT_SPM;
17
          out  0x37,r17;           //schreibe in SPMCR-Register und führe aus
18
          spm;
19
     #endasm
20
}



Irgntwie verschluckt er mir 5 Zeilen aus der HEX Datei.
Nach dem Aufruf schreiben der ersten Flash Seite.

Andreas schrieb:
> Wenn nicht, schreibst Du vielleicht irgendwo in den
>
> Flashspeicher, was erklären könnte, warum dein Programm anschließend
>
> nicht mehr funktioniert - es wurde überschrieben.

Mein Bootlader Programm wird nicht überschrieben. Funktioniert auch 
weiterhin.

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.