-         

Ergebnis 1 bis 2 von 2

Thema: eeprom_dump(4 pages) und Zeiten für eeprom_write/read_byte()

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    18.12.2006
    Ort
    Eberbach
    Beiträge
    199

    eeprom_dump(4 pages) und Zeiten für eeprom_write/read_byte()

    Anzeige

    Hi,

    ich habe gestern die neue Asurolib v270rc3 installiert.

    An dem Programm zum Dumpen (ausgeben) des EEPROM-Inhaltes des Asuro in ein Terminalprogramm stellte ich dann fest, daß ein einfaches NeuÜbersetzen die Anzahl der Seiten (pages), welche auf den Asuro geflashed werden, von 27 auf 17 reduzierte. Nun erwachte mein sportlicher Ehrgeiz und ich wollte es so klein wie möglich kriegen, damit EEPROM_dump.hex nicht nur ein nützliches, sondern auch ein schnelles Tool ist. Das waren die Schritte für die Größe von EEPROM_dump.hex:
    • mit Asurolib v270rc2: 27 pages
    • mit Asurolib v270rc3: 17 pages
    • nur UartPutc (ohne SerWrite): 14 pages
    • Weglassen der asuro.c im Makefile (!): 5 pages
    • weiteres tuning: 4 pages
    Weiter ging es nicht mehr, aber 4 pages sind auch schnell geflashed.

    So sieht ein Output von EEPROM_dump.hex im Terminalprogramm aus, einfach 32 Zeilen â 16 bytes hexadezimal (das EEPROM hat eine Größe von 512 bytes):
    Code:
    000102030405060708090A0B0C0D0E0F
    101112131415161718191A1B1C1D1E1F
    202122232425262728292A2B2C2D2E2F
    303132333435363738393A3B3C3D3E3F
    404142434445464748494A4B4C4D4E4F
    505152535455565758595A5B5C5D5E5F
    606162636465666768696A6B6C6D6E6F
    707172737475767778797A7B7C7D7E7F
    808182838485868788898A8B8C8D8E8F
    909192939495969798999A9B9C9D9E9F
    A0A1A2A3A4A5A6A7A8A9AAABACADAEAF
    B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF
    C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF
    D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF
    E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
    F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
    000102030405060708090A0B0C0D0E0F
    101112131415161718191A1B1C1D1E1F
    202122232425262728292A2B2C2D2E2F
    303132333435363738393A3B3C3D3E3F
    404142434445464748494A4B4C4D4E4F
    505152535455565758595A5B5C5D5E5F
    606162636465666768696A6B6C6D6E6F
    707172737475767778797A7B7C7D7E7F
    808182838485868788898A8B8C8D8E8F
    909192939495969798999A9B9C9D9E9F
    A0A1A2A3A4A5A6A7A8A9AAABACADAEAF
    B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF
    C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF
    D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF
    E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
    F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
    Als Anhang gibt es EEPROM_dump.hex.txt zum direkten Flashen (.hex ist leider keine erlaubte Dateiendung für Attachments, einfach in .hex umbenennen), hier ist der Quelltext (nicht vergessen, asuro.c im makefile auszukommentieren #SRC += asuro.c):
    Code:
    #include <avr/eeprom.h>
    
    void UartPutc (unsigned char zeichen)
    {
      UCSRB  = 0x08;                        // enable transmitter
      UCSRA |= 0x40;                        // clear transmitter flag
      while (!(UCSRA & 0x20))               // wait for empty transmit buffer
        ;
      UDR = zeichen;
      while (!(UCSRA & 0x40))               // Wait for transmit complete flag (TXC)
        ;
    }
    
    unsigned char map(unsigned char x) { return ( (x<10) ? '0'+x : 'A'+(x-10) ); }
    
    int main(void)
    {
      unsigned int u;
    
      for(u=0; u<0x0200; ++u)
      {  
        unsigned char ch = eeprom_read_byte((uint8_t*) u);
    
        UartPutc(map(ch >> 4));
        UartPutc(map(ch & 0x0F));
    
        if ((u & 0x0F) == 0x0F)
        {
          UartPutc('\r');
          UartPutc('\n');
        }
      }	
    
      while (1); 
    
      return 0;
    }
    Da die Asurolib nicht benutzt wird, mußte natürlich UartPutc(), die einzige aus der Asurolib benötigte Routine, in den Quelltext hineinkopiert werden. Hier nun die Ausgabe von avr-objdump aus dem Make-Prozeß (C-Quelltext und Assembler gemischt):
    Code:
    test.elf:     file format elf32-avr
    
    Sections:
    Idx Name          Size      VMA       LMA       File off  Algn
      0 .text         000000ce  00000000  00000000  00000094  2**0
                      CONTENTS, ALLOC, LOAD, READONLY, CODE
      1 .data         00000000  00800060  000000ce  00000162  2**0
                      CONTENTS, ALLOC, LOAD, DATA
      2 .bss          00000000  00800060  000000ce  00000162  2**0
                      ALLOC
      3 .noinit       00000000  00800060  00800060  00000162  2**0
                      CONTENTS
      4 .eeprom       00000000  00810000  00810000  00000162  2**0
                      CONTENTS
      5 .stab         000003e4  00000000  00000000  00000164  2**2
                      CONTENTS, READONLY, DEBUGGING
      6 .stabstr      000005d7  00000000  00000000  00000548  2**0
                      CONTENTS, READONLY, DEBUGGING
    Disassembly of section .text:
    
    00000000 <__vectors>:
       0:	12 c0       	rjmp	.+36     	; 0x26
       2:	2b c0       	rjmp	.+86     	; 0x5a
       4:	2a c0       	rjmp	.+84     	; 0x5a
       6:	29 c0       	rjmp	.+82     	; 0x5a
       8:	28 c0       	rjmp	.+80     	; 0x5a
       a:	27 c0       	rjmp	.+78     	; 0x5a
       c:	26 c0       	rjmp	.+76     	; 0x5a
       e:	25 c0       	rjmp	.+74     	; 0x5a
      10:	24 c0       	rjmp	.+72     	; 0x5a
      12:	23 c0       	rjmp	.+70     	; 0x5a
      14:	22 c0       	rjmp	.+68     	; 0x5a
      16:	21 c0       	rjmp	.+66     	; 0x5a
      18:	20 c0       	rjmp	.+64     	; 0x5a
      1a:	1f c0       	rjmp	.+62     	; 0x5a
      1c:	1e c0       	rjmp	.+60     	; 0x5a
      1e:	1d c0       	rjmp	.+58     	; 0x5a
      20:	1c c0       	rjmp	.+56     	; 0x5a
      22:	1b c0       	rjmp	.+54     	; 0x5a
      24:	1a c0       	rjmp	.+52     	; 0x5a
    
    00000026 <__ctors_end>:
      26:	11 24       	eor	r1, r1
      28:	1f be       	out	0x3f, r1	; 63
      2a:	cf e5       	ldi	r28, 0x5F	; 95
      2c:	d4 e0       	ldi	r29, 0x04	; 4
      2e:	de bf       	out	0x3e, r29	; 62
      30:	cd bf       	out	0x3d, r28	; 61
    
    00000032 <__do_copy_data>:
      32:	10 e0       	ldi	r17, 0x00	; 0
      34:	a0 e6       	ldi	r26, 0x60	; 96
      36:	b0 e0       	ldi	r27, 0x00	; 0
      38:	ee ec       	ldi	r30, 0xCE	; 206
      3a:	f0 e0       	ldi	r31, 0x00	; 0
      3c:	02 c0       	rjmp	.+4      	; 0x42
    
    0000003e <.do_copy_data_loop>:
      3e:	05 90       	lpm	r0, Z+
      40:	0d 92       	st	X+, r0
    
    00000042 <.do_copy_data_start>:
      42:	a0 36       	cpi	r26, 0x60	; 96
      44:	b1 07       	cpc	r27, r17
      46:	d9 f7       	brne	.-10     	; 0x3e
    
    00000048 <__do_clear_bss>:
      48:	10 e0       	ldi	r17, 0x00	; 0
      4a:	a0 e6       	ldi	r26, 0x60	; 96
      4c:	b0 e0       	ldi	r27, 0x00	; 0
      4e:	01 c0       	rjmp	.+2      	; 0x52
    
    00000050 <.do_clear_bss_loop>:
      50:	1d 92       	st	X+, r1
    
    00000052 <.do_clear_bss_start>:
      52:	a0 36       	cpi	r26, 0x60	; 96
      54:	b1 07       	cpc	r27, r17
      56:	e1 f7       	brne	.-8      	; 0x50
      58:	12 c0       	rjmp	.+36     	; 0x7e
    
    0000005a <__bad_interrupt>:
      5a:	d2 cf       	rjmp	.-92     	; 0x0
    
    0000005c <UartPutc>:
    #include <avr/eeprom.h>
    
    void UartPutc (unsigned char zeichen)
    {
      5c:	98 2f       	mov	r25, r24
      UCSRB  = 0x08;                        // enable transmitter
      5e:	88 e0       	ldi	r24, 0x08	; 8
      60:	8a b9       	out	0x0a, r24	; 10
      UCSRA |= 0x40;                        // clear transmitter flag
      62:	5e 9a       	sbi	0x0b, 6	; 11
      while (!(UCSRA & 0x20))               // wait for empty transmit buffer
      64:	5d 9b       	sbis	0x0b, 5	; 11
      66:	fe cf       	rjmp	.-4      	; 0x64
        ;
      UDR = zeichen;
      68:	9c b9       	out	0x0c, r25	; 12
      while (!(UCSRA & 0x40))               // Wait for transmit complete flag (TXC)
      6a:	5e 9b       	sbis	0x0b, 6	; 11
      6c:	fe cf       	rjmp	.-4      	; 0x6a
        ;
    }
      6e:	08 95       	ret
    
    00000070 <map>:
    
    unsigned char map(unsigned char x) { return ( (x<10) ? '0'+x : 'A'+(x-10) ); }
      70:	8a 30       	cpi	r24, 0x0A	; 10
      72:	10 f4       	brcc	.+4      	; 0x78
      74:	80 5d       	subi	r24, 0xD0	; 208
      76:	01 c0       	rjmp	.+2      	; 0x7a
      78:	89 5c       	subi	r24, 0xC9	; 201
      7a:	99 27       	eor	r25, r25
      7c:	08 95       	ret
    
    0000007e <main>:
    
    int main(void)
    {
      7e:	cf e5       	ldi	r28, 0x5F	; 95
      80:	d4 e0       	ldi	r29, 0x04	; 4
      82:	de bf       	out	0x3e, r29	; 62
      84:	cd bf       	out	0x3d, r28	; 61
      unsigned int u;
    
      for(u=0; u<0x0200; ++u)
      86:	c0 e0       	ldi	r28, 0x00	; 0
      88:	d0 e0       	ldi	r29, 0x00	; 0
      {  
        unsigned char ch = eeprom_read_byte((uint8_t*) u);
      8a:	ce 01       	movw	r24, r28
      8c:	18 d0       	rcall	.+48     	; 0xbe
      8e:	18 2f       	mov	r17, r24
    
        UartPutc(map(ch >> 4));
      90:	82 95       	swap	r24
      92:	8f 70       	andi	r24, 0x0F	; 15
      94:	ed df       	rcall	.-38     	; 0x70
      96:	e2 df       	rcall	.-60     	; 0x5c
        UartPutc(map(ch & 0x0F));
      98:	1f 70       	andi	r17, 0x0F	; 15
      9a:	81 2f       	mov	r24, r17
      9c:	e9 df       	rcall	.-46     	; 0x70
      9e:	de df       	rcall	.-68     	; 0x5c
    
        if ((u & 0x0F) == 0x0F)
      a0:	ce 01       	movw	r24, r28
      a2:	8f 70       	andi	r24, 0x0F	; 15
      a4:	90 70       	andi	r25, 0x00	; 0
      a6:	0f 97       	sbiw	r24, 0x0f	; 15
      a8:	21 f4       	brne	.+8      	; 0xb2
        {
          UartPutc('\r');
      aa:	8d e0       	ldi	r24, 0x0D	; 13
      ac:	d7 df       	rcall	.-82     	; 0x5c
          UartPutc('\n');
      ae:	8a e0       	ldi	r24, 0x0A	; 10
      b0:	d5 df       	rcall	.-86     	; 0x5c
      b2:	21 96       	adiw	r28, 0x01	; 1
      b4:	82 e0       	ldi	r24, 0x02	; 2
      b6:	c0 30       	cpi	r28, 0x00	; 0
      b8:	d8 07       	cpc	r29, r24
      ba:	38 f3       	brcs	.-50     	; 0x8a
        }
      }	
    
      while (1); 
      bc:	ff cf       	rjmp	.-2      	; 0xbc
    
    000000be <eeprom_read_byte>:
    
      return 0;
    }
      be:	e1 99       	sbic	0x1c, 1	; 28
      c0:	fe cf       	rjmp	.-4      	; 0xbe
      c2:	9f bb       	out	0x1f, r25	; 31
      c4:	8e bb       	out	0x1e, r24	; 30
      c6:	e0 9a       	sbi	0x1c, 0	; 28
      c8:	99 27       	eor	r25, r25
      ca:	8d b3       	in	r24, 0x1d	; 29
      cc:	08 95       	ret
    Wie man schön sehen kann, ist Alles recht kompakt, bis 0x5c gibt es C-Compiler-Kram, danach UartPutc(), und der Rest des Programms bis 0xbe, und angehängt eeprom_read_byte() aus der AVR-Library.


    Hier noch eine Frage an die Entwickler der Library:
    Warum klappt UartPutc() ohne Aufruf von Init() aus der Asurolib?
    Wird der Asuro etwa schon vom BootLoader auf 2400bps eingestellt?
    Der Code aus Init() wird ja gerade nicht ausgeführt:
    Code:
    ...
    void Init (
      void)
    {
      /*
        Timer2, zum Betrieb mit der seriellen Schnittstelle, fuer die
        IR-Kommunikation auf 36 kHz eingestellt.
      */
      TCCR2 = (1 << WGM20) | (1 << WGM21) | (1 << COM20) | (1 << COM21) | (1 << CS20);
      OCR2  = 0x91;                         // duty cycle fuer 36kHz
      TIMSK |= (1 << TOIE2);                // 36kHz counter
    
      /*
        Die serielle Schnittstelle wurde waerend der Boot-Phase schon
        programmiert und gestartet. Hier werden die Parameter auf 2400 1N8 gesetzt.
      */
      UCSRA = 0x00;
      UCSRB = 0x00;
      UCSRC = 0x86; // 1 Stop Bit | No Parity | 8 Data Bit
      UBRRL = 0xCF; // 2400bps @ 8.00MHz
    ...

    Last, but not least, hier noch ein Programm, welches den EEPROM-Inhalt auf ein definiertes Muster setzt:
    Code:
    #include <asuro.h>
    
    #include <avr/eeprom.h>
    
    int main (void)
    {
      unsigned int u;
      long t0,t1,t2,tmax;
      unsigned char ch;
    
      Init();
    
      tmax = 0;
      t0 = t1 = Gettime();
    
      for(u=0x0000; u<0x0200; ++u)
      {
        eeprom_write_byte((uint8_t*)u,(unsigned char)(u&0xff));
    
        t2 = Gettime();
    
        if (t2-t1>tmax)
          tmax=t2-t1;
    
        t1=t2;
      }
    
      t2 = Gettime();
    
      SerPrint("\r\naverage time for writing 1 byte to eeprom: ");
      PrintLong((1000*(t1-t0))/512);
      SerPrint("us\r\n");
    
      SerPrint("maximal time for writing 1 byte to eeprom: ");
      PrintLong(tmax);
      SerPrint("ms\r\n");
    
      ch = 0x00;
    
      t0 = Gettime();
    
      for(u=0x0000; u<0x0200; ++u)
        ch ^= eeprom_read_byte((uint8_t*)u);
    
      t1 = Gettime();
    
      SerPrint("average time for reading 1 byte from eeprom: ");
      PrintLong((1000*(t1-t0))/512);
      SerPrint("us\r\n");
    
      SerPrint("control value (should be 0): ");
      PrintInt((int)ch);
      SerPrint("\r\n");
    
      while (1);
    	
      return 0;
    }
    Das Programm bestimmt noch nebenbei die durchschnittlichen Zeiten für Lesen/Schreiben von/auf EEPROM, hier der Output von 4 Läufen:
    Code:
    average time for writing 1 byte to eeprom: 8355us
    maximal time for writing 1 byte to eeprom: 9ms
    average time for reading 1 byte from eeprom: 3us
    control value (should be 0): 0
    
    average time for writing 1 byte to eeprom: 8306us
    maximal time for writing 1 byte to eeprom: 9ms
    average time for reading 1 byte from eeprom: 3us
    control value (should be 0): 0
    
    average time for writing 1 byte to eeprom: 8308us
    maximal time for writing 1 byte to eeprom: 9ms
    average time for reading 1 byte from eeprom: 5us
    control value (should be 0): 0
    
    average time for writing 1 byte to eeprom: 8302us
    maximal time for writing 1 byte to eeprom: 9ms
    average time for reading 1 byte from eeprom: 3us
    control value (should be 0): 0
    Also Lesen eines Bytes 3-5µs, Schreiben eines Bytes 8.3ms, also mehr als 3 Größenordnungen langsamer ...


    Noch ein Tipp für die Nutzer von Hyperterminal:
    Zeilen, die nach oben aus dem Screen rausrutschen, werden zumindest in meinem Hyperterminal verunstaltet, wenn man nach oben scrolled.
    Deshalb vor Start von EEPROM_dump.hex auf dem Asuro nicht Vergessen, den Terminal-Output mittles "Transfer-->Capture Text" (habe gerade kein dt. Hyperterminal griffbereit) in eine Datei zu sichern. Hinterher "Transfer-->Capture Text-->Stop" nicht vergessen.
    Angehängte Dateien Angehängte Dateien

  2. #2
    Erfahrener Benutzer Roboter Genie Avatar von m.a.r.v.i.n
    Registriert seit
    24.07.2005
    Ort
    Berlin
    Beiträge
    1.246
    Hallo Hermann,

    sehr interessant, deine Untersuchung. Mit dem EEPROM habe ich mich bisher noch gar nicht beschäftigt.

    Zu deiner Frage (obwohle ich den Quellcode des Bootloaders nicht kenne). Ja, die UART wird bereits im Bootloader initialisiert. Muß ja so sein, sonnte würde das Flashen nicht funktionieren.

    Zur Codegröße. Das Optimum wäre es, jede Funktion einzeln in eine Datei ablegen, und daraus die LIB übersetzen. Noch kleiner geht es nur noch in Assembler. Beim weglassen der asuro.c darf man aber auch kein Sleep oder Msleep aufrufen, weil die Timer ISR auch nicht eingebunden wird.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •