Forum: Compiler & IDEs Array nicht in RAM


von gregor (Gast)


Lesenswert?

Hallo,

meines Wissens werden ja Arrays, sofern nicht mit PROGMEM 
gekennzeichnet, im RAM des AVRs abgelegt, doch irgendwie passiert das 
bei mir nicht.
1
// Sollte im RAM sein
2
const uint16_t c_FreqTable[] =
3
{
4
  220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415,
5
  440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831,
6
  880
7
};
8
9
// ...
10
11
SetFrequency(c_FreqTable[7]); // Korrekte Ausgabe
12
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

von Stefan E. (sternst)


Lesenswert?

gregor schrieb:
1
SetFrequency(c_FreqTable[7]); // Korrekte Ausgabe
2
SetFrequency(c_FreqTable[i]); // Müll

Tja, dann wird wohl i Müll enthalten.

von gregor (Gast)


Lesenswert?

glaube ich nicht ;)

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

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

von Jan M. (mueschel)


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.

von Stefan E. (sternst)


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.

von gregor (Gast)


Lesenswert?

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

von Naja (Gast)


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.

von Karl H. (kbuchegg)


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)

von Stefan E. (sternst)


Lesenswert?

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

von gregor (Gast)


Angehängte Dateien:

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

von gregor (Gast)


Lesenswert?

gregor schrieb:
> Frage: Wie zitiert man in diesem Forum?

Hat sich erledigt

von Stefan E. (sternst)


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.

von gregor (Gast)


Lesenswert?

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

Hier, bitte
1
avr-gcc.exe -msize -mmcu=atmega8 -Os -Wall -DF_CPU=4000000UL  -g     -c main.c -o obj\Debug\main.o
2
avr-g++.exe  -o bin\Debug\synth.elf obj\Debug\main.o   -mmcu=atmega8 -Wl,-Map=bin\Debug\synth.elf.map,--cref  
3
Output size is 11.45 KB
4
Running project post-build steps
5
avr-size --mcu=atmega8 --format=avr bin\Debug\synth.elf
6
AVR Memory Usage
7
----------------
8
Device: atmega8
9
Program:    4842 bytes (59.1% Full)
10
(.text + .data + .bootloader)
11
Data:        316 bytes (30.9% Full)
12
(.data + .bss + .noinit)
13
avr-objcopy -O ihex -R .eeprom -R .eesafe bin\Debug\synth.elf bin\Debug\synth.elf.hex
14
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!

von Naja (Gast)


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.

von Karl H. (kbuchegg)


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
1
/*
2
 */
3
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <util/delay.h>
7
//#include "sin_table.h"
8
9
#define SQUARE_WAVE(x, DutyCycle) ((x<DutyCycle)?255:0)
10
#define SAWTOOTH_WAVE(x) (x)
11
12
volatile uint8_t g_Volume = 255;
13
volatile uint32_t g_PhaseStep = 1;
14
volatile uint32_t g_Phase = 0;
15
16
void Sleep(uint16_t Time)
17
{
18
  for(;Time>0; Time--)
19
    _delay_ms(1);
20
}
21
22
const uint16_t c_FreqTable[] =
23
{
24
  220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415,
25
  440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831,
26
  880
27
};
28
29
30
void SetFrequency(uint16_t Frequency);
31
32
33
int main(void)
34
{
35
  DDRB = (1<<PORTB0);
36
  DDRD = 0xff;
37
38
  SetFrequency(440);
39
40
  TCCR1A = 0;
41
  TCCR1B = (1<<CS10) | (1<<WGM12 ); // no prescaler
42
  TIMSK |= (1<<OCIE1A); // Timer-CTC interrupt
43
//  TIMSK |= (1<<OCIE1B);
44
  OCR1A = 500;
45
  sei();
46
47
  uint8_t i=0;
48
  while(1)
49
  {
50
    // Der Hack
51
    if(i==0) SetFrequency(c_FreqTable[0]);
52
    else if(i==1) SetFrequency(c_FreqTable[1]);
53
    else if(i==2) SetFrequency(c_FreqTable[2]);
54
    else if(i==3) SetFrequency(c_FreqTable[3]);
55
    else if(i==4) SetFrequency(c_FreqTable[4]);
56
    else if(i==5) SetFrequency(c_FreqTable[5]);
57
    else if(i==6) SetFrequency(c_FreqTable[6]);
58
    else if(i==7) SetFrequency(c_FreqTable[7]);
59
    else if(i==8) SetFrequency(c_FreqTable[8]);
60
    else if(i==9) SetFrequency(c_FreqTable[9]);
61
    else if(i==10) SetFrequency(c_FreqTable[10]);
62
    else if(i==11) SetFrequency(c_FreqTable[11]);
63
    else if(i==12) SetFrequency(c_FreqTable[12]);
64
    else if(i==13) SetFrequency(c_FreqTable[13]);
65
    else if(i==14) SetFrequency(c_FreqTable[14]);
66
    else if(i==15) SetFrequency(c_FreqTable[15]);
67
    else if(i==16) SetFrequency(c_FreqTable[16]);
68
    else if(i==17) SetFrequency(c_FreqTable[17]);
69
    else if(i==18) SetFrequency(c_FreqTable[18]);
70
    else if(i==19) SetFrequency(c_FreqTable[19]);
71
    else if(i==20) SetFrequency(c_FreqTable[20]);
72
    else if(i==21) SetFrequency(c_FreqTable[21]);
73
    else if(i==22) SetFrequency(c_FreqTable[22]);
74
    else if(i==23) SetFrequency(c_FreqTable[23]);
75
    else if(i==24) SetFrequency(c_FreqTable[24]);
76
    else PORTB = ~PORTB;
77
78
//    SetFrequency(c_FreqTable[i]); // Das klappt nicht
79
    i++;
80
    if(i >= 25)
81
      i=0;
82
    Sleep(250);
83
  }
84
85
    return 0;
86
}
87
88
89
void SetFrequency(uint16_t Frequency)
90
{
91
  g_PhaseStep = (uint64_t)Frequency*0xffffffff / 8000UL;
92
}
93
94
ISR(TIMER1_COMPA_vect)
95
{
96
  g_Phase += g_PhaseStep;
97
98
  uint8_t Index = (g_Phase >> 24);
99
  uint8_t Value = Index>159?64:0;
100
101
  PORTD = ((uint16_t)Value * g_Volume) >> 8;
102
}

von gregor (Gast)


Angehängte Dateien:

Lesenswert?

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

Sorry, daran hatte ich nicht gedacht.

von Stefan E. (sternst)


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?

von gregor (Gast)


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
1
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 ;)

von Naja (Gast)


Lesenswert?

Laut dem Map-File liegt das im Datensegment.

von Naja (Gast)


Lesenswert?

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

von gregor (Gast)


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.

von Karl H. (kbuchegg)


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?

von Karl H. (kbuchegg)


Lesenswert?

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

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

von Naja (Gast)


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]

von gregor (Gast)


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...

von Karl H. (kbuchegg)


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

von Stefan E. (sternst)


Lesenswert?

Zeit das elf-File zu posten (von der i-Variante).

von Karl H. (kbuchegg)


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.

von Naja (Gast)


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.

von gregor (Gast)


Angehängte Dateien:

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.

von Karl H. (kbuchegg)


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.

von Karl H. (kbuchegg)


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
1
void SetFrequency(uint16_t Frequency)
2
{
3
  uint32_t tmp = (uint64_t)Frequency*0xffffffff / 8000UL;
4
5
  cli();
6
  g_PhaseStep = tmp;
7
  sei();
8
}

von Naja (Gast)


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]

von Karl H. (kbuchegg)


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.

von Naja (Gast)


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:
1
SetFrequency(c_FreqTable[i]);

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

von gregor (Gast)


Angehängte Dateien:

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
1
avr-gcc -Os -DF_CPU=4000000UL main.c -S -mmcu=atmega8
den Assemlber Code erstellt.

von Karl H. (kbuchegg)


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
1
  mov r30,r17
2
  ldi r31,lo8(0)
3
  lsl r30
4
  rol r31
5
  subi r30,lo8(-(c_FreqTable))
6
  sbci r31,hi8(-(c_FreqTable))
7
  ld r24,Z
8
  ldd r25,Z+1

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

von Naja (Gast)


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]

von Naja (Gast)


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?

von Karl H. (kbuchegg)


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
1
  rcall SetFrequency
2
  subi r17,lo8(-(1))    ; i = i + 1
3
  cpi r17,lo8(25)       ; if( i >= 25 )
4
  brlo .L21
5
  ldi r17,lo8(0)        ;    i = 0;
6
.L21:
7
  ldi r24,lo8(250)      ;  ab da das delay Geplänkel ....
8
  ldi r25,hi8(250)
9
.L22:
10
  movw r30,r28
11
/* #APP */
12
 ;  105 "d:/tools/winavr-20090313/lib/gcc/../../avr/include/util/delay_basic.h" 1
13
  1: sbiw r30,1
14
  brne 1b
15
 ;  0 "" 2
16
/* #NOAPP */
17
  sbiw r24,1
18
  brne .L22             ; ....  bis hier her
19
  rjmp .L23             ; und dann zurück zur Schleifenbildung

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

von gregor (Gast)


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...

von Karl H. (kbuchegg)


Lesenswert?

Das sieht seltsam aus
1
.L21:
2
  ldi r24,lo8(250)
3
  ldi r25,hi8(250)
4
.L22:
5
  movw r30,r28
6
  1: sbiw r30,1
7
  brne 1b
8
9
  sbiw r24,1
10
  brne .L22

Das sind doch nie und nimmer 250 Millisekunden

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger schrieb:
> Das sieht seltsam aus
>
1
> .L21:
2
>   ldi r24,lo8(250)
3
>   ldi r25,hi8(250)
4
> .L22:
5
>   movw r30,r28
6
>   1: sbiw r30,1
7
>   brne 1b
8
> 
9
>   sbiw r24,1
10
>   brne .L22
11
>
>
> Das sind doch nie und nimmer 250 Millisekunden

Shit

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

Doch, könnte hinkommen

von Karl H. (kbuchegg)


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.

von Stefan E. (sternst)


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. ;-)

von gregor (Gast)


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...

von Stefan E. (sternst)


Lesenswert?

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

von Stefan E. (sternst)


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?

von Naja (Gast)


Lesenswert?

@ Karl-Heinz

Hast recht. Der Index ist in Ordnung.

Das Delay sieht auch gut aus.

Seltsam.

von gregor (Gast)


Angehängte Dateien:

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.

von gregor (Gast)


Lesenswert?

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

von Sven P. (Gast)


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 :-)

von Karl H. (kbuchegg)


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)

von gregor (Gast)


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?

von gregor (Gast)


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.

von Simon K. (simon) Benutzerseite


Lesenswert?

Und du verwendest auch einen ATmega8 ja?

von Simon K. (simon) Benutzerseite


Lesenswert?

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

von gregor (Gast)


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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Es müsste doch heissen
1
if (i < 25)
2
    SetFrequency(c_FreqTable[i]);
3
else 
4
     PORTB = ~PORTB;
anstatt
1
SetFrequency(c_FreqTable[i]); // Das klappt nicht

von gregor (Gast)


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:
1
/*
2
 */
3
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <util/delay.h>
7
//#include "sin_table.h"
8
9
#define SQUARE_WAVE(x, DutyCycle) ((x<DutyCycle)?255:0)
10
#define SAWTOOTH_WAVE(x) (x)
11
12
volatile uint8_t g_Volume = 255;
13
volatile uint16_t g_PhaseStep = 1;
14
volatile uint16_t g_Phase = 0;
15
16
void Sleep(uint16_t Time)
17
{
18
  for(;Time>0; Time--)
19
    _delay_ms(1);
20
}
21
22
const uint16_t c_FreqTable[] =
23
{
24
  220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415,
25
  440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831,
26
  880
27
};
28
29
30
void SetFrequency(uint16_t Frequency);
31
32
33
int main(void)
34
{
35
  DDRB = (1<<PORTB0);
36
  DDRD = 0xff;
37
38
  SetFrequency(440);
39
40
  TCCR1A = 0;
41
  TCCR1B = (1<<CS10) | (1<<WGM12 ); // no prescaler
42
  TIMSK |= (1<<OCIE1A); // Timer-CTC interrupt
43
//  TIMSK |= (1<<OCIE1B);
44
  OCR1A = 500;
45
  sei();
46
47
  uint8_t i=0;
48
  while(1)
49
  {
50
    // Der Hack
51
//    if(i==0) SetFrequency(c_FreqTable[0]);
52
//    else if(i==1) SetFrequency(c_FreqTable[1]);
53
//    else if(i==2) SetFrequency(c_FreqTable[2]);
54
//    else if(i==3) SetFrequency(c_FreqTable[3]);
55
//    else if(i==4) SetFrequency(c_FreqTable[4]);
56
//    else if(i==5) SetFrequency(c_FreqTable[5]);
57
//    else if(i==6) SetFrequency(c_FreqTable[6]);
58
//    else if(i==7) SetFrequency(c_FreqTable[7]);
59
//    else if(i==8) SetFrequency(c_FreqTable[8]);
60
//    else if(i==9) SetFrequency(c_FreqTable[9]);
61
//    else if(i==10) SetFrequency(c_FreqTable[10]);
62
//    else if(i==11) SetFrequency(c_FreqTable[11]);
63
//    else if(i==12) SetFrequency(c_FreqTable[12]);
64
//    else if(i==13) SetFrequency(c_FreqTable[13]);
65
//    else if(i==14) SetFrequency(c_FreqTable[14]);
66
//    else if(i==15) SetFrequency(c_FreqTable[15]);
67
//    else if(i==16) SetFrequency(c_FreqTable[16]);
68
//    else if(i==17) SetFrequency(c_FreqTable[17]);
69
//    else if(i==18) SetFrequency(c_FreqTable[18]);
70
//    else if(i==19) SetFrequency(c_FreqTable[19]);
71
//    else if(i==20) SetFrequency(c_FreqTable[20]);
72
//    else if(i==21) SetFrequency(c_FreqTable[21]);
73
//    else if(i==22) SetFrequency(c_FreqTable[22]);
74
//    else if(i==23) SetFrequency(c_FreqTable[23]);
75
//    else if(i==24) SetFrequency(c_FreqTable[24]);
76
//    else PORTB = ~PORTB;
77
78
    SetFrequency(c_FreqTable[i]); // Das klappt nicht
79
    i++;
80
    if(i >= 25)
81
      i=0;
82
    Sleep(250);
83
  }
84
85
    return 0;
86
}
87
88
89
void SetFrequency(uint16_t Frequency)
90
{
91
  uint16_t tmp = (uint64_t)Frequency*0xffff / 8000UL;
92
  cli();
93
  g_PhaseStep = tmp;
94
  sei();
95
}
96
97
ISR(TIMER1_COMPA_vect)
98
{
99
  g_Phase += g_PhaseStep;
100
101
  uint16_t Index = (g_Phase >> 8);
102
//  uint8_t Value = Index>159?64:0;
103
  uint8_t Value = Index;
104
105
  PORTD = ((uint16_t)Value * g_Volume) >> 8;
106
}

von gregor (Gast)


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!!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.