AVR, Sinustabelle zu groß für den Speicherplatz

Gast #3298393
Lesenswert?

Hallo,

ich habe die Sinusfunktion und die Arcuscosinusfunktion mit Hilfe einer 
Tabelle programmiert.
Leider sind die Tabellen mit 2000 Werten jeweils zu groß, so dass der 
compiler immer folgende Speicherbelegung angibt. Eigentlich sollen die 
Tabellen auch noch doppelt so groß werden als sie jetzt sind.
Gibt es eine Möglcihkeit die Tabellen im anderen Speicherbereich 
abzulegen?

Gruß,
Daniel
Angehängte Dateien:
(Firma: fritzler-avr.de) #3298416
Lesenswert?

legs im Flash oder EEROM ab...
Sieht dann so aus (tiny2313):
1
#include <avr/interrupt.h>
2
#include <avr/pgmspace.h>
3
#include <avr/io.h> 
4

5
const uint8_t samples[] PROGMEM = {127, 133, 139, 146, 152, 158, 164, 170, 176, 181, 187, 192, 
6
198, 203, 208, 212, 217, 221, 225, 229, 233, 236, 239, 242, 244, 247, 249, 250, 252, 253, 253, 
7
254, 254, 254, 253, 253, 252, 250, 249, 247, 244, 242, 239, 236, 233, 229, 225, 221, 217, 212, 
8
208, 203, 198, 192, 187, 181, 176, 170, 164, 158, 152, 146, 139, 133, 127, 121, 115, 108, 102, 
9
96, 90, 84, 78, 73, 67, 62, 56, 51, 46, 42, 37, 33, 29, 25, 21, 18, 15, 12, 10, 7, 5, 4, 2, 1, 
10
1, 0, 0, 0, 1, 1, 2, 4, 5, 7, 10, 12, 15, 18, 21, 25, 29, 33, 37, 42, 46, 51, 56, 62, 67, 73, 
11
78, 84, 90, 96, 102, 108, 115, 121 };
12

13
volatile uint8_t samplewert = 127;
14
volatile uint8_t samplesprung = 20;
15
volatile uint8_t samplezeiger = 0;
16

17
 
18
int main (void) {
19
 
20
  //Portinit
21
  DDRB  = 0xff;
22
  PORTB = 127;
23
  DDRD  = (1<<PD5); //PWM
24
  
25
  //Timer0 init (PWM DAC)
26
  TCCR0A = (1<<COM0B1)|(1<<WGM01)|(1<<WGM00); //noninv. OC0B fast PWM
27
  TCCR0B = (1<<CS00); //CLK/1
28
  OCR0B  = 127;
29
  
30
  //Timer1 init (10kHz Samplerate)
31
  TCCR1A = 0;
32
  TCCR1B = (1<<WGM12)|(1<<CS10); //CTC Mode (OCR1A), CLK/1
33
  TIMSK |= (1<<OCIE1A); //CTC ISR
34
  OCR1A  = 613; //CLK/1228 = 10kHz //CLK/614 = 20kHz
35

36
  sei();
37
 
38
  while(1) {
39
  
40
    ;
41

42
  }
43
 
44

45
   return 0;
46
}
47

48
ISR (TIMER1_COMPA_vect){
49

50
  samplezeiger += samplesprung;
51
  samplezeiger &= 127;
52
  samplewert = pgm_read_byte(&samples[samplezeiger]);
53
  OCR0B = samplewert;
54
  PORTB = samplewert;
55

56
}
Moderator (Firma: Titel) Persönliche Seite #3298467
Lesenswert?

Norbert schrieb:
> Ansonsten würde es auch reichen z.B. bei einem Sinus nur eine viertel
> Periode zu speichern und dann zu spiegeln/invertieren um die anderen
> vier Quadranten zu bekommen.
Und man könnte Stützstellen speichern und dazwischen interpolieren. 
Wieviele Stützstellen nötig sind kommt auf den maximal erlaubten Fehler 
an. Aber man glaubt nicht, wie gut man einen viertel Sinus mit 10 
nichtlinearen (nicht äquidistanten) Stützpunkten hinbekommt. Denn man 
muss nur dort die Stützpunkte eng setzen, wo sich was tut.
Und das würde beim Sinus bedeuten: von 0 bis pi/8 ist das fast eine 
Gerade, von pi3/8 bis pi/2 trotz gleichem Abstand aber ganz und gar 
nicht. Deshalb müssen in diesem Bereich die Stützstellen enger sitzen.

So arbeiten z.B. auch Logikanalyzer: wenn 10ms ein '1' Pegel anliegt, 
dann wird z.B. trotz 100MHz Samplerate nur 1 Datenpaket abgespeichert:
'1' für 10ms.
#3298535
Lesenswert?

http://www.mikrocontroller.net/articles/Digitale_Sinusfunktion
Eine sehr ausführliche Arbeit zum Thema.

http://www.mikrocontroller.net/articles/Sinusgenerator_mit_IIR-Filter
Den Artikel hab ich mal angefangen. Scheint aber nicht die ideale 
Sinusgeneratormethode zu sein. Alle Methoden, die durch Rundungsfehler 
Amplitudenänderungen erfahren, sind zu kompliziert.

Auch Tabellenverfahren haben dicht unterhalb der Nyquistfrequenz ein 
Problem, ein DDS (hat auch eine Tabelle) macht in den obersten Oktaven 
Schwebungen, wenn er nicht auf ganzzahlige Teiler der Taktfrequenz 
eingestellt ist.
Gast #3298540
Lesenswert?

Danke für die Hinweise!

Ich habe meine Tabelle jetzt mit PROGMEM auf den Flash gelegt, wenn ich 
jetzt aber wieder aus dieser Tabelle lesen will, werden teilweise Werte 
zurückgeliefert, welche nicht in der Tabelle stehen.
Meine Tabelle sieht folgendermaßen aus:

const int sinusTabelle[] PROGMEM = {...};
//enthält zurzeit 1000 Einträge von 0° bis 90°

Kann ich nun mit der folgenden Zeile wieder aus dieser Tabelle lesen, 
oder muss noch etwas anderes beachtet werden?

result = pgm_read_byte(&sinusTabelle[i]);

Gruß
#3298569
Lesenswert?

Daniel schrieb:
> Okay, du hast recht.
> Das war mir nicht klar.
> Gibts denn eine Möglichkeit oder einen Befehl aus dieser Tabelle zu
> lesen?

Hast du dir mal die API zu den pgm_ Befehlen angeguckt? Da kann man auch 
größere Einheiten als Bytes lesen. Oder du legst deine Werte als Bytes 
ab, wobei 2 Bytes dann ein Wort ergeben und halt 2 mal read_byte machst 
und zusammenbaust. Du kannst den Pointer auch einfach auf uint8_t 
umbiegen und liest dann Byteweise aus deinen Ints.
Es gibt genug Möglichkeiten.

gruß cyblord
Gast #3299443
Lesenswert?

>result = sinusTabelle[i];

>Bitte den letzten Beitrag von mir ignorieren. Ich habs selbst gemerkt :)

Mit einem ARM geht das. Da gibt es diesen PROGMEM Unsinn nicht mehr.

Das liegt im Flash:
const uint16_t sinusTabelle[] = {...};

Das liegt im RAM:
uint16_t sinusTabelle[] = {...};

Beides lesen (keine Sonderbehandlung für Flash nötig):
result = sinusTabelle[i];

Alleine das ist es schon wert auf ARM zu wechseln.
Keine doppelten Funktionen mehr.

Wie wollt ihr eigentlich jemals die Galaxie verlassen wenn
ihr euch mit Controllern beschäftigt die nicht fliegen können?
Immer ein Bremsklotz am Bein. Nimm ARM statt Red Bu... Dann kannst
auch du fliegen;)
Gast #3299478
Lesenswert?

>Wie wollt ihr eigentlich jemals die Galaxie verlassen wenn

Also mir gefällt’s hier, ich gehöre nicht zu denen die per se meinen es 
ist andernorts schöner, bequemer, besser oder ........ (bitte 
zutreffendes Eintragen) ist.

Aus diesem Grunde werde ich den Unsinn auch weiterhin machen. Übrigens 
bei der Gelegenheit wird man immer mal wieder mit den zugrundeliegenden 
Funktionen konfrontiert und daran, dass es auch sinnvoll sein kann die 
anderen, zu diesem Bereich gehörenden Funktionen, zu verwenden. Compiler 
sind nämlich doof – wenn sie auch in den letzten 30 Jahren hinzugelernt 
haben.
Auch vergisst man bei der Gelegenheit nicht, warum Zugriffe aufs Flash 
langsamer sind als z.B. Zugriffe auf Konstanten im RAM – für die, die 
auf 'nen Quicky stehen.
#3299768
Lesenswert?

holger schrieb:
>>result = sinusTabelle[i];
>
> Mit einem ARM geht das. Da gibt es diesen PROGMEM Unsinn nicht mehr.
>
> Das liegt im Flash:
> const uint16_t sinusTabelle[] = {...};
>
> Das liegt im RAM:
> uint16_t sinusTabelle[] = {...};
>
> Beides lesen (keine Sonderbehandlung für Flash nötig):
> result = sinusTabelle[i];
>
> Alleine das ist es schon wert auf ARM zu wechseln.
> Keine doppelten Funktionen mehr.

Wie gesagt, bei den ATmegas geht das mittlerweile über "__flash" 
genauso. Die letzten drei Beiträge vor mir, die den ARM so hervorheben, 
ignorieren das allerdings.

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