mikrocontroller.net

Forum: Compiler & IDEs Array nicht in RAM


Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

meines Wissens werden ja Arrays, sofern nicht mit PROGMEM 
gekennzeichnet, im RAM des AVRs abgelegt, doch irgendwie passiert das 
bei mir nicht.
// Sollte im RAM sein
const uint16_t c_FreqTable[] =
{
  220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415,
  440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831,
  880
};

// ...

SetFrequency(c_FreqTable[7]); // Korrekte Ausgabe
SetFrequency(c_FreqTable[i]); // Müll

Wenn das Array tatsächlich im RAM liegt, dann müsste es gehen, wenn es 
aber, whyever, im Flash ist, dann gehts ja wohl nicht.

Mein µC ist ein AtMega8, falls das hilft.

Danke

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:
SetFrequency(c_FreqTable[7]); // Korrekte Ausgabe
SetFrequency(c_FreqTable[i]); // Müll

Tja, dann wird wohl i Müll enthalten.

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
glaube ich nicht ;)

Ich habe einen Hack eingebaut, bis ich eine gescheite Lösung für das 
Problem habe:
if(i==0) SetFrequency(c_FreqTable[0]);
else if(i==1) SetFrequency(c_FreqTable[1]);
else if(i==2) SetFrequency(c_FreqTable[2]);
else if(i==3) SetFrequency(c_FreqTable[3]);
// [...] more of the same
else if(i==22) SetFrequency(c_FreqTable[22]);
else if(i==23) SetFrequency(c_FreqTable[23]);
else if(i==24) SetFrequency(c_FreqTable[24]);

Also i sollte keinen Müll enthalten, denn mit der "eleganten" Lösung 
geht es.

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie versuchst du auf das Array im Flash zuzugreifen? Direkt mit dem 
Variablennamen? -> Das geht nicht, du musst memcpy_P, pgm_read_byte, 
pgm_read_word etc. benutzen.

Der Grund, dass es mit festen Zahlen funktioniert, ist der Optimierer 
der direkt die richtigen Zahlen einsetzt, so dass im fertigen Programm 
gar keine Zugriffe auf das Array stattfinden.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:

> glaube ich nicht ;)

Natürlich nicht. Der restliche nicht gezeigte Code ist ja immer 
fehlerfrei.

> Also i sollte keinen Müll enthalten, denn mit der "eleganten" Lösung
> geht es.

Deine Lösung lässt keinen Rückschluss darauf zu, ob i irgendwann mal 
Müll enthält. Sie verhindert nur, dass in dem Fall SetFrequency mit 
einem ungültigen Wert aufgerufen wird. Setze doch noch ein else hinten 
dran und schalte dort z.B. eine LED ein.

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Soweit hatte ich das auch verstanden, aber warum ist das Array denn im 
Flash, ich hab doch nirgendwo ein PROGMEM stehen?

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn es auch nicht unmöglich ist, das Du da auf ein Problem gestossen 
bist, so ist es doch eher unwahrscheinlich. Wahrscheinlicher ist, das in 
Deinem ersten Code i tatsächlich keinen sinnvollen Wert enthielt.

>doch irgendwie passiert das bei mir nicht.
Das sollte sich durch einen Blick in das map-file bzw. Listing klären 
lassen.
Du kannst die beiden Dateien hier auch als Anhang posten.

Sag uns doch bitte noch welchen Compiler und welche Entwicklungsumgebung 
Du verwendest.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:
> Soweit hatte ich das auch verstanden, aber warum ist das Array denn im
> Flash, ich hab doch nirgendwo ein PROGMEM stehen?

Das Array ist auch nicht im Flash.
Du hast einen Fehler in den Programteilen die du nicht hergezeigt hast 
(sofern man das bischen überhaupt als 'Programteil' bezeichnen kann)

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übrigens, weitere Möglichkeit:
Was für ein Makefile benutzt du?
Zeige mal die Kommandozeile, die das hex-File erzeugt.

Autor: gregor (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe den Quellcode und die map file im Anhang.

Als Entwicklungsumgebung benutze ich Code::Blocks, zusammen mit dem 
AVR-GCC und avrdude zum upload.

avr-gcc --version
(WinAVR 20090313) 4.3.2

Habe mal ans Ende der if's einmal LEDs umschalten gehängt, LED ist 
dauerhaft eingeschaltet.

Hm... ins Makefile habe ich keinen EInblick, Code::Blocks verwendet sein 
eigenes buildsystem. Es sind die -Os, --mmcu=atmega8, -g und -msize 
Flags gesetzt.

[quote]Natürlich nicht. Der restliche nicht gezeigte Code ist ja immer
fehlerfrei.[/quote]
Sorry, so war das nicht gemeint, aber ich bin mir eben sicher, dass ich 
es noch schaffe i von 0-24 laufen zu lassen. Der Code, den du natürlich 
nicht gesehen hast, schien für mich einfach richtig.

Frage: Wie zitiert man in diesem Forum?

Danke,
Gregor

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:
> Frage: Wie zitiert man in diesem Forum?

Hat sich erledigt

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bräuchte schon genau die komplette Kommandozeile von der 
hex-File-Generierung. Also bitte entweder den Build-Output kopieren, 
oder (besser) das Makefile posten.

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ahh, hab in Code::Blocks die Einstellung gefunden, damit er im Build log 
die komplette Kommandozeile zeigt.

Hier, bitte
avr-gcc.exe -msize -mmcu=atmega8 -Os -Wall -DF_CPU=4000000UL  -g     -c main.c -o obj\Debug\main.o
avr-g++.exe  -o bin\Debug\synth.elf obj\Debug\main.o   -mmcu=atmega8 -Wl,-Map=bin\Debug\synth.elf.map,--cref  
Output size is 11.45 KB
Running project post-build steps
avr-size --mcu=atmega8 --format=avr bin\Debug\synth.elf
AVR Memory Usage
----------------
Device: atmega8
Program:    4842 bytes (59.1% Full)
(.text + .data + .bootloader)
Data:        316 bytes (30.9% Full)
(.data + .bss + .noinit)
avr-objcopy -O ihex -R .eeprom -R .eesafe bin\Debug\synth.elf bin\Debug\synth.elf.hex
avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex bin\Debug\synth.elf bin\Debug\synth.elf.eep.hex

Hoffe du kannst damit was anfangen!

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich persönlich fände ein weniger exotisches Komprimierungsformat wie zip 
oder gzip usw. gut. Diese 7z-Dateien kann ich nicht öffnen; es gibt 
nichtmal einen offiziellen Port für Debian. Und ich habe auch keine Lust 
jetzt erstmal ne Stunde zu versuchen das Ding zu kompilieren.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm.
Der Arrayzugriff sieht gut aus.
Wie hast du festgestellt, dass die ausgelesenen Werte nicht stimmen?

Deine Erlaubnis vorausgesetzt habe ich den Code mal hier hereingestellt
/*
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//#include "sin_table.h"

#define SQUARE_WAVE(x, DutyCycle) ((x<DutyCycle)?255:0)
#define SAWTOOTH_WAVE(x) (x)

volatile uint8_t g_Volume = 255;
volatile uint32_t g_PhaseStep = 1;
volatile uint32_t g_Phase = 0;

void Sleep(uint16_t Time)
{
  for(;Time>0; Time--)
    _delay_ms(1);
}

const uint16_t c_FreqTable[] =
{
  220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415,
  440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831,
  880
};


void SetFrequency(uint16_t Frequency);


int main(void)
{
  DDRB = (1<<PORTB0);
  DDRD = 0xff;

  SetFrequency(440);

  TCCR1A = 0;
  TCCR1B = (1<<CS10) | (1<<WGM12 ); // no prescaler
  TIMSK |= (1<<OCIE1A); // Timer-CTC interrupt
//  TIMSK |= (1<<OCIE1B);
  OCR1A = 500;
  sei();

  uint8_t i=0;
  while(1)
  {
    // Der Hack
    if(i==0) SetFrequency(c_FreqTable[0]);
    else if(i==1) SetFrequency(c_FreqTable[1]);
    else if(i==2) SetFrequency(c_FreqTable[2]);
    else if(i==3) SetFrequency(c_FreqTable[3]);
    else if(i==4) SetFrequency(c_FreqTable[4]);
    else if(i==5) SetFrequency(c_FreqTable[5]);
    else if(i==6) SetFrequency(c_FreqTable[6]);
    else if(i==7) SetFrequency(c_FreqTable[7]);
    else if(i==8) SetFrequency(c_FreqTable[8]);
    else if(i==9) SetFrequency(c_FreqTable[9]);
    else if(i==10) SetFrequency(c_FreqTable[10]);
    else if(i==11) SetFrequency(c_FreqTable[11]);
    else if(i==12) SetFrequency(c_FreqTable[12]);
    else if(i==13) SetFrequency(c_FreqTable[13]);
    else if(i==14) SetFrequency(c_FreqTable[14]);
    else if(i==15) SetFrequency(c_FreqTable[15]);
    else if(i==16) SetFrequency(c_FreqTable[16]);
    else if(i==17) SetFrequency(c_FreqTable[17]);
    else if(i==18) SetFrequency(c_FreqTable[18]);
    else if(i==19) SetFrequency(c_FreqTable[19]);
    else if(i==20) SetFrequency(c_FreqTable[20]);
    else if(i==21) SetFrequency(c_FreqTable[21]);
    else if(i==22) SetFrequency(c_FreqTable[22]);
    else if(i==23) SetFrequency(c_FreqTable[23]);
    else if(i==24) SetFrequency(c_FreqTable[24]);
    else PORTB = ~PORTB;

//    SetFrequency(c_FreqTable[i]); // Das klappt nicht
    i++;
    if(i >= 25)
      i=0;
    Sleep(250);
  }

    return 0;
}


void SetFrequency(uint16_t Frequency)
{
  g_PhaseStep = (uint64_t)Frequency*0xffffffff / 8000UL;
}

ISR(TIMER1_COMPA_vect)
{
  g_Phase += g_PhaseStep;

  uint8_t Index = (g_Phase >> 24);
  uint8_t Value = Index>159?64:0;

  PORTD = ((uint16_t)Value * g_Volume) >> 8;
}

Autor: gregor (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Naja schrieb:
> Ich persönlich fände ein weniger exotisches Komprimierungsformat wie zip
oder gzip usw. gut.

Sorry, daran hatte ich nicht gedacht.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Verdacht hat sich leider nicht bestätigt.

Und synth.elf.hex ist auch das, womit du dann den Controller 
programmierst? Oder vielleicht synth.elf?

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wie hast du festgestellt, dass die ausgelesenen Werte nicht stimmen?

Per DDS werden die Frequenzen über einen passiven DAC an einen 
Lautsprecher ausgegeben.

Wenn ich den Hack verwende, dann steigt der Ton tatsächlich in 1/4 
Sekundenschritten an.

Wenn ich den direkten Zugriff
SetFrequency(c_FreqTable[i]); // Das klappt nicht
verwende, dann wird die ganze Zeit ein durchgehender Ton ausgegeben.

Wer die c_FreqTable anschaut, der sieht, dass es a0 - a'' in 
Halbtonschritten ist ;)

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Laut dem Map-File liegt das im Datensegment.

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mist. Vertippt.
Sollte heissen:
Laut dem Map-File liegt das Array im Datensegment.

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schlechtes Timing :P

> Und synth.elf.hex ist auch das, womit du dann den Controller
> programmierst? Oder vielleicht synth.elf?

Ja, mit synth.elf.hex wird der Controller programmiert.

Was sagt die Mapfile? Mit dennen habe ich mich nie auseiander gesetzt 
und weiss daher nicht, wie man bei ihnen sieht, wo ein Array gespeichert 
ist.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:

> Wenn ich den Hack verwende, dann steigt der Ton tatsächlich in 1/4
> Sekundenschritten an.

> verwende, dann wird die ganze Zeit ein durchgehender Ton ausgegeben.

Hmm. Interessant.
Aber der Ton an sich ist richtig?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hat jetzt zwar nichts mit deinem Problem zu tun (denke ich), aber du 
solltest das setzen von phaseStep atomar machen
void SetFrequency(uint16_t Frequency)
{
  cli();
  g_PhaseStep = (uint64_t)Frequency*0xffffffff / 8000UL;
  sei();
}

Nicht dass dir ein Interrupt reinknallt, während g_PhaseStep seine 4 
bytes zugewiesen bekommt.

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Was sagt die Mapfile? Mit dennen habe ich mich nie auseiander gesetzt
>und weiss daher nicht, wie man bei ihnen sieht, wo ein Array gespeichert
>ist.

Die beiden wesentlichen Punkt sind:

1. Die Memory Map.

Memory Configuration



Name             Origin             Length             Attributes

text             0x00000000         0x00002000         xr

data             0x00800060         0x0000ffa0         rw !x

eeprom           0x00810000         0x00010000         rw !x

fuse             0x00820000         0x00000400         rw !x

lock             0x00830000         0x00000400         rw !x

signature        0x00840000         0x00000400         rw !x

default        0x00000000         0xffffffff


text ist das Flash, data das RAM und EEPROM .... (habe ich vergessen 
:-))

Hier (etwas später im File) dann die Adresse des Arrays.

 .data          0x00800060       0x37 obj\Debug\main.o

                0x00800065                c_FreqTable



[Klugscheissmodus]
"Die" Datei oder "das" File. Also das Map-File.
[/Klugscheissmodus]

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Hmm. Interessant.
>Aber der Ton an sich ist richtig?

Nein, leider nicht. Er ist viel zu hoch für 220Hz. Ich hab das ganze mal 
mit Audacity am PC aufgenommen und die Frequenz näherungsweise bestimmt: 
etwa 1501Hz

>Laut dem Map-File liegt das Array im Datensegment.
Also im EEPROM? Wie bekomme ich das Array da raus?

Naja, wenn am Ende nichts hilft, dann werde ich wohl die Daten mit 
EEPROM oder Flash zugriffen auslesen...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:
>
>>Laut dem Map-File liegt das Array im Datensegment.
> Also im EEPROM? Wie bekomme ich das Array da raus?

Nein.
data ist das SRAM
eeprom hat seine eigene Section

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zeit das elf-File zu posten (von der i-Variante).

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:
>>Hmm. Interessant.
>>Aber der Ton an sich ist richtig?
>
> Nein, leider nicht. Er ist viel zu hoch für 220Hz. Ich hab das ganze mal
> mit Audacity am PC aufgenommen und die Frequenz näherungsweise bestimmt:
> etwa 1501Hz

Mach mal die Absicherung gegen einen Interrupt in der SetFrequency.

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>Laut dem Map-File liegt das Array im Datensegment.
>Also im EEPROM? Wie bekomme ich das Array da raus?

Hä? Wieso EEPROM. Da war ich wohl zu lakonisch.

Data ist im Ram und liegt bei:

data             0x00800060         0x0000ffa0         rw !x

Das ist also NICHT Dein Problem.



Aber: Diese ganzen Casts sind mir etwas suspekt.

Autor: gregor (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
>du solltest das setzen von phaseStep atomar machen
Ich habe es gerade kurz versucht, aber jetzt habe deutlich hörbare 
Klopfer.

>Zeit das elf-File zu posten (von der i-Variante).
Ich habe jetzt das elf-File hochgeladen, nicht elf.hex, hoffe das war 
richtig.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> gregor schrieb:
>>>Hmm. Interessant.
>>>Aber der Ton an sich ist richtig?
>>
>> Nein, leider nicht. Er ist viel zu hoch für 220Hz. Ich hab das ganze mal
>> mit Audacity am PC aufgenommen und die Frequenz näherungsweise bestimmt:
>> etwa 1501Hz
>
> Mach mal die Absicherung gegen einen Interrupt in der SetFrequency.

Duch die direkten Zugrife hast du ein geringfügig anders Timing und 
möglicherweise einfach nur Glück, dass dir kein Interrupt während der 
4-Byte Zuweisungsaktion dazwischenknallt.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:
>>du solltest das setzen von phaseStep atomar machen
> Ich habe es gerade kurz versucht, aber jetzt habe deutlich hörbare
> Klopfer.

Das wird die 64-Bit Arithmetik sein. Dauert einfach zu lange
-> Die Interrupts nur so kurz wie möglich, aber so lange wie notwendig 
sperren
void SetFrequency(uint16_t Frequency)
{
  uint32_t tmp = (uint64_t)Frequency*0xffffffff / 8000UL;

  cli();
  g_PhaseStep = tmp;
  sei();
}

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>du solltest das setzen von phaseStep atomar machen
>Ich habe es gerade kurz versucht, aber jetzt habe deutlich hörbare Klopfer.

[bloedesgequatsche]
Ja, es wird immer erst schlimmer ehe es besser wird.
[/bloedesgequatsche]

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja schrieb:
>>>du solltest das setzen von phaseStep atomar machen
>>Ich habe es gerade kurz versucht, aber jetzt habe deutlich hörbare Klopfer.
>
> [bloedesgequatsche]
> Ja, es wird immer erst schlimmer ehe es besser wird.
> [/bloedesgequatsche]

Vor allen Dingen gibt es keine wirkliche Erklärung für einen 'falschen' 
Arrayzugriff. Ausser einem Compilerfehler. Aber daran glaube ich erst 
wenn es keine andere Möglichkeit mehr gibt, bzw wenn er im Assemblercode 
nachweisbar ist.

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Vor allen Dingen gibt es keine wirkliche Erklärung für einen 'falschen'
>Arrayzugriff.

Ich würde wirklich gerne mal das Assemblerlisting sehen. Eben den 
Aufruf:
SetFrequency(c_FreqTable[i]);

Bin gerade dabei einen ganzen Schwung commits zu machen, sonst würde ich 
mir das elf mal disassembliert anschauen.

Autor: gregor (Gast)
Datum:
Angehängte Dateien:
  • main.s (4,56 KB, 433 Downloads)

Bewertung
0 lesenswert
nicht lesenswert
Naja schrieb:
>Aber: Diese ganzen Casts sind mir etwas suspekt.
Bei setFrequency? Die Berechnung hatte ich aus Topic 89387,

Karl heinz Buchegger schrieb:
>Das wird die 64-Bit Arithmetik sein. Dauert einfach zu lange
>-> Die Interrupts nur so kurz wie möglich, aber so lange wie notwendig
>sperren
Hab deinen Vorschlag eingebaut: Jop, die Klopfer sind weg, aber der Ton 
hat immernoch eine falsche Frequenz, die sich nicht ändert.

Naja schrieb:
>Hä? Wieso EEPROM. Da war ich wohl zu lakonisch.
>Data ist im Ram und liegt bei:
Wir haben diePosts zeitlgleich losgeschickt gehabt, hatte es deswegen 
noch nicht gelesen und nur gemutmaßt ;)
Okay, aber wenn es im RAM ist, dann sollte ja der zugriff gehen?

Bin eine Assemblerniete, kann demnach nicht selbst nachschauen.
Hab mal mit
avr-gcc -Os -DF_CPU=4000000UL main.c -S -mmcu=atmega8
den Assemlber Code erstellt.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:

> Okay, aber wenn es im RAM ist, dann sollte ja der zugriff gehen?

Grundsätzlich ja.
Ich denke immer noch, das nicht der Zugriff das Problem ist, sondern 
irgendetwas anders.

> Bin eine Assemblerniete, kann demnach nicht selbst nachschauen.

Hier ist der Zugriff
  mov r30,r17
  ldi r31,lo8(0)
  lsl r30
  rol r31
  subi r30,lo8(-(c_FreqTable))
  sbci r31,hi8(-(c_FreqTable))
  ld r24,Z
  ldd r25,Z+1

sieht gut aus und ist richtig. (r17 enthält i, der Tabellenwert kommt 
nacht r24/r25)

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>den Assemlber Code erstellt.

Ah. Suppe.


Das sieht komisch aus:

/* #APP */
 ;  45 "main.c" 1
  sei
 ;  0 "" 2
/* #NOAPP */
  ldi r17,lo8(0)
  ldi r28,lo8(1000)
  ldi r29,hi8(1000)
.L23:
  mov r30,r17
  ldi r31,lo8(0)
  lsl r30
  rol r31
  subi r30,lo8(-(c_FreqTable))
  sbci r31,hi8(-(c_FreqTable))
  ld r24,Z
  ldd r25,Z+1
  rcall SetFrequency

Der Index ist konstant 0.
Schalte mal -Os aus.
Das ist die Optimierung auf Grösse. Ich weiss nicht wo das Dein Deiner 
IDE geht.

[ErinnerungenEinesProgrammiers]
Da hatte ich vor einer Woche schon mal ein Problem das ich aber 
ignorieren wollte bis ich die Rechnung schreibe.
[ErinnerungenEinesProgrammiers]

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Karl-Heinz

Das sieht gut aus für Dich? Hmm. Habe ich mich vertan?

Er lädt doch R30, R31 im Endeffekt mit 0. Oder gucke ich falsch?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja schrieb:
> @ Karl-Heinz
>
> Das sieht gut aus für Dich? Hmm. Habe ich mich vertan?
>
> Er lädt doch R30, R31 im Endeffekt mit 0.

Ja, aber nur beim ersten mal, wenn i gleich 0 ist.

Kurz danach wird r17 erhöht
Und nach dem Delay wird L23 angesprungen. Dann ist r17 nicht mehr 0
  rcall SetFrequency
  subi r17,lo8(-(1))    ; i = i + 1
  cpi r17,lo8(25)       ; if( i >= 25 )
  brlo .L21
  ldi r17,lo8(0)        ;    i = 0;
.L21:
  ldi r24,lo8(250)      ;  ab da das delay Geplänkel ....
  ldi r25,hi8(250)
.L22:
  movw r30,r28
/* #APP */
 ;  105 "d:/tools/winavr-20090313/lib/gcc/../../avr/include/util/delay_basic.h" 1
  1: sbiw r30,1
  brne 1b
 ;  0 "" 2
/* #NOAPP */
  sbiw r24,1
  brne .L22             ; ....  bis hier her
  rjmp .L23             ; und dann zurück zur Schleifenbildung

Der Code ist in Ordnung. Aber ich habe keine Idee warum deine Freuquenz 
nicht stimmt!

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Schalte mal -Os aus.
_delay_ms Meldung ignoriert ;)
Geht nicht, kein Unterschied.

Ich habe gerade etwas interessantes getestet:
Ich habe SetFrequency(c_FreqTable[i]); zu SetFrequency(c_FreqTable[0]); 
gemacht, doch er gibt immernoch den falschen Ton aus, der Zustand hat 
sich also verschlechtert!
Die einzige Änderung, die ich seit dem letzten erfolgreichen Test 
gemacht habe, war in SetFrequency die Interrupts auszuschalten.
Ich habe also cli(); und sei(); auskommentiert, da spielt er tatsächlich 
den 220Hz Ton ab!
Zugriff über den Index i will er aber immernoch nicht...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das sieht seltsam aus
.L21:
  ldi r24,lo8(250)
  ldi r25,hi8(250)
.L22:
  movw r30,r28
  1: sbiw r30,1
  brne 1b

  sbiw r24,1
  brne .L22

Das sind doch nie und nimmer 250 Millisekunden

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Das sieht seltsam aus
>
> .L21:
>   ldi r24,lo8(250)
>   ldi r25,hi8(250)
> .L22:
>   movw r30,r28
>   1: sbiw r30,1
>   brne 1b
> 
>   sbiw r24,1
>   brne .L22
> 
>
> Das sind doch nie und nimmer 250 Millisekunden

Shit

  ldi r28,lo8(1000)
  ldi r29,hi8(1000)

Doch, könnte hinkommen

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:

> Die einzige Änderung, die ich seit dem letzten erfolgreichen Test
> gemacht habe, war in SetFrequency die Interrupts auszuschalten.
> Ich habe also cli(); und sei(); auskommentiert,

Das ist kontraproduktiv.
Du brauchst die Sicherung beim Schreiben auf g_PhaseStep. Während des 
Schreibvorganges müssen die Interrupts deaktiviert sein, sonst ist nicht 
garaniert, dass die ISR auf ein intaktes und in sich stimmiges 
g_PhaseStep zugreift.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:

> Das sind doch nie und nimmer 250 Millisekunden

Doch, sind es. Ich hatte nämlich vor ein paar Minuten exakt den selben 
Gedanken. ;-)

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Das ist kontraproduktiv.
Das ist mir (inzwischen) klar, es war ja nur ein Test. Der ein seltsames 
Ergebnis hatte. Inzwischen hab ich es wieder einkommentiert, nur das 
jetzt nicht mal mehr der Hack mit den vielen ifs vom Anfang geht.

Bei der Assemblerdiskussion kann ich leider nicht mitmachen...

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im elf-File sieht es ein wenig anders aus, anderes Register für i, 
SetFrequency ge-inlined, aber ich kann nichts finden.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gregor schrieb:

> Das ist mir (inzwischen) klar, es war ja nur ein Test. Der ein seltsames
> Ergebnis hatte. Inzwischen hab ich es wieder einkommentiert, nur das
> jetzt nicht mal mehr der Hack mit den vielen ifs vom Anfang geht.

Könntest du davon bitte nochmal den Code posten?

Autor: Naja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Karl-Heinz

Hast recht. Der Index ist in Ordnung.

Das Delay sieht auch gut aus.

Seltsam.

Autor: gregor (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:
>Könntest du davon bitte nochmal den Code posten?
War mir nicht sicher welchen du wolltest:

Im ZIP sind zwei Ordner: ton_richtig (cli und sei auskommentiert) und 
ton_falsch (cli und sei im Code drinne).
Beide Ordner enthalten jeweils den Assembler-Code, C-Code und das 
elf-File des jeweiligen Übersetzervorgangs.

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ähh, ignoriert die beiden Dateien im zip, die nicht in den beiden 
Ordnern liegen :P Feler mainersaits :)

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Vollständigkeit halber:
Der Vektor liegt praktisch sowohl im .text- als auch im .data-Segment. 
Schließlich wird er wohl kaum ins RAM teleportiert :-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So sehr ich auch suche. Ich finde nichts!

Du bist sicher, dass die Berechnung stimmt?
(Nicht dass deine jetzige Frequenz mit dem cli-sei die richtige ist, 
und die sich so gut anhörenden ohne cli-sei eigentlich falsch sind und 
sich nur durch den cli-sei Fehler richtig anhören)

Hintergrund: Die Berechnung sieht für mich nämlich auf den ersten Blick 
seltsam aus. Eine Multiplikation mit 0xffffffff kommt selten genug vor.

Genauso wie das hier

  uint8_t Index = (g_Phase >> 24);
  uint8_t Value = Index>159?64:0;

Warum 159? (Ok ist nur ein Treshhold Wert aber immerhin)

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Sven:
Hat das auf das Problem eine Auswirkung?

gregor schrieb:
>Feler mainersaits :)
Wo wir gerade dabei sind, ich hab einen fehler beim Messen der Frequenz 
gemacht (ich sag aber nicht was, ist mir zu peinlich). Die Frequenz 
liegt im Berech von 667Hz bis 723Hz, die Rechteckswellenfrequenz 
schwankt also leicht (Mess-, Programm-, Aufnahmefehler?).

Ich denke aber nicht, dass es etwas erklärt, jedenfalls sagen mir die 
Werte nichts besonderes.


Die Berechnung habe ich aus diesem Thread
Beitrag "DDS-Direct Digital Synthesis"

Karl schrieb:
>Nicht dass deine jetzige Frequenz mit dem cli-sei die richtige ist,
Wie oben gesagt, die Frequenz mit cli-sei ist 667Hz oder mehr.
Ich hab jetzt nochmal ohne cli-sei gemessen: 221Hz, das kann ich als 
Messfehler verbuchen :P

Hinzu kommt, dass bei cli-sei + if-Hack die Frequenz IMMER gleich 
bleibt, sie ändert sich nur, wenn ich das cli-sei weg mache...



Hmm.... hast du einen Vorschlag was ich machen soll? Wenn ich ehrlich 
bin finde ich das Projekt viel zu spannend als es in die Tonne zu 
treten.
Rewrite wäre mehr als verschmerzlich, weill es ja nur extrem wenig Code 
ist, nur ist die Frage, ob der Fehler weg ist?

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Genauso wie das hier
>  uint8_t Index = (g_Phase >> 24);
Ich verwende aus der Phase nur die oberen 8 bits für den DAC, die 
Widerstandsleiter hat halt keine höhrere Auflösung ;)


> Warum 159? (Ok ist nur ein Treshhold Wert aber immerhin)
Das ist vom Spielen mit Tastverhältnissen übrig. Ursprünglich hatte ich 
da 127, dann 32 und dann 159. Habs aber nicht mehr geändert :) Noch 
früher habe ich da eine Sägezahnwelle ausgegeben. Da vermute ich keinen 
Fehler.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und du verwendest auch einen ATmega8 ja?

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und du verwendest auch einen ATmega8 ja? Warum eigentlich avr-g++ fürs 
linken? Nehm da doch auch mal den avr-gcc.

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon K. schrieb:
>Und du verwendest auch einen ATmega8 ja?
Japp, habe nix anderes (außer einem ATmega644, der ist aber noch nicht 
ausprobiert worden).

>Warum eigentlich avr-g++ fürs linken? Nehm da doch auch mal den avr-gcc.
Hm.. bei Code::Blocks war avr-g++ als Linker eingetragen, habe es in 
avr-gcc geändert und nochmal ein vorher nicht funktionierendes Programm 
compiliert. Leider geht es immernoch nicht.

Trotzdem danke für den Hinweis

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es müsste doch heissen
if (i < 25)
    SetFrequency(c_FreqTable[i]);
else 
     PORTB = ~PORTB;
anstatt
SetFrequency(c_FreqTable[i]); // Das klappt nicht

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jonathan
Das PORTB = ~PORTB hatte ich nur eingefügt um zu schauen, ob beim langen 
if-Block ein ungültiger Wert auftritt.


Aber nun eine freudige Ankündigung: DO NOT WANT!!!!!!!
Ich habe das Problem gelöst. Tatsächlich lag das Problem in 
SetFrequency, ich hab mir die "Formeln" die ich übers DDS gefunden hatte 
noch mal angeschaut .. und keinen unterschied gefunden.
Ich hab aber den 32bit Phasenakkumulator durch einen 16bit Akku ersetzt, 
dementsprechend muss ich mit 0xffff mutliplizieren. Und was soll man 
sagen: so geht es!

Ich habe aber keine Erklärung, warum es mit den größeren Zahlen nicht 
funktioniert hat, vor allem warum es, zum Teil, mit den konstanten 
Indexangaben funktioniert hat...

Also, für alle die es interessiert, hier der komplette, funktionierende 
Code:
/*
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//#include "sin_table.h"

#define SQUARE_WAVE(x, DutyCycle) ((x<DutyCycle)?255:0)
#define SAWTOOTH_WAVE(x) (x)

volatile uint8_t g_Volume = 255;
volatile uint16_t g_PhaseStep = 1;
volatile uint16_t g_Phase = 0;

void Sleep(uint16_t Time)
{
  for(;Time>0; Time--)
    _delay_ms(1);
}

const uint16_t c_FreqTable[] =
{
  220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415,
  440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831,
  880
};


void SetFrequency(uint16_t Frequency);


int main(void)
{
  DDRB = (1<<PORTB0);
  DDRD = 0xff;

  SetFrequency(440);

  TCCR1A = 0;
  TCCR1B = (1<<CS10) | (1<<WGM12 ); // no prescaler
  TIMSK |= (1<<OCIE1A); // Timer-CTC interrupt
//  TIMSK |= (1<<OCIE1B);
  OCR1A = 500;
  sei();

  uint8_t i=0;
  while(1)
  {
    // Der Hack
//    if(i==0) SetFrequency(c_FreqTable[0]);
//    else if(i==1) SetFrequency(c_FreqTable[1]);
//    else if(i==2) SetFrequency(c_FreqTable[2]);
//    else if(i==3) SetFrequency(c_FreqTable[3]);
//    else if(i==4) SetFrequency(c_FreqTable[4]);
//    else if(i==5) SetFrequency(c_FreqTable[5]);
//    else if(i==6) SetFrequency(c_FreqTable[6]);
//    else if(i==7) SetFrequency(c_FreqTable[7]);
//    else if(i==8) SetFrequency(c_FreqTable[8]);
//    else if(i==9) SetFrequency(c_FreqTable[9]);
//    else if(i==10) SetFrequency(c_FreqTable[10]);
//    else if(i==11) SetFrequency(c_FreqTable[11]);
//    else if(i==12) SetFrequency(c_FreqTable[12]);
//    else if(i==13) SetFrequency(c_FreqTable[13]);
//    else if(i==14) SetFrequency(c_FreqTable[14]);
//    else if(i==15) SetFrequency(c_FreqTable[15]);
//    else if(i==16) SetFrequency(c_FreqTable[16]);
//    else if(i==17) SetFrequency(c_FreqTable[17]);
//    else if(i==18) SetFrequency(c_FreqTable[18]);
//    else if(i==19) SetFrequency(c_FreqTable[19]);
//    else if(i==20) SetFrequency(c_FreqTable[20]);
//    else if(i==21) SetFrequency(c_FreqTable[21]);
//    else if(i==22) SetFrequency(c_FreqTable[22]);
//    else if(i==23) SetFrequency(c_FreqTable[23]);
//    else if(i==24) SetFrequency(c_FreqTable[24]);
//    else PORTB = ~PORTB;

    SetFrequency(c_FreqTable[i]); // Das klappt nicht
    i++;
    if(i >= 25)
      i=0;
    Sleep(250);
  }

    return 0;
}


void SetFrequency(uint16_t Frequency)
{
  uint16_t tmp = (uint64_t)Frequency*0xffff / 8000UL;
  cli();
  g_PhaseStep = tmp;
  sei();
}

ISR(TIMER1_COMPA_vect)
{
  g_Phase += g_PhaseStep;

  uint16_t Index = (g_Phase >> 8);
//  uint8_t Value = Index>159?64:0;
  uint8_t Value = Index;

  PORTD = ((uint16_t)Value * g_Volume) >> 8;
}

Autor: gregor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry wenn ich ein bisschen spamme, aber das muss sein:

Ich möchte mich ganz arg bei allen bedanken, die versucht haben mir zu 
helfen und ihre Zeit dafür geopfert haben und ganz besonders großen Dank 
an Karl, dass er mich auf die richtige Spur geführt hat!!

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.