Forum: Mikrocontroller und Digitale Elektronik AVR/GCC: pgm_read_byte funktioniert, pgm_read_word nicht?


von Andi M. (rootsquash)


Lesenswert?

Hallo,

ich habe ein kleines Problem mit dem Zugriff auf den Flash-Speicher:
ATMega8 (8 KB Flash)
Programm belegt ~4 oder ~5 KB

Geht:
uint8_t b[22][7] = {...}
const uint8_t array[16][100] PROGMEM = {...}
pwm_setting[i] = pgm_read_byte (&array[b[i][6]-1][b[i][2]]);

Geht nicht:
uint8_t b[22][7] = {...}
const uint16_t array[16][100] PROGMEM = {...}
pwm_setting[i] = pgm_read_word (&array[b[i][6]-1][b[i][2]]);


Wenn ich meine Beobachtungen korrekt interpretiere liefert die Funktion 
häufig "0" statt einen Wert aus "array".
Genauer kann ich die eingelesenen Werte frühestens heute Abend angucken 
wenn ich ein Display an den µC hänge, aber vielleicht sieht ja schon 
jemand was da kaputt ist, mir sind die Ideen ausgegangen:
Habe ich da irgendwas grob falsch gemacht oder benötigt pgm_read_word 
vielleicht einfach 1000 Zyklen?

Grüße, "Rootsquash"

von Falk B. (falk)


Lesenswert?

@ Andi M. (rootsquash)

>Geht nicht:
>uint8_t b[22][7] = {...}
>const uint16_t array[16][100] PROGMEM = {...}
>pwm_setting[i] = pgm_read_word (&array[b[i][6]-1][b[i][2]]);

Spar dir solchen Käse un poste VOLLSTÄNDIGEN, OROIGINALEN Code, am 
besten als Anhang.

>Habe ich da irgendwas grob falsch gemacht

Ja, aber in dem Stück Code, das wir nicht sehen.

>oder benötigt pgm_read_word
>vielleicht einfach 1000 Zyklen?

Nö.

von Andi M. (rootsquash)


Angehängte Dateien:

Lesenswert?

So, bin wieder an einem Computer: Original-Quelltext ist im Anhang. Es 
handelt sich um die Software aus dem Artikel Soft_PWM, aufgebläht auf 
mehr Auflösung und etwa 20 Kanäle. Die Werte sollen aus einer Tabelle 
gelesen werde.
Ich dachte das hätte ich fertig in der Schublade liegen, bei genauerem 
Hinsehen zeigen sich aber immer wieder unerwünsche Werte im 
Ausgangssignal*.
Jetzt wollte ich es etwas beschleunigen indem ich nur einen Wert aus dem 
Flash lese, nicht 2, aber dann flackern die LEDs an den Ausgängen ganz 
furchtbar, so als gingen sie nur jedes x-te Mal an. Der programmierte 
Verlauf ist mit etwas gutem Willen aber erkennbar.

Es scheint also irgendwas schief zu gehen wenn ich mit pgm_read_word 
einen Wert aus einem uint16_t array lese.


Grüße, "Rootsquash"


* Wenn ich
"pwm_setting[i] = pgm_read_word (&nichtlinear_array[pwm_setting[i]]); 
// Benötigte Pulsbreite raussuchen"
auskommentiere sind die Verläufe im Prinzip so wie ich es gern möchte, 
aber linear.
Wenn ich die Zeile mit rein nehme bleibt die LED immer mal wieder aus, 
so als wäre pwm_setting[i] ab und zu einfach 0.
Ich habe übers Wochenende leider nur ein HM 312 als Oszilloskop, das ist 
keine so besonders zuverlässige Informationsquelle bei Digitalsignalen.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Andi M. (rootsquash)

>Jetzt wollte ich es etwas beschleunigen indem ich nur einen Wert aus dem
>Flash lese, nicht 2, aber dann flackern die LEDs an den Ausgängen ganz
>furchtbar, so als gingen sie nur jedes x-te Mal an. Der programmierte
>Verlauf ist mit etwas gutem Willen aber erkennbar.

Naja, da sind glaube ich noch ein paar Bugs drin, auch wenn ich im 
Moment nicht alles überblicke.

portstatus_table[i][0]++;        // PWmodulierstes Signal wurde 
ausgegeben

Diese Zeile macht rein gar nichts.

portstatus_table[i][2]++;            // Aktuellen Wert neu setzen: Wert 
aus nächster Spalte holen

Die auch nicht.

Wenn gleich die verschachtelte Indizierung des Arrays etwas 
furchteinflößend ist, sollte sie denoch funktionieren. Der Fehler liegt 
eher in deiner Steuertabelle sowie deren Auswertung.

von Andi M. (rootsquash)


Lesenswert?

Falk Brunner schrieb:

> portstatus_table[i][0]++;        // PWmodulierstes Signal wurde
> ausgegeben
>
> Diese Zeile macht rein gar nichts.

Die Zeile zählt einen Eintrag hoch, damit ich den Wert mehrfach ausgeben 
lassen kann bevor der nächste gelesen wird, falls ich die Breite des 
PWM-Signals nicht alle 10 ms ändern möchte, sondern nur alle n*10 ms.


> portstatus_table[i][2]++;            // Aktuellen Wert neu setzen: Wert
> aus nächster Spalte holen
>
> Die auch nicht.

portstatus_table[i][2] gibt an an welcher Stelle des Signalverlaufs das 
Programm gerade ist. Sonst, würde ich immer nur den ersten Wert aus 
meiner Zeile kriegen.

In der Tabelle stelle ich ein ob ich einen Sägezahn, einen Sinus oder 
sonstwas haben möchte usw., wirklich "getan" wird aber tatsächlich erst 
hier etwas:

pwm_setting[i] = pgm_read_byte 
(&verlaufs_array[portstatus_table[i][6]-1][portstatus_table[i][2]]); 
// Wert lesen

Diese Werte landen dann durch pwm_update via double_buffering auf den 
Ausgängen.


> Wenn gleich die verschachtelte Indizierung des Arrays etwas
> furchteinflößend ist, sollte sie denoch funktionieren. Der Fehler liegt
> eher in deiner Steuertabelle sowie deren Auswertung.

Mh, da werde ich morgen nochmal drüber nachdenken müssen. Vielleicht 
schreibe ich es auch nochmal neu.. ich weiß blos nicht ob ich dabei dann 
irgendwas anders machen werde.

Vielen Dank für die Antworten und Grüße, "Rootsquash"

von Andi M. (rootsquash)


Lesenswert?

Guten Morgen!

Die Helligkeitssprünge konnte ich beseitigen: Beim Neuformatieren fand 
ich ein überschüssiges Komma in meiner Tabelle, jetzt ist das 
Ausgangssignal schön "glatt".

Im Prinzip funktioniert3 es jetzt also, das Problem mit dem 
pgm_read_word war so aber noch nicht gelöst:
Wenn ich direkt den 16 Bit-Wert ausgelesen habe flackerten die LEDs 
ziemlich wild. Daraufhin habe ich einfach aus Spaß mal
#define PWM_STEPS     768
auf 256 gesetzt, schon ging es.
Dann habe ich den Wert nach und nach wieder auf 768 erhöht.. und es tut 
immernoch was es soll.
Kann bei der Verwendung von pgm_read_... notwendig werden immer wieder 
"make clean" aufzurufen?
Anders kann ich mir gerade nicht wirklich erklären warum sich das System 
nicht ordentlich deterministisch verhält.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Andi M. schrieb:
> Kann bei der Verwendung von pgm_read_... notwendig werden immer wieder
> "make clean" aufzurufen?

Falls dein Makefile korrekt ist: Nein.


Und anstsatt progmem+pgm_read geht das einfacher mit __flash.

von Andi M. (rootsquash)


Lesenswert?

Johann L. schrieb:
> Andi M. schrieb:
>> Kann bei der Verwendung von pgm_read_... notwendig werden immer wieder
>> "make clean" aufzurufen?
>
> Falls dein Makefile korrekt ist: Nein.

Mh, das Ding habe ich nicht selbst gebaut :-/

> Und anstsatt progmem+pgm_read geht das einfacher mit __flash.

Oh, schick.
Mein Editor versteht __flash leider nicht, aber es natürlich schöner zu 
schreiben, danke für den Tipp.

von Jörg E. (jackfritt)


Lesenswert?

Johann L. schrieb:
> Andi M. schrieb:
>> Kann bei der Verwendung von pgm_read_... notwendig werden immer wieder
>> "make clean" aufzurufen?
>
> Falls dein Makefile korrekt ist: Nein.
>
>
> Und anstsatt progmem+pgm_read geht das einfacher mit __flash.

__flash kenn ich noch nich. Gibs beispiele?

von Andi M. (rootsquash)


Lesenswert?

Jörg Esser schrieb:
> Johann L. schrieb:
>> Andi M. schrieb:
>>> Kann bei der Verwendung von pgm_read_... notwendig werden immer wieder
>>> "make clean" aufzurufen?
>>
>> Falls dein Makefile korrekt ist: Nein.
>>
>>
>> Und anstsatt progmem+pgm_read geht das einfacher mit __flash.
>
> __flash kenn ich noch nich. Gibs beispiele?

Steht (leicht zu übersehen) in 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial

Zitat:
__flash und Embedded-C[Bearbeiten]

Ab Version 4.7 unterstützt avr-gcc Adress-Spaces gemäß dem Embedded-C 
Dokument ISO/IEC TR18037. Der geläufigste Adress-Space ist __flash, der 
im Gegensatz zu progmem kein GCC-Attribut ist, sondern ein Qualifier und 
damit ähnlich verwendet wird wie const oder volatile.

GCC kennt keine eigene Option zum Aktivieren von Embedded-C, es wird als 
GNU-C Erweiterung behandelt. Daher müssen C-Module, die Address-Spaces 
verwenden, mit -std=gnu99 compiliert werden.

static const __flash int value = 10;

int get_value (void)
{
  return value;
}
Im Gegensatz zu progmem sind keine speziellen Bibliotheksfunktionen oder 
-makros für den Zugriff mehr notwendig: Der Code zum Lesen der Variable 
ist "normales" C.
Die Variable wird im richtigen Speicherbereich (Flash) angelegt.
__flash ist nur zusammen mit read-only Objekten oder Zeigern, d.h. nur 
zusammen mit const, erlaubt.
Zugriffe wie im obigen Beispiel können (weg)optimiert werden. Das 
Beispiel entspricht einem "return 10". Es besteht keine Notwendigkeit, 
für value überhaupt Flash-Speicher zu reservieren.
Auch Zeiger-Indirektionen sind problemlos möglich. Zu beachten ist, dass 
__flash auf der richtigen Seite des "*" in der Zeigerdeklaration bzw. 
-definition steht:

Rechts vom *: Der Zeiger selbst liegt im Flash
Links vom *: Der Zeiger enthält eine Flash-Adresse
// val ist eine Variable im Flash
const __flash int val = 42;

// pval liegt auch im Flash und enthält die Adresse von val
const __flash int* const __flash pval = &val;

char get_val (void)
{
  // liest den Wert von val über die in pval abgelegte Adresse
  return *pval;
}

von Jörg E. (jackfritt)


Lesenswert?

Jaaa jetz endlich 14.2.2 ok. Danke
Habe nicht
Lang genug gelesen, sorry immer diese Ungeduld.

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.