Suche Hilfe bei Optimierung Bootloader

#4144940
Lesenswert?

Hallo,

ich habe mir einen Bootloader geschrieben, der soweit prima 
Funktioniert.
Nur verbraucht er die vollen 2k und ich könnte etwas mehr Flash fürs 
Programm brauchen. Daher mal eine Bitte, ob ihr drüber sehen könntet und 
mir sagen, wo man optimieren könnte.

Plattform ist ein ATmega32 mit avr gcc.

Das Protokoll ist vorgegeben und nicht veränderbar!
Alle Daten werden als ASCII übertragen, eine Zahl 0x01 also als "01" und 
somit 2 char.

Das ganze läuft ohne Interrupts (Deaktiviert)

Der Bootloader kann direkt vom Programm oder beim Start des Controllers 
aufgerufen werden. Die Unterscheidung mache ich über die Reset source.

Ist es ein boot nach einem Normalen Reset, prüfe ich die Programm 
Checksumme (steht im EEPROM) und führe das Programm aus, sofern diese ok 
ist, sonst bleibe ich im Bootloader.

Protokoll ist erstes Zeichen "@", dann Empfänger Adresse, sender Adresse 
und dann Kommando mit ggf. Nutzdaten

"@017FT?\r" Frägt zum Beispiel die Modul Version ab.

Achja, fehlende Defines kommen aus dem Makefile, wie "MODULE_ID", was 
einfach "1001" ist.

Kommandos, des Bootloaders, jeweils ohne "@" und Adressen. Diese kann 
man man hier als Beispiel immer mit "@017f" annehmen.

T? => liefert Modul Typ, zur Erkennung der Firmware
RT => Löst einen Reboot per Watchdog aus
BT => schickt page size (0x80 beim ATMega32)
BP => springt direkt ins Programm
BLnnMMMMMMMOOOO => Daten zum schreiben, nn = Anzahl Bytes (nicht 
Zeichen), MM = Daten, OOOO = CRC Summe der Daten
BSnnnnMMMM => Daten Transfer Start, nnnn = ID der Firmware, muss mit 
modul ID übereinstimmen, MMMM = Anzahl Bytes die kommen

Wäre über Tipps echt Dankbar.

Gruss
Juergen

Linker Zeile
1
avr-gcc -mmcu=atmega32 -I.  -MD -MP -MF .dep/bootloader.elf.d -D_TYPE_1001_="1001" -D_HAS_I2C_="_HAS_I2C_" -DMODULE_TYPE="1001" -DMODULE_ID=0x1001 -DF_CPU=16000000UL -DBOOTLOADER_ADR=0x7000 -DMODULE_VERSION=\"0.2.1\" -DADDR_PC_DEF=127 -DADDR_TX_LCD_DEF=102 -DADDR_TX_MAIN_DEF=101  -DADDR_RX_MAIN_DEF=1 -DADDR_BROADCAST_DEF=0 -DMY_DEF_ADDR=1 -DADDR_DEBUG_RS232_DEF=99 -DMAX_FUNC_CNT=32 -std=gnu99 obj/bootloader.o obj/addr_list.o --output bootloader.elf -Wl,-Map=bootloader.map,--cref -Ttext=0x7000

Und der Quellcode des Bootloaders
1
/**
2
 * The common bootloader for RX and TX
3
 */
4

5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
#include <avr/pgmspace.h>
8
#include <avr/eeprom.h>
9
#include <avr/boot.h>
10
#include <stdlib.h>
11
#include <string.h>
12
#include <util/crc16.h>
13
#include <avr/wdt.h>
14

15
#include "../global_files/avr_helper.h"
16

17
#if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
18
#warning "compiling mega32"
19
#define RESET_SOURCE_MASK (_BV(JTRF)|_BV(WDRF)|_BV(BORF)|_BV(EXTRF)|_BV(PORF))
20
#elif _TYPE_1003_
21
#warning "compiling mega328(p)"
22
#define RESET_SOURCE_MASK (_BV(WDRF)|_BV(BORF)|_BV(EXTRF)|_BV(PORF))
23
#elif _TYPE_1006_
24
#warning "compiling mega1284p"
25
#define RESET_SOURCE_MASK (_BV(WDRF)|_BV(BORF)|_BV(EXTRF)|_BV(PORF))
26
#else
27
#error "This code is not yet done for this module type"
28
#endif
29

30
char rxbuffer_boot[SPM_PAGESIZE*2+20]; // This is a hughe array, but we are in the bootloader and have all for us
31
char txbuffer[40];
32
uint16_t rxpos_boot = 0;    // anzahl empfangener Zeichen
33
uint8_t txpos = 0;    // anzahl zu sendender Zeichen
34
uint8_t txspos =  0;  // nächstes zu senden
35
uint8_t myAddress = MY_DEF_ADDR;  // unsere Adresse
36
uint32_t page = 0;
37
uint16_t crc = 0;
38
uint16_t shouldCrc = 0;
39

40
/**
41
 * The different states of the bootloader
42
 */
43
enum
44
{
45
    BOOT_CMD = 1,
46
    BOOT_DATA,
47
    BOOT_CHK
48
};
49

50
#define PROGMEM_CRC_ADDR 0x0000
51

52
void (*startMainApp)( void ) = 0x0000;        /* Funktionspointer auf 0x0000 */
53

54
/*
55
FUSES =
56
{
57
    .low = 0xFF, // 0xff
58
    .high = ( FUSE_EESAVE & FUSE_SPIEN & FUSE_CKOPT & FUSE_BOOTSZ1 & FUSE_BOOTSZ0 ) // 0xc1
59
};
60
*/
61
#if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
62
FUSES =
63
{
64
    0xFF,
65
    ( FUSE_EESAVE & FUSE_SPIEN & FUSE_CKOPT & FUSE_BOOTSZ1 & FUSE_BOOTSZ0 ) // 0xc1
66
    //EFUSE_DEFAULT
67
};
68
#elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
69
FUSES =
70
{
71
    0xFD,
72
    ( FUSE_EESAVE & FUSE_SPIEN & FUSE_BOOTSZ1 & FUSE_BOOTSZ0 ), // 0xc1
73
    0xFF
74
    //EFUSE_DEFAULT
75
};
76
#endif
77
void ( *bootloader ) ( void ) = (void(*)(void))0x3800;
78

79

80
/**
81
 * converts AH to uint8_t value
82
 */
83
uint8_t ahtoUint8 ( uint8_t *data )
84
{
85
    uint8_t val = 0;
86

87
    for ( uint8_t i = 0 ; i < 2 ; i++ )
88
    {
89
        if ( ( data[i] >= '0' ) && ( data[i] <= '9' ) )
90
            val = ( val * 16 ) + ( data[i] - '0' );
91
        else if ( ( data[i] >= 'a' ) && ( data[i] <= 'f' ) )
92
            val = ( val * 16 ) + ( data[i] - 'a' + 0x0a );
93
        else
94
            break;
95
    }
96

97
    return val;
98
}
99

100
/**
101
 * converts AH to uint16_t value
102
 */
103
uint16_t ahtoUint16 ( uint8_t *data )
104
{
105
    uint16_t val = 0;
106

107
    for ( uint8_t i = 0 ; i < 4 ; i++ )
108
    {
109
        if ( ( data[i] >= '0' ) && ( data[i] <= '9' ) )
110
            val = ( val * 16 ) + ( data[i] - '0' );
111
        else if ( ( data[i] >= 'a' ) && ( data[i] <= 'f' ) )
112
            val = ( val * 16 ) + ( data[i] - 'a' + 0x0a );
113
        else
114
            break;
115
    }
116

117
    return val;
118
}
119

120
/**
121
 * convert uint16_t to AH. The result is stored in buffer
122
 */
123
char* uint16ToAh ( char *buffer, uint16_t val )
124
{
125
    uint16_t t = val;
126
    uint8_t z;
127

128
    for ( uint8_t i = 0 ; i < 4 ; i++ )
129
    {
130
        z = ( uint8_t ) ( ( t & 0xF000 ) >> 12 );
131
        t = t << 4;
132

133
        if ( ( z >= 0 ) && ( z <= 9 ) )
134
            buffer[i] = z + '0';
135
        else if ( ( z >= 0x0a ) && ( z <= 0x0f ) )
136
            buffer[i] = z + 'a' - 10;
137
    }
138

139
    buffer[4] = 0;
140

141
    return buffer;
142
}
143

144
/**
145
 * convert uint8_t to AH. The result is stored in buffer
146
 */
147
char* uint8ToAh ( char *buffer, uint8_t val )
148
{
149
    uint8_t t = val;
150
    uint8_t z;
151

152
    for ( uint8_t i = 0 ; i < 2 ; i++ )
153
    {
154
        z = ( uint8_t ) ( ( t & 0xF0 ) >> 4 );
155
        t = t << 4;
156

157
        if ( ( z >= 0 ) && ( z <= 9 ) )
158
            buffer[i] = z + '0';
159
        else if ( ( z >= 0x0a ) && ( z <= 0x0f ) )
160
            buffer[i] = z + 'a' - 10;
161
    }
162

163
    buffer[2] = 0;
164

165
    return buffer;
166
}
167

168
/**
169
 * Append Zero terminated string to TX buffer
170
 */
171
void uartPuts(const char *sb)
172
{
173
    int len = strlen(sb);
174
    if ((txpos+len) < sizeof(txbuffer))
175
    {
176
        strcat(txbuffer, sb);
177
        txpos+=strlen(sb);
178
    }
179
}
180

181
#define MSG "BOOT" /*SPM_PAGESIZE "\r\n"*/
182

183
/**
184
 * setup UART comm port
185
 */
186
void initUart(uint16_t baud)
187
{
188
    uint16_t ubrr = ( uint16_t ) ( ( ( uint32_t ) F_CPU / ( 16UL * baud ) ) - 1 );
189

190
#if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
191
    UBRRH = ( uint8_t ) ( ubrr << 8 ) & 0x0F;
192
    UBRRL = ( uint8_t ) ( ubrr & 0xFF );
193

194
    UCSRA = _BVC(U2X) | _BVC(MPCM);
195

196
    UCSRB = _BV ( RXEN ) | _BV ( TXEN ) | _BVC( RXCIE ) | _BVC(UCSZ2);
197

198
    UCSRC = _BV ( URSEL ) | _BVC(UMSEL) | _BV ( UCSZ1 ) | _BV ( UCSZ0 ) | _BVC(USBS) | _BVC(UPM1) | _BVC(UPM0) | _BVC(UCPOL);
199
#elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
200
    UBRR0H = ( uint8_t ) ( ubrr << 8 ) & 0x0F;
201
    UBRR0L = ( uint8_t ) ( ubrr & 0xFF );
202

203
    UCSR0A = _BVC(U2X0) | _BVC(MPCM0);
204

205
    UCSR0B = _BV ( RXEN0 ) | _BV ( TXEN0 ) | _BVC( RXCIE0 ) | _BVC(UCSZ02);
206

207
    UCSR0C = _BVC ( UMSEL01 ) | _BVC(UMSEL00) | _BV ( UCSZ01 ) | _BV ( UCSZ00 ) | _BVC(USBS0) | _BVC(UPM01) | _BVC(UPM00) | _BVC(UCPOL0);
208
#endif
209
}
210

211

212

213
/**
214
 * write a buffer to flash page.
215
 * This is 1:1 from the avrlibc documentation
216
 */
217
void boot_program_page (uint32_t page, uint8_t *buf)
218
{
219
    uint16_t i;
220
    uint8_t sreg;
221

222
    uint8_t z='0'+page;
223

224
    // Disable interrupts.
225

226
    sreg = SREG;
227
    cli();
228

229
    eeprom_busy_wait ();
230

231
    boot_page_erase (page);
232
    boot_spm_busy_wait ();      // Wait until the memory is erased.
233

234
    for (i=0; i<SPM_PAGESIZE; i+=2)
235
    {
236
        // Set up little-endian word.
237

238
        uint16_t w = *buf++;
239
        w += (*buf++) << 8;
240

241
        boot_page_fill (page + i, w);
242
    }
243

244
    boot_page_write (page);     // Store buffer in flash page.
245
    boot_spm_busy_wait();       // Wait until the memory is written.
246

247
    // Reenable RWW-section again. We need this if we want to jump back
248
    // to the application after bootloading.
249

250
    boot_rww_enable ();
251

252
    // Re-enable interrupts (if they were ever enabled).
253

254
    SREG = sreg;
255
}
256

257
/**
258
 * Send the header of a command
259
 */
260
void sendHeader(uint8_t toAddr)
261
{
262
    char buffer[6];
263
    uartPuts("@");
264
    uartPuts(uint8ToAh(buffer, toAddr));
265
    uartPuts(uint8ToAh(buffer, myAddress));
266
}
267

268
/**
269
 * send module ID
270
 */
271
void sendModuleID(uint8_t toAddr)
272
{
273
    char buffer[6];
274
    sendHeader(toAddr);
275
    uartPuts("T");
276
    uartPuts(uint16ToAh(buffer, MODULE_ID));
277
    uartPuts("\r");
278
}
279

280
/**
281
 * Send flash page size
282
 * This is used by the app to adjust data send
283
 */
284
void sendPageSize(uint8_t toAddr)
285
{
286
    char buffer[6];
287
    sendHeader(toAddr);
288
    uartPuts("BT");
289
    uartPuts(uint16ToAh(buffer, SPM_PAGESIZE));
290
    uartPuts("\r");
291
}
292

293
/**
294
 * Send ACK for reboot command
295
 */
296
void sendRebootACK(uint8_t toAddr)
297
{
298
    char buffer[6];
299
    sendHeader(toAddr);
300
    uartPuts("RTA");
301
    uartPuts("\r");
302
}
303

304
/**
305
 * Send Bot loader ACK
306
 */
307
void sendBootloaderACK(uint8_t toAddr)
308
{
309
    char buffer[6];
310
    sendHeader(toAddr);
311
    uartPuts("BLA");
312
    uartPuts(uint16ToAh(buffer, page));
313
    uartPuts("\r");
314
}
315

316
/**
317
 * Send bootloader NACK
318
 */
319
void sendBootloaderNACKcrc(uint8_t toAddr)
320
{
321
    char buffer[6];
322
    sendHeader(toAddr);
323
    uartPuts("BLNcrc");
324
    uartPuts(uint16ToAh(buffer, crc));
325
    uartPuts(",sh ");
326
    uartPuts(uint16ToAh(buffer, shouldCrc));
327
    uartPuts("\r");
328
}
329

330
/**
331
 * Send Prog CRC
332
 */
333
void sendProgCRC(uint8_t toAddr, uint16_t crc)
334
{
335
    char buffer[6];
336
    sendHeader(toAddr);
337
    uartPuts("CRC");
338
    uartPuts(uint16ToAh(buffer, crc));
339
    uartPuts(uint16ToAh(buffer, eeprom_read_word(PROGMEM_CRC_ADDR)));
340
    uartPuts("\r");
341
}
342

343
void sendBootloaderNACK(uint8_t toAddr)
344
{
345
    char buffer[6];
346
    sendHeader(toAddr);
347
    uartPuts("BLN");
348
    uartPuts("\r");
349
}
350

351
/**
352
 * Send Bootloader start downbload ACK or NACK
353
 */
354
void sendBootloaderStartACK(uint8_t toAddr, uint8_t ack)
355
{
356
    char buffer[6];
357
    sendHeader(toAddr);
358
    if (ack)
359
        uartPuts("BSA\r");
360
    else
361
        uartPuts("BSN\r");
362
}
363

364

365
uint8_t doTransmitUart(void)
366
{
367
    // Handle transmit data
368
#if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
369
    if ((txpos > 0) && (UCSRA & _BV(UDRE)))
370
#elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
371
    if ((txpos > 0) && (UCSR0A & _BV(UDRE0)))
372
#endif
373
    {
374
#if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
375
        UDR = txbuffer[txspos];
376
#elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
377
        UDR0 = txbuffer[txspos];
378
#endif
379
        txspos++;
380

381
        if (txspos >= txpos)
382
        {
383
            txspos = 0;
384
            txpos = 0;
385
            txbuffer[0] = 0;
386
        }
387
    }
388
    return txpos;
389
}
390

391
/**
392
 * Caclulate program CRC
393
 * This function calculate the CRC over all program space
394
 */
395
uint16_t calcProgCRC(void)
396
{
397
    crc = 0;
398
    for (uint16_t i=0; i<(BOOTLOADER_ADR); i++)
399
    {
400
        crc = _crc_xmodem_update(crc, pgm_read_byte ( i ));
401
    }
402
    return crc;
403
}
404

405

406

407
/**
408
 * Our main loop
409
 */
410
int main ( void )
411
{
412
#if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
413
    uint8_t resetSource = MCUCSR & RESET_SOURCE_MASK;
414
    MCUCSR &= ~RESET_SOURCE_MASK;
415
#elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
416
    uint8_t resetSource = MCUSR & RESET_SOURCE_MASK;
417
    MCUSR &= ~RESET_SOURCE_MASK;
418
#endif
419
    wdt_disable(); // Important or we risk a mess
420
    cli();
421

422

423
    initUart ( 38400 );  
424

425

426
    uint8_t status = BOOT_CMD;
427
    uint8_t toAddr = 0x00;
428
    uint8_t fromAddr = myAddress;
429
    uint16_t fwsize = 0;  // size of fw to load
430
    uint16_t rxfwsize = 0;  // size of received size
431
    char buffer[10];
432
    uint8_t cmd_rx = 0;
433

434
    // we just forced into boot loader
435
    // aCK this and report page size !
436
    //sendModuleID(toAddr);
437
    //while (doTransmitUart());
438
    uint16_t iscrc = calcProgCRC();
439
    sendProgCRC(ADDR_BROADCAST_DEF, iscrc);
440
    while(doTransmitUart());
441
 
442
    sendPageSize(ADDR_BROADCAST_DEF);
443
    while (doTransmitUart());  // Empty TX buffer
444

445
    while ( 1 )
446
    {
447
        /*
448
         * IF get this far without any reset source set,
449
         * we are directly called by the main app
450
         * So we have to skip the CRC check and directly continue with the bootloader
451
         */
452
        if (resetSource != 0)  // not jumped in on purpose (from main app)
453
        {
454
            /*
455
             * We have come here after a reset. We now check the CRC of tzhe program
456
             * If it is ok, we will start the main app. If not, we will continue
457
             * with the boot loader
458
             */
459
            if (iscrc == eeprom_read_word(PROGMEM_CRC_ADDR))
460
            {
461
                static uint16_t delay=0xffff;
462
        delay--;
463
                if (delay == 0)
464
                {
465
                    sendHeader(ADDR_BROADCAST_DEF);
466
                    uartPuts("MPCRCOk\r");
467
                    startMainApp();  // reboot into main prog
468
                }
469
            }
470
            else
471
            {
472
                sendHeader(ADDR_BROADCAST_DEF);
473
                //uartPuts("MPCRCErr\r");
474
            }
475
        }
476
        while (doTransmitUart());  // Empty TX buffer
477

478
        // Handle receive data
479
        char c = 0;
480
#if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
481
        if (UCSRA & _BV(RXC))
482
        {
483
            c = UDR;
484
#elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
485
        if (UCSR0A & _BV(RXC0))
486
        {
487
            c = UDR0;
488
#endif
489
            rxbuffer_boot[rxpos_boot] = c;
490
            rxpos_boot++;
491
            if (c == '\r')
492
      {
493
        resetSource = 0;  // Stay here
494
                cmd_rx = 1;
495
      }
496
            if (rxpos_boot > sizeof(rxbuffer_boot))
497
            {
498
                rxpos_boot=0;
499
            }
500

501
        }
502
        doTransmitUart();
503
        if (cmd_rx == 1)
504
        {
505
            uint8_t error = 0;
506
            // If the syntax is not correct, we will simply ignore the rest and fall through.
507
            if ((rxbuffer_boot[0] == '@') || (rxpos_boot >= 7)) // "@" + <adr> + B + <cmd> + <optional data>
508
            {
509
                toAddr = ahtoUint8((uint8_t*)&rxbuffer_boot[1]);
510
                fromAddr = ahtoUint8((uint8_t*)&rxbuffer_boot[3]);
511
                if ((toAddr == myAddress) || (toAddr == ADDR_BROADCAST_DEF))
512
                {
513
                    // Ok, this is a message for us !
514
                    if ((rxbuffer_boot[5] == 'T') && (rxbuffer_boot[6] == '?'))
515
                    {
516
                        sendModuleID(fromAddr);
517
                    }
518
                    else if ((rxbuffer_boot[5] == 'R') && (rxbuffer_boot[6] == 'T'))
519
                    {
520
                        sendRebootACK(fromAddr);
521
                        wdt_enable(WDTO_250MS);
522
                    }
523
                    else if (0) //(rxbuffer_boot[5] == 'D') && (rxbuffer_boot[6] == 'F'))
524
                    {
525
                        for (uint16_t s=0; s<(0x7fff) ; s+=SPM_PAGESIZE)
526
                        {
527
                            uartPuts("\r\n");
528
                            uartPuts(uint16ToAh(buffer, s));
529
                            uartPuts(">");
530

531
                            while (txpos)
532
                                doTransmitUart();
533

534

535
                            for (uint8_t b=0; b<SPM_PAGESIZE ; b++)
536
                            {
537
                                uartPuts(uint8ToAh(buffer, pgm_read_byte((uint8_t*)(b+s)) ));
538

539
                                while (txpos)
540
                                    doTransmitUart();
541
                            }
542
                        }
543
                    }
544
                    else if ((rxbuffer_boot[5] == 'B') && (rxbuffer_boot[6] == 'T'))
545
                    {
546
                        sendPageSize(fromAddr);
547
                        //startMainApp();
548
                        //bootloader();  // jump back from bootloader to bootloader, does make sense ? :-)
549
                    }
550
                    else if ((rxbuffer_boot[5] == 'B') && (rxbuffer_boot[6] == 'P'))
551
                    {
552
                        //sendPageSize(fromAddr);
553
                        startMainApp();
554
                        //bootloader();  // jump back from bootloader to bootloader, does make sense ? :-)
555
                    }
556
                    else if ((rxbuffer_boot[5] == 'B') && (rxbuffer_boot[6] == 'L') && (rxpos_boot >= 9))
557
                    {
558
                        uint8_t bytecnt = ahtoUint8((uint8_t*)&rxbuffer_boot[7]);
559
                        uint8_t offset = 9;
560
                        if (rxpos_boot >= ((bytecnt*2)+offset+4))
561
                        {
562
                            uint16_t pos;
563
                            // reformat data to binary
564
                            // we reuse the rx array, as we are sure no additional data comes in (we are stuck here, right !)
565
                            // this is save
566
                            crc = 0;
567
                            for (uint16_t i = 0 ; i < bytecnt ; i++)
568
                            {
569
                                pos = (i*2)+offset;
570
                                rxbuffer_boot[i] = ahtoUint8((uint8_t*)&rxbuffer_boot[pos]);
571
                                crc = _crc_xmodem_update(crc, rxbuffer_boot[i]);
572
                            }
573

574
                            rxfwsize+=bytecnt;
575

576
                            // get should crc
577
                            pos = (bytecnt*2)+offset;
578
                            shouldCrc = ahtoUint16((uint8_t*)&rxbuffer_boot[pos]);
579

580
                            // Fill remainder of page
581
                            if (bytecnt < SPM_PAGESIZE)
582
                            {
583
                                for (uint16_t i = bytecnt ; i < SPM_PAGESIZE ; i++)
584
                                    rxbuffer_boot[i] = 0xFF;  // Will be ignored by CPU !
585
                            }
586

587
                            if (crc == shouldCrc)
588
                            {
589
                                // now write flash
590
                                boot_program_page(page, (uint8_t*)rxbuffer_boot);
591

592
                                page+=SPM_PAGESIZE;
593

594
                                if (rxfwsize >= fwsize)
595
                                {
596
                                    uint16_t iscrc = calcProgCRC();
597
                                    eeprom_write_word((uint16_t*)PROGMEM_CRC_ADDR, iscrc);
598
                                    sendProgCRC(ADDR_BROADCAST_DEF, iscrc);
599
                                }
600

601
                                sendBootloaderACK(fromAddr);
602

603
                            }
604
                            else
605
                            {
606
                                sendBootloaderNACKcrc(fromAddr);
607
                            }
608
                        }
609
                        else
610
                        {
611
                            sendBootloaderNACK(fromAddr);
612
                        }
613
                    }
614
                    else if ((rxbuffer_boot[5] == 'B') && (rxbuffer_boot[6] == 'S') && (rxpos_boot >= 15))
615
                    {
616
                        uint16_t id = ahtoUint16((uint8_t*)&rxbuffer_boot[7]);
617
                        if (id == MODULE_ID)
618
                        {
619
                            fwsize = ahtoUint16((uint8_t*)&rxbuffer_boot[11]);
620
                            if (fwsize > 0)
621
                            {
622
                                sendBootloaderStartACK(fromAddr, 1);
623
                                page = 0;
624
                            }
625
                            else
626
                            {
627
                                error = 2;
628
                            }
629
                        }
630
                        else
631
                            error = 1;
632
                        if (error)
633
                        {
634
                            sendBootloaderStartACK(fromAddr, 0);
635
                        }
636
                    }
637
                    else
638
                    {
639
                        //sendUnknownCmd(fromAddr);
640
                    }
641
                }
642
            }
643
            rxpos_boot = 0;
644
            cmd_rx = 0;
645
        }
646
    }
647
}
Gast #4144978
Lesenswert?

Jürgen Sachs schrieb:
> Daher mal eine Bitte, ob ihr drüber sehen könntet und
> mir sagen, wo man optimieren könnte.

du hast zu viel doppelte code

ahtoUint8
ahtoUint16

die 2.Version braucht niemand.

uint16_t x = ahtoUint8(data) << 8 | ahtoUint8(data+2);

auch die ganze Send Funktionen lassen sich bestimmt sparsamer bauen.
Überall ist
1
    sendHeader(toAddr);
2
    uartPuts("BLA");
3
    uartPuts("\r");
drin.
#4145058
Lesenswert?

Peter II schrieb:
> Jürgen Sachs schrieb:
>> Daher mal eine Bitte, ob ihr drüber sehen könntet und
>> mir sagen, wo man optimieren könnte.
>
> du hast zu viel doppelte code
>
> ahtoUint8
> ahtoUint16
>
> die 2.Version braucht niemand.
>
> uint16_t x = ahtoUint8(data) << 8 | ahtoUint8(data+2);
>
> auch die ganze Send Funktionen lassen sich bestimmt sparsamer bauen.
> Überall ist
>
1
>     sendHeader(toAddr);
2
>     uartPuts("BLA");
3
>     uartPuts("\r");
4
>
> drin.
Das ging ja schnell :-)

Danke, auf die Idee Funktionen zu kombinieren we
1
uint16_t x = ahtoUint8(data) << 8 | ahtoUint8(data+2);
bin ich gar nicht gekommen.
aber wie ich den zweiten Punkt, den du erwähnt hast, vereinfachen soll, 
fehlt mir die Idee.
Die Funktionen sind ja schon eine Zusammenfassung, damit ich sich 
wiederholenden Code zusammen fasse.
Das einzige was mir auffällt, das die ganzen Zeichen nicht aus dem Flash 
kommen, sondern aus dem RAM. Aber davon habe ich ja im Bootloader die 
ganzen 2k für mich alleine.
Ich denke nicht, dass ich da Code größe sparen kann, zudem ich dann eine 
sendUart_p() Funktion machen müsste.

Aber die ersten 282 Byte Einsparung waren ja schon mal recht einfach.
Danke
Juergen
#4145143
Lesenswert?

Jürgen Sachs schrieb:

> Danke, auf die Idee Funktionen zu kombinieren we
>
1
uint16_t x = ahtoUint8(data) << 8 | ahtoUint8(data+2);
> bin ich gar nicht gekommen.

Solltest du aber.
Immer dann, wenn du COpy&Paste Programmierung machst und nur ein paar 
Zahlenwerte in der neuen Funktion austauscht, solltest du dir Gedanken 
machen, wie man die Dinge zusammenführen kann.

Das hier
1
void uartPuts(const char *sb)
2
{
3
    int len = strlen(sb);
4
    if ((txpos+len) < sizeof(txbuffer))
5
    {
6
        strcat(txbuffer, sb);
7
        txpos+=strlen(sb);
8
    }
9
}
ist auch viel zu kompliziert
1
void uartPuts(const char *sb)
2
{
3
  while( *sb && txpos < sizeof(txbuffer) )
4
    txbuffer[txpos++] = *sb++;
5
}

Nichts gegen die str... Funktionen. Aber oftmals ist es viel einfacher, 
wenn man selber die Dinge in die Hand nimmt.

> Die Funktionen sind ja schon eine Zusammenfassung, damit ich sich
> wiederholenden Code zusammen fasse.

zb ist allen Funktionen gemeinsam, dass zuerst der Header geschickt 
wird, gefolgt von einem String.
Warum muss jetzt in jeder Bearbeitungsfunktion wieder einzeln sendHeader 
und uartPuts aufgerufen werden? Warum gibt es nicht eine Funktion
1
void uartSendResponse( const char* str )
2
{
3
  sendHeader( .. );
4
  uartPuts( str );
5
}

die von jeder Funktion als erstes aufgerufen wird?
1
...
2
void sendPageSize(uint8_t toAddr)
3
{
4
    uartSendRespone( "BT" );
5
    uartPuts(uint16ToAh(buffer, SPM_PAGESIZE));
6
    uartPuts("\r");
7
}
8
...

und schon ist in jeder deiner Bearbeitungsfunktionen ein Funktionsaufruf 
weniger, der speichertechnisch zu Buche schlägt.

Auch kommt das zb
1
    uartPuts("\r");
oft vor. So oft, dass es sich ev. schon lohnen würde, dafür eine eigene 
Funktion zu machen, die genau einen \n in den txBuffer stellt.
#4145159
Lesenswert?

Deine ganzen ....ToAh Funktionen.
Alles viel zu kompliziert geschrieben.

Du hast genau 1 Funktion, die einen Wert im Bereich 0 bis 0xF übernimmt 
und das entsprechende Zeichen dafür generiert.
Die Funktionen für uint8_t etc. benutzen dann wieder diese kleinere 
Hilfsfunktion um die 2 Zeichen zu erzeugen, die es für 1 Byte braucht. 
Die Funktion für uint16_t greift wieder auf die Funktion zurück, die 1 
Byte konvertieren kann (1 uint16_t besteht ja aus 2 uint8_t)
1
char hexDigit( uint8_t val )
2
{
3
  if( val > 9 )
4
    return val + 'a' - 10;
5

6
  return val + '0';
7
}
8

9
char* uint8ToAh ( char *buffer, uint8_t val )
10
{
11
  buffer[0] = hexDigit( val >> 4 );
12
  buffer[1] = hexDigit( val & 0x0F );
13

14
  return buffer;
15
}
16

17
char* uint16ToAh ( char *buffer, uint16_t val )
18
{
19
  uint8ToAh( buffer, val >> 8 );
20
  uint8ToAh( buffer + 2, val );
21

22
  return buffer;
23
}


Du musst noch viel mehr in aufeinander aufbauenden Funktionen denken!
#4145171
Lesenswert?

Solche Konstrukte
1
    uartPuts(uint16ToAh(buffer, crc));

... also das Senden eines Zahlenwerts ....

scheinen mir auch hinreichend häufig vorzukommen, so dass sich eigene 
Funktionen
1
  uartPutUint8
2
bzw.
3
  uartPutUint16
lohnen würden.
Das könnte man jetzt natürlich auch so machen, dass man um 1 uint16_t zu 
senden, diesen Fall auf das versenden von 2 uint8_t zurückführt. Wodurch 
wiederrum die Konvertierfunktion für einen uin16_t überflüssig werden 
würde, was wiederrum Speicher spart.

Das befreit dich dann auch vom immer gleichen buffer, den du quer durch 
die Bank nur zur Konvertierung der Zahlen in vielen Funktionen brauchst.
#4145182
Lesenswert?

Karl Heinz schrieb:

> Das könnte man jetzt natürlich auch so machen, dass man um 1 uint16_t zu
> senden, diesen Fall auf das versenden von 2 uint8_t zurückführt. Wodurch
> wiederrum die Konvertierfunktion für einen uin16_t überflüssig werden
> würde, was wiederrum Speicher spart.

Wohingegen das Versenden eines uint8_t wiederrum so einfach ist, dass 
man auch die Konvertierfunktion für einen uint8_t gar nicht mehr 
braucht.
Jetzt wäre es natürlich gut, wenn es eine Funktion gäbe, die ein 
einzelnes Zeichen in den Ausgabepuffer stellt. Ich postuliere mal, dass 
es so eine gibt.
1
void uartPutUint8( uint8_t val )
2
{
3
  uartPutC( hexDigit( val >> 4) );
4
  uartPutC( hexDigit( val & 0x0F );
5
}
6

7
void uartPutUint16( uint16_t val )
8
{
9
  uartPutUint8( val >> 8 );
10
  uartPutUint8( val );
11
}

und die ganzen Konvertierfunktionen für uint8_t bzw. uint16_t sind damit 
obsolet geworden.
Wohingegen sich die Bearbeitungsfunktionen zb so schreiben
1
void sendProgCRC(uint8_t toAddr, uint16_t crc)
2
{
3
    uartSendResponse( "CRC" );
4
    uartPutUint16( crc );
5
    uartPutUint16( eeprom_read_word(PROGMEM_CRC_ADDR) );
6
    uartPutC('\r');
7
}

NB: In deinem Bootloader gibt es ein kunterbuntes Mischmasch, ob du eine 
Ausgabe mit \r, mit \n, oder sogar mit \r\n abschliesst. Einige dich mit 
dir selbst auf eine Variante und zieh sie durch!
#4145197
Lesenswert?

Warum heisst es an manchen Stellen in deinem Programm
1
                            while (txpos)
2
                                doTransmitUart();
und an manch anderen Stellen
1
    while (doTransmitUart());  // Empty TX buffer

beides macht offenbar dasselbe: Es gibt alles aus, was zu diesem 
Zeitpunkt im TxBuffer gesammelt wurde.

Aber dann solltest du das auch immer auf die gleiche Art und Weise 
schreiben!

Und am einfachsten geht das, wenn es eine Funktion
1
void emptyTxBuffer()
2
{
3
  while (doTransmitUart())
4
    ;
5
}
gibt, und du die überall aufrufst, wo du jetzt die while Schleifen 
explizit drinnen hast.
#4145203
Lesenswert?

1
uint32_t page = 0;

ich weiss zwar nicht, was es mit 'page' genau auf sich hat.
Aber bist du sicher, dass das ein uint32_t sein muss?

Ist dir klar, welche Auswirkungen dieser Datentyp da hat?

Wenn page das aussagt, was ich vermute das es aussagt, dann kann ich mir 
nicht vorstellen, dass es jemals einen AVR geben wird, der den möglichen 
Wertebereich eines uin32_t auch nur annähernd ausnützt.
#4145204
Lesenswert?

Karl Heinz schrieb:
>
1
> uint32_t page = 0;
2
>
>
> ich weiss zwar nicht, was es mit 'page' genau auf sich hat.
> Aber bist du sicher, dass das ein uint32_t sein muss?
>
> Ist dir klar, welche Auswirkungen dieser Datentyp da hat?
>
> Wenn page das aussagt, was ich vermute das es aussagt, dann kann ich mir
> nicht vorstellen, dass es jemals einen AVR geben wird, der den möglichen
> Wertebereich eines uin32_t auch nur annähernd ausnützt.

Ah, ja
1
void sendBootloaderACK(uint8_t toAddr)
2
{
3
...
4
    uartPuts(uint16ToAh(buffer, page));
5
...
6
}

soviel dazu :-)
#4145220
Lesenswert?

Karl Heinz schrieb:

> Wenn page das aussagt, was ich vermute das es aussagt


Muss ich zurücknehmen.
Die Variable ist einfach nur schlecht benannt.
Das ist die Byte-Startadresse im Flash, ab der geschrieben werden soll. 
Ich dachte das wäre eine Page-Nummer.

In dem Fall ist ein uint32_t ok, da es ja AVR mit mehr als 64K Flash 
gibt.

Aber dann sollte die Rückmeldefunktion auch mit einem uint32_t 
operieren!
#4145391
Lesenswert?

So, ich denke ich habe mal das meiste umgesetzt.
Alles ist doch mit ganz schön arbeit verbunden

das mit der page variable hatte ich damals so übernommen von der 
Funktion aus der avrlibc.

Aktuell ist er schon etwas kleiner geworden
laut avr size
text von 0xf9c auf 0xe60
data von 0x44 auf 0x40
bss von 0x14a auf 0x148
hex von 112a auf fe8

es wird....

Die Optimierung der umwandel Routinen muss ich mir noch mal ansehen

Ich danke euch allen mal für die Hilfe...

Falls ihr noch was findet, immer gerne

Gruss
Juergen
Persönliche Seite #4145819
Lesenswert?

Jürgen Sachs schrieb:
> Falls ihr noch was findet, immer gerne

Falls eine Funktion (statisch) nur 1x verwendet wird und nicht global 
sein muss, dann kann es günstiger sein, sie als static zu deklarieren. 
Dann kann sie inline eingefügt werden was u.U. deutlich Codegröße spart.


> Falls ihr noch was findet, immer gerne

Viele Funktionen verwenden einen Puffer der Speicherklasse auto wie z.B.
1
char buffer[6];
Falls die Funktion nicht reentrant sein muss — was bei deinem Bootloader 
vermutlich der Fall ist — kann es günstifer sein, den Puffer statisch zu 
vergeben, d.h. entweder local static oder modul-statisch.  Das spart 
evtl. das Anlegen eines Frames, was sehr teuer ist.


> Falls ihr noch was findet, immer gerne

Mitunter ist es teuer, Variablen wie rxpos_boot global zu haben.  Wenn 
sie wirklich global sein muss und sich die Verwenung an einer Stelle 
häuft, dann kann es günstiger sein, sie in eine lokale Variable zu 
laden.  Grund sind die Aliasing-Rules von C.


> Falls ihr noch was findet, immer gerne

Ist wirklich notwendig, strlen und strcat zu verwenden?  Im Bootloader 
brauch man doch keine Nebenläufigkeit, und die UART-Routinen bzw. puts 
et al. können blockierend arbeiten, d.h. Zeichenketten werden Zeichen 
für Zeichen ausgegeben bis der auszugebende String aufgebraucht ist.


...und noch ein paar Anmerkungen zum Stil:

> Falls ihr noch was findet, immer gerne

An mehreren Stellen lese ich ein CLI bzw. Operationen mit SREG, aber 
nirgends ist ein SEI.  Wozu das alles?


> Falls ihr noch was findet, immer gerne

Um die Anwendung zu starten springst du nach 0x0 (startMainApp) was 
mehrere Nachteile hat:

1) Die Handware wird nicht initialisiert, d.h. es bleiben Einstellungen 
des Bootloaders bestehen.  Geht die Anwendung davon aus, dass die 
Hardware frisch der Reset initialisiert ist (was fast alle Anwendungen 
tun), dann geht die Anwendung also von falschen Voraussetzungen aus.

Falls möglich, sollte ein Reset immer ein Hard-Reset sein!


> Falls ihr noch was findet, immer gerne

Ad '\r'

Ein Zeilenumbruch in C ist immer ein '\n', d.h. im Code wird man 
immer ein \n ausgeben.  Das '\r' hat im "normalen" Code nix zu suchen, 
denn der Code weiß ja nicht, welches OS die Gegenstelle fährt.  Ergo: 
Falls notwendig, gibt es eine einzige Stelle im Code, welche das \r 
ausgibt, und zwar die zentrale put-Routine selbst, etwa so:
1
    ...
2
#ifdef HOST_WINDOWS
3
    // For MS-Windows terminal: output newline as "\r\n".
4
    if (c == '\n')
5
        uart_putc ('\r');
6
#endif /* HOST_WINDOWS */
7
    uart_putc (c);
8
    ...
In diesem Beispiel wird mit -DHOST_WINDOWS compiliert falls die 
Gegenstelle ein Windows ist.  Falls es zur Compilezeit nicht bekannt 
ist, wird es etwas komplizierter.

Dies muss natürlich nur beachtet werden, wenn die Kommunikation mit 
einem terminal o.ä. geschieht; falls es sich um ein eigenes Protokoll 
mit einer definierten Gegenstelle handelt, ist die Unterscheidung i.d.R. 
nicht notwendig, aber dennoch ist es nicht ratsam, den Code mit \r zu 
übersäen.


> Falls ihr noch was findet, immer gerne

An vielen Stellen stehen Casts wie
1
ahtoUint16((uint8_t*)&rxbuff...
Besser den Cast in ahtoUint16 machen und als Parameter const void* 
übergeben.
Moderator Persönliche Seite #4145866
Lesenswert?

Johann L. schrieb:
> In diesem Beispiel wird mit -DHOST_WINDOWS compiliert falls die
> Gegenstelle ein Windows ist.  Falls es zur Compilezeit nicht bekannt
> ist, wird es etwas komplizierter.

Wieso? Ich beschreibe mal das Szenario für Unix/Linux:

Ich kann es mir nur so vorstellen: Ich starte Kermit oder ein ähnliches 
(Terminal-Emulations-)Programm, welches mit TTYs umgehen kann. Dieses 
Programm wird das TTY, an dem der µC via UART angeschlossen ist, im 
Normalfall im Raw-Mode öffnen, d.h. es findet keine 
CarriageReturn/Newline-Wandlung statt. Oder auch anders gesagt: Das Flag 
ONLCR ist normalerweise am TTY des µCs nicht gesetzt.

Ein Terminal - egal ob es ein echtes Terminal oder eine Emulation ist, 
erwartet standardmäßig immer ein Carriage Return ('\r' und ein Newline 
('\n'), um den Cursor:

  a) an den Anfang der(selben) Zeile zu setzen ('\r')
  b) den Cursor um eine Zeile nach unten zu setzen ('\n')

Das heisst: Auch wenn Dein µC mit einem Unix-/Linux-Host verbunden ist, 
muss der µC ein \r\n schicken, um einen korrekten Zeilenvorschub zu 
erzeugen.

Das ist komplett unabhängig vom Host.

Warum Unix-/Linux-Programme selber lediglich ein bloßes '\n' schicken 
(müssen), um einen korrekten Zeilenvorschub zu erzeugen, liegt an den 
Einstellungen des TTYs, an dem der Benutzer arbeitet: Dieses läuft im 
"Cooked-Mode", d.h. es sind (unter anderem) die Flags OPOST und ONLCR 
eingeschaltet. Damit wird ein Newline ('\n') vom TTY-Treiber in ein 
CarriageReturn + Newline ('\r\n') gewandelt. Aber wohlgemerkt: Das ist 
das TTY, an dem der User arbeitet und nicht das TTY, an dem der µC 
hängt!

Fazit: Es muss keine Unterscheidung bzgl. des Hosts gemacht werden. Wenn 
doch, ist das TTY für den µC am Unix-/Linux falsch eingestellt. 
Kommunikationsprogramme wie Kermit und andere 
Terminal-Emulationsprogramme arbeiten in dieser Hinsicht aber korrekt.

Auch wenn man ein eigenes Flash-Programm (und kein Terminalprogramm) 
verwendet, welches über das TTY mit dem µC kommuniziert und keine 
TTY-Flags ändert: Standardmäßig sind die Flags OPOST und ONLCR 
abgeschaltet auf TTYs, auf denen kein getty (o.ä.) läuft. D.h. die 
Zeichen werden 1:1 im Hostprogramm ankommen. Selbstverständlich muss es 
dann natürlich ein '\r\n' in der Antwort erwarten. Warum sollte es nur 
ein '\n' sein? Nur, weil es unter Linux läuft? Nein, das ist kein 
Kriterium, wenn es um TTY-Kommunikation geht.
Gast #4146213
Lesenswert?

Das Protokoll läuft zwischen dem atmega und einem speziellen Programm 
ab.
Das Protokoll ist nicht für die direkte Ausgabe in einem terminal 
gedacht.

Statt dem CR hätte ich auch ein etx (0x03) nehmen können.

Da das ganze über Bluetooth geht, will ich unnötige Zeichen vermeiden.

Zum Flaschen gibt es eine spezielle Software, die mit dem bootloader 
über Bluetooth spricht.

Im Normalbetrieb sind es 2 atmega, die sich per Bluetooth unterhalten.

Also spielt das CR nur eine untergeordnete Rolle.

Stelen und strcat sind, dank eurer Vorschläge, Vergangenheit.

Warum die Funktionen für den UART nicht blockend sind, hat einfach den 
Hintergrund, das die aus einer frühen Version des hauptcodes kommen und 
da muss das alles per interrupt laufen.

Das cli genutzt wird, aber kein sei hat einfach den Grund sicher zu 
sein, dass der interrupt aus ist, wenn ich z.b. vom Programm in den 
bootloader springe.

Und ich springe an Position 0x0000 da ein reset mich wieder in den 
bootloader bringt. Das ist per Fuse so eingestellt und beabsichtigt. 
Mein Programm initialisiert alles (hoffe ich)

Gruss
Juergen
(Firma: Torrox.de) #4146578
Lesenswert?

Hallo,
ich habe mir das jetzt nicht im Detail angeguckt: hast Du die 
Optimierung (-Os) des Compilers eingeschaltet? Ansonsten kannst Du mit 
--gc-sections noch dafür sorgen, dass nur referenzierter Code auch im 
binary landet. Und mit -ffunction-sections -fdata-sections dafür sorgen, 
dass jede Funktion und jedes Datum in einer eigenen section landet und 
damit nur dann im binary landet, wenn es referenziert wird. Danach würde 
ich dann mal im Mapfile gucken.

mfg Torsten
#4164372
Lesenswert?

Johann L. schrieb:
> An vielen Stellen stehen Casts
> wie
1
ahtoUint16((uint8_t*)&rxbuff...
> Besser den Cast in ahtoUint16
> machen und als Parameter const void* übergeben.

Koenntest Du Beschreiben welchen Vorteil man davon hat?
Eine Signatur mit
1
 void foo(const uint8_t* x);
oder
1
 void foo(const void* x);
fuehrt doch immer dazu, dass ein 16-Bit Wert (auf dem 8-Bit AVR) kopiert 
wird. Was uebersehe ich?

-Foka
#4509648
Lesenswert?

So,

sorry für die späte Rückmeldung, aber es gab leider andere Dinge die 
Vorrang hatten.

Aktuell ist es so, dass ich die Maximale Größe des Bootloaders 
beanspruche, also 4k oder 2000 Worte. Da bin ich irgendwie durcheinander 
gekommen.
Beim compilieren ergibt sich daraus 3750 Bytes
1
avr-size bootloader.elf 
2
   text     data      bss      dec      hex  filename
3
   3678       74      330     4082      ff2  bootloader.elf
4
avr-size --mcu=atmega32 -C bootloader.elf
5
AVR Memory Usage
6
----------------
7
Device: atmega32
8

9
Program:    3750 bytes (11.4% Full)
10
(.text + .data + .bootloader)
11

12
Data:        402 bytes (19.6% Full)
13
(.data + .bss + .noinit)

Gibt es überhaupt eine Chance das auf unter 2000Byte zu bekommen?
Weil das wäre die nächst kleinere Größe des Bootloaders.

In Manchen Setups nehme ich schon eine größere CPU, aber beim manchen 
benutze ich das BCA8-BTM mit einem mega328p, da kann ich nicht größer 
werden.
Der Compile unten ist für einen mega32.

Zur Frage der Compiler Optionen
1
avr-gcc bootloader.cpp -mmcu=atmega32 -I. -MD -MP -MF .dep/bootloader.o.d -D_TYPE_1007_=1007 -DMODULE_TYPE=1007 -DMODULE_ID=0x1007 -DF_CPU=16000000UL -DBOOTLOADER_ADR=0x7000 -DMODULE_VERSION="0.2.1" -DADDR_PC_DEF=127 -DADDR_TX_LCD_DEF=102 -DADDR_TX_MAIN_DEF=101 -DADDR_RX_MAIN_DEF=1 -DADDR_BROADCAST_DEF=0 -DMY_DEF_ADDR=1 -DADDR_DEBUG_RS232_DEF=99 -DMAX_FUNC_CNT=32 -DTARGET_AVR -std=gnu99 -ffunction-sections

Linker
1
avr-gcc -mmcu=atmega32 -I.  -MD -MP -MF .dep/bootloader.elf.d -D_TYPE_1007_="1007" -DMODULE_TYPE="1007" -DMODULE_ID=0x1007 -DF_CPU=16000000UL -DBOOTLOADER_ADR=0x7000 -DMODULE_VERSION=\"0.2.1\" -DADDR_PC_DEF=127 -DADDR_TX_LCD_DEF=102 -DADDR_TX_MAIN_DEF=101  -DADDR_RX_MAIN_DEF=1 -DADDR_BROADCAST_DEF=0 -DMY_DEF_ADDR=1 -DADDR_DEBUG_RS232_DEF=99 -DMAX_FUNC_CNT=32 -DTARGET_AVR -std=gnu99 -ffunction-sections obj/bootloader.o obj/addr_list.o --output bootloader.elf -Wl,-Map=bootloader.map,--cref -Ttext=0x7000

Wenn ich etwas übersehen habe, bitte nochmal Fragen.

Danke
Jürgen
Angehängte Dateien:
#4509859
Lesenswert?

Steffen R. schrieb:
> -ffunction-sections
>
> vergrößert den Code (weil der Optimierer manche funktionsübergreifende
> Dinge Optimierungen nicht machen kann) und benötigt man nur, wenn man
> überflüssige Funktionen durch den Linker löschen lassen möchte.
>
> Ich sehe keine Optimierer-Optionen -O?

Ok, das mit dem fehlenden Optimier Optionen ist ein grobes Faul.
Im Makefile wird zwar eine Konstante gesetzt, aber die nirgends 
umgesetzt :-(
Eingebaut und wir sind ein großes Stück weiter. von 3754 Bytes auf 2254. 
Das ist doch mal eine Ansage :-)

Das -ffunction-section ist auch (wieder) entfernt. macht hier in der Tat 
nicht viel Sinn. und hat fast 80 Byte gebracht.
1
avr-nm -n bootloader.elf > bootloader.sym
2
avr-size bootloader.elf 
3
   text     data      bss      dec      hex  filename
4
   2254       72      330     2656      a60  bootloader.elf
5
avr-size --mcu=atmega32 -C bootloader.elf
6
AVR Memory Usage
7
----------------
8
Device: atmega32
9

10
Program:    2324 bytes (7.1% Full)
11
(.text + .data + .bootloader)
12

13
Data:        400 bytes (19.5% Full)
14
(.data + .bss + .noinit)

Danke für die Hinweise.
Jürgen
#4509867
Lesenswert?

Damit hat sich fast shcon mein Platz Problem erledigt.
Bisher war mein Code 28700 Byte groß, nach einfügen der fehlenden 
Optimierung 15002. Das hätte ich nicht erwartet.

Die Frage ist, ob noch alles geht :-)

Irgendwann muss ich mein UrMakefile mal die Optimierung entfernt haben.
Jetzt wieder drin.

Aber eventuell bekommt man den Bootloader ja noch unter 2000Bytes.

Aber wie bekannt ist, kosten die ersten 80% nur 20% der Zeit..

Gruss
Juergen
#4510685
Lesenswert?

Bei -Os bin ich mir etwas unsicher. Hier sollte man mal verschiedene 
durchtesten. -Os versucht ein Optimum zwischen Laufzeit und Codegröße zu 
schaffen, mit Präferenz auf Codegröße. Hier scheint aber die Codegröße 
viel wichtiger zu sein und die Laufzeit eher keine Rolle zu spielen.

An dieser Stelle fehlt mir aber die Erfahrung bei den kleinen Atmels.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren