Forum: Mikrocontroller und Digitale Elektronik Zugriff auf C-Array (Progmem) aus Inlineassembler AVR 8-Bit.


von Stefan F. (s_m_f)


Lesenswert?

Hallo,

ich habe ein kleines Problem (welches vermutlich irgendwo schon bis in's 
letzte Detail erklärt ist... nur finde ich diese Stelle nicht).

Programmiersprache ist C++ (gcc-avr), µC ist ein ATmega32u4

Ich habe ein paar Arrays im C++-Teil meines Projektes. Diese folgen 
durchweg diesem Schema:
1
extern "C"
2
{
3
  PROGMEM volatile const uint8_t data[64] = // volatile?! why?
4
  {
5
    0,1,2,3,...
6
  };
7
8
  volatile uint8_t offset = 0;
9
}

Ich muss in einem kleinen inline-assembly Teil auf vier verschiedene 
davon zugreifen, d.h. ich kann nicht einfach den g++ die Addresse in's 
Z-register (bzw. X/Y) schieben lassen sondern muss irgendwie "direkt" an 
die Adresse herankommen.
1
      "ldi        r30, pm_lo8(data)                                   \n\t"
2
      "ldi        r31, pm_hi8(data)                                   \n\t"
3
      "lds        r16, (offset)             ; range [0..255] !        \n\t"
4
      "asr        r16                       ; shift down by two bits  \n\t"
5
      "asr        r16                       ; so range is [0...63]    \n\t"
6
      "add        r30, r16                  ; add offset              \n\t"
7
      "adc        r31, r0                   ; add carry (and r0=0)    \n\t"
8
      "lpm        r17, Z                    ; load value into r17     \n\t"

Dabei habe ich verschiedene Probleme:

1. Wenn ich das Array ohne einen (zusätzlichen) 'volatile' anlege, 
bekomme ich einen 'undefined reference "data"'... und ich verstehe nicht 
warum?!
2. Es ist bestimmt ein dummer (Verständnis-)Fehler, aber die Werte die 
ich in 'r17' erhalte, sind nicht die aus dem Array sonder 
"irgendeinwasauchimmer"...

Es ist nicht das erste Mal, dass ich Assembler schreibe, wohl aber für 
AVR... Wenn also jemand so freundlich wäre, mir das Brett vorm Kopf 
abzumontieren? Ich würde gern verstehen, was ich da Dümmliches tue...

Vielen lieben Dank,
Stefan

von Stefan F. (s_m_f)


Lesenswert?

Stefan F. schrieb:
> "asr        r16                       ; shift down by two bits
> \n\t"
>       "asr        r16                       ; so range is [0...63]
> \n\t"

Das hätte natürlich ein "lsr" sein sollen... asr macht es nicht 
besser... :-P

von Rolf M. (rmagnus)


Lesenswert?

Stefan F. schrieb:
> Ich muss in einem kleinen inline-assembly Teil auf vier verschiedene
> davon zugreifen, d.h. ich kann nicht einfach den g++ die Addresse in's
> Z-register (bzw. X/Y) schieben lassen

Warum nicht?

> 1. Wenn ich das Array ohne einen (zusätzlichen) 'volatile' anlege,
> bekomme ich einen 'undefined reference "data"'... und ich verstehe nicht
> warum?!

Meine Vermutung: Wenn du aus dem C++-Code nicht darauf zugreifst und es 
auch in den Operandenlsten deines asm-Blocks nicht erwähnst, meint der 
Compiler, es wäre unbenutzt und wirft es raus.

von c-hater (Gast)


Lesenswert?

Rolf M. schrieb:

> Meine Vermutung: Wenn du aus dem C++-Code nicht darauf zugreifst und es
> auch in den Operandenlsten deines asm-Blocks nicht erwähnst, meint der
> Compiler, es wäre unbenutzt und wirft es raus.

Könnte so sein, ja. Compiler sind halt ziemlich doof, halten sich aber 
für intelligent, sogar für so intelligent, um die Einschübe der wirklich 
Intelligenten (also der Menschen) missachten zu dürfen...

Naja, zumindest, bis man ihnen klar gemacht hat, was sie nicht 
missachten dürfen...

von Stefan F. (s_m_f)


Lesenswert?

Rolf M. schrieb:
> Stefan F. schrieb:
>> Ich muss in einem kleinen inline-assembly Teil auf vier verschiedene
>> davon zugreifen, d.h. ich kann nicht einfach den g++ die Addresse in's
>> Z-register (bzw. X/Y) schieben lassen
>
> Warum nicht?

Weil es dafür zu viele sind. Ich habe drei Addressregister die ich mir 
"vorfüllen" lassen könnte (X,Y,Z). Ich habe aber vier Arrays auf die ich 
zugreifen muss.

>> 1. Wenn ich das Array ohne einen (zusätzlichen) 'volatile' anlege,
>> bekomme ich einen 'undefined reference "data"'... und ich verstehe nicht
>> warum?!
>
> Meine Vermutung: Wenn du aus dem C++-Code nicht darauf zugreifst und es
> auch in den Operandenlsten deines asm-Blocks nicht erwähnst, meint der
> Compiler, es wäre unbenutzt und wirft es raus.

Es wird aus dem C++-Code ebenfalls darauf zugegriffen. Es ist also 
vorhanden. Sogar in derselben Source-Datei. Und der Zugriff aus C++ 
funktioniert.

von Stefan F. (s_m_f)


Lesenswert?

Interessant...

... es funktioniert, wenn ich dies tue:
1
extern "C"
2
{
3
  PROGMEM volatile const uint8_t data[64] =
4
  {
5
    ...
6
  };
7
8
  volatile uint8_t offset = 0;
9
}
1
"ldi        r30, lo8(data)                                      \n\t"
2
"ldi        r31, hi8(data)                                      \n\t"
3
"lds        r16, (offset)             ; range [0..255] !        \n\t"
4
"lsr        r16                       ; shift down by two bits  \n\t"
5
"lsr        r16                       ; so range is [0...63]    \n\t"
6
"add        r30, r16                  ; add offset              \n\t"
7
"adc        r31, r0                   ; add carry (and r0=0)    \n\t"
8
"lpm        r17, Z                    ; load value into r17     \n\t"

Mit lo8()/hi8() anstelle von pm_lo8()/pm_hi8() bekomme ich jetzt die 
richtige Adresse und die richtigen Daten aus dem Array. Das Array liegt 
aber definitiv im PROGMEM. Siehe "lpm"... Zugriff auf der C++-Seite 
erfolgt über pgm_read_byte_near().

Hmm,... jetzt habe ich zwar eine funktionierende Lösung allerdings beißt 
sich diese mit dem was ich dazu in "diverser" Dokumentation finde...

Das mit dem "volatile" ist auch irritierend. /me --> confused... :-)

von EAF (Gast)


Lesenswert?

Stefan F. schrieb:
> extern "C"

Brauchst du nicht wenn du sowieso mit C++ arbeitest

Du musst dem Compiler/Linker nur das "used" verkaufen.


Siehe:
1
extern  const uint8_t  data[2] __attribute__((progmem)); 
2
extern  uint8_t offset;
3
4
const uint8_t  data[2] __attribute__((progmem,used )) =
5
{
6
    14,12
7
};
8
9
uint8_t offset __attribute__((used)) = 0;

Und dann tuts auch dein ASM Code

von Wech (Gast)


Lesenswert?

c-hater schrieb:
> Könnte so sein, ja. Compiler sind halt ziemlich doof, halten sich aber
> für intelligent, sogar für so intelligent, um die Einschübe der wirklich
> Intelligenten (also der Menschen) missachten zu dürfen...
>
> Naja, zumindest, bis man ihnen klar gemacht hat, was sie nicht
> missachten dürfen...

viell blahblah abba keine hilfe1
anung schenst du ja nicht zu habben

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.