PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Programmgrösse AVR_GCC



Vbxler
11.02.2009, 22:39
Hallo an Alle!

Ich spiele mit dem Gedanken, dass ich von Bascom auf GCC umsteige. Ich habe mein erstes Programm geschrieben, funktioniert bestens, nur wird für diese Winzprogramm 4200Byte im Controller benötigt!
//************************************************** ***********************
//Title: AnalogDigitalConverter
//Author:
//File: Analogwert_01.c
//Software: AVR-Studio 4.15
//Hardware: AVR with built-in UART, tested on ATMEGA8 at 8 Mhz
//
//DESCRIPTION:
// Beispielprogramm für den Gebrauch der "uart.h"
//
//************************************************** ***********************
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#include "uart.h" // einbinden uart.h
#define XTAL 8000000UL // festlegen der CPU - Frequenz in Mhz
#define UART_BAUD_RATE 9600 // 9600 baud für RS232

//-----------------------------------------------------------------------
// Deklaration der Konstanten / Variablen
//-----------------------------------------------------------------------


//-----------------------------------------------------------
//AnalogSpannung messen
//-----------------------------------------------------------
//ADCMUX: 00 1 0 , 0000
// Bit 7:6 – REFS1:0: Reference Selection Bits
// Bit 5 – ADLAR: ADC Left Adjust Result
// Bit 3:0 – MUX3:0: Analog Channel Selection Bits
//
//ADCSRA: 1110,0010
// Bit 7 – ADEN: ADC Enable
// Bit 6 – ADSC: ADC Start Conversion
// Bit 5 – ADFR: ADC Free Running Select
// Bit 4 – ADIF: ADC Interrupt Flag
// Bit 3 – ADIE: ADC Interrupt Enable
// Bits 2:0 – ADPS2:0: ADC Prescaler Select Bits
//--------------------------------------------------------------
void init(void)
{

//---------------------------------------------------
//Pins bzw. Ports als Ein-/Ausgänge konfigurieren //---------------------------------------------------
DDRB |= 0x00; //00000000 -> Eingänge - nicht verwendet
DDRC |= 0x00; //00000000 -> alle Analogports als Eingänge
DDRD |= 0x00; //00000000 -> Eingänge - nicht verwendet

ADMUX |= (0<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen!!
ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler

uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,XTAL) ); // Initialisieren der UART-Library durch Übergabe der baudrate und XTAL
sei(); // interrupt freigeben

}

//-----------------------------------------------------------
//AnalogSpannung messen
//-----------------------------------------------------------
//ADCMUX: 00 1 0 , 0000
// Bit 7:6 – REFS1:0: Reference Selection Bits
// Bit 5 – ADLAR: ADC Left Adjust Result
// Bit 3:0 – MUX3:0: Analog Channel Selection Bits
//
//ADCSRA: 1110,0010
// Bit 7 – ADEN: ADC Enable
// Bit 6 – ADSC: ADC Start Conversion
// Bit 5 – ADFR: ADC Free Running Select
// Bit 4 – ADIF: ADC Interrupt Flag
// Bit 3 – ADIE: ADC Interrupt Enable
// Bits 2:0 – ADPS2:0: ADC Prescaler Select Bits
//--------------------------------------------------------------
uint16_t ReadChannel(uint8_t mux)
{
uint8_t byZeiger; //Zeiger Schleife
uint16_t result; //Messwert
//----------------------------

ADMUX = (ADMUX&0xF0)|mux; // Kanal festlegen
ADCSRA = (1<<ADEN) | (1<<ADSC); // Aktivieren des ADC und erste ADC-Wandlung auslesen
while ( ADCSRA & (1<<ADSC) ) {;} // auf Abschluss der Konvertierung warten
result = ADCW; // ADCW muss einmal gelesen werden,
result = 0; //Zwischenpeicher leeren


//ADC 4mal einlesen uns Mittelwert bilden
for( byZeiger=0; byZeiger<4; byZeiger++ )
{
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while ( ADCSRA & (1<<ADSC)) {;} // auf Abschluss der Konvertierung warten
result += ADCW; // Wandlungsergebnisse aufaddieren
}

ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)
result /= 4; // Summe durch vier teilen = arithm. Mittelwert
return result;
}


//-----------------------------------------------------------------------
// Hauptprogramm
//-----------------------------------------------------------------------
int main(void)
{
const float rDigitADC = 0.0048828125; //Referenzwert zur Multiplikation mit den Werten der Analogports (5/1024)
char buffer[7]; //Array für Aussgabe Daten über UART
uint16_t wAnalog; //Variable für jeweils an einem Analogport gemessenen Wert

init(); //Initialisierung
//-----------------------------------------------------------------------
// Hauptschleife
//-----------------------------------------------------------------------
while (1)
{

// 1 Sekunde warten
_delay_ms(1000);

wAnalog = ReadChannel(1); //ADC_0 einlesen


utoa( wAnalog, buffer, 10); // konvertieren interger nach String (decimal format)
uart_puts(buffer); // übertrage string an uart library
uart_puts(" - Digit \n");

dtostrf(wAnalog * rDigitADC, 11, 8, buffer); //Spannung umrechnen
uart_puts(buffer);
uart_puts(" Volt\r\n\n");
}
}

Selbst wenn ich alles für die Ausgabe über UART weg lasse, werden noch immer >3800Byte benötigt. Das vergleichbare Programm mit Bascom kommt fast mit dem halben Speicherplatz aus.

Build started 11.2.2009 at 21:56:22
avr-gcc -mmcu=atmega8 -Wall -gdwarf-2 -std=gnu99 -DF_CPU=8000000UL -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Os -MD -MP -MT Analogwert_01.o -MF dep/Analogwert_01.o.d -c ../Analogwert_01.c
avr-gcc -mmcu=atmega8 -Wl,-Map=Analogwert_01.map Analogwert_01.o uart.o -o Analogwert_01.elf
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature Analogwert_01.elf Analogwert_01.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex Analogwert_01.elf Analogwert_01.eep || exit 0
avr-objdump -h -S Analogwert_01.elf > Analogwert_01.lss

AVR Memory Usage
----------------
Device: atmega8

Program: 4192 bytes (51.2% Full)
(.text + .data + .bootloader)

Data: 333 bytes (32.5% Full)
(.data + .bss + .noinit)

Build succeeded with 0 Warnings...

Die Optimierung habe ich bereits auf -Os gestellt.
Gibt es da noch möglichkeiten zur Speicheroptimierung?

Danke

Felix G
11.02.2009, 23:20
Ich würde mal sagen der enorme Platzbedarf kommt von dtostrf...

gerade bei solchen Funktionen sollte man schon genau überlegen ob man sie wirklich braucht, oder ob es nicht auch platzsparende Alternativen gibt (prinf und scanf z.B. gehören auch in die Kategorie der Speicherfresser)

sternst
12.02.2009, 07:37
Die Größe resultiert aus dem Benutzen von Gleitkommaarithmetik ohne Verwendung der entsprechenden Library (-lm).

Vbxler
12.02.2009, 08:20
Ich danke euch beiden!!

Bereits das einbinden der libm.a spart >1500Byte und das weglassen der dtostrf spart > 3000Byte.

Jetzt ist wieder Licht in Sicht! 8-[


Danke

Vbxler

sternst
12.02.2009, 10:28
das weglassen der dtostrf spart > 3000Byte.
Ja, aber nicht das Weglassen der Funktion an sich spart diese große Menge, sondern der dadurch entstehende Verzicht auf Gleitkommaarithmetik im allgemeinen.