Probleme mit Memcpy_p

Hallo Community,

ich habe ein Problem mit dem kopieren von einem kleinen Array aus dem Progmem in ein größeres Array im dynamischen Speicher. Ich möchte es gern verstehen.

Auszug aus dem Coding

#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(x[0]))

// servo counter
const int numberOfServos = 12;

const int framesWalkFwd[19][numberOfServos] PROGMEM = { { 9707, 6607, 9000, 5900, 10400, 9000, 7200, 9000, 9800, 9000, 6700, 9000 },
                                                        { 12081, 7946, 9000, 5900, 11871, 9000, 5829, 9000, 9800, 9000, 6700, 9000 },
                                                        { 12357, 8266, 9000, 5900, 12048, 9000, 5652, 9000, 9800, 9000, 6700, 9000 },
                                                        ...

int currentFrames[32][numberOfServos];

void moveForeward() {
  memcpy_P(currentFrames, framesWalkFwd, NUM_ELEMENTS(framesWalkFwd));

  for (uint8_t f = 0; f < NUM_ELEMENTS(framesWalkFwd); f++) {
    for (uint8_t s = 0; s < numberOfServos; s++) {
      // Serial.print((String)f+"#"+currentFrames[f][s] + "#");
      // Serial.print(f);Serial.print("|");Serial.print(currentFrames[f][s]);
      currentFrames[f][s] = currentFrames[f][s] - 9000;
      Serial.print(currentFrames[f][s]);Serial.print("#");
    }
    Serial.println("");
  }

  while (1) {};
}

Die serielle Ausgabe ergibt folgendes

707#-2393#0#-3100#1400#0#-1800#0#800#-8960#-9000#-9000#
-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#
-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#

Ursprünglich hatte ich im Progmem negative Werte. Dazu habe ich gelesen, dass das nicht unterstütz wird. Deshalb habe ich in der Datenquelle 9000 addiert und ziehe sie nach dem kopieren wieder ab.

Egal was ich tue... ab einem Wert stimmen die Werte im dynamischen Speicher einfach nicht mehr. Erst dachte ich, dass das Problem bei späteren Berechnungen liegt (float) denn die Servos machten was sie wollten, aber nicht was sie sollten.

Nun habe ich erkannt, dass das Problem ganz am Anfang liegt, nämlich daran, dass die Werte nicht vollständig aus dem Progmem übernommen werden.

Was ist die Ursache bzw. wo ist mein Denkfehler :frowning: Ach ja... es handelt sich um einen Arduino Nano.

Wer hat dir das geschrieben?
Der/Die/Das hat 3 Monate Urlaub auf einer Streckbank eigener Wahl verdient!

Übrigens:
Dein Code ist untestbar

Zudem hast du vergessen zu sagen, warum du das "so" tun willst.

Ich finde den Link nicht mehr. ich habe im Verlauf nur noch den hier gefunden. Aber glaube mir das es irgendwo stand. Ich hätte mir sonst nicht die Mühe gemacht mein Excel umzubauen in dem ich die Werte habe und mir das Coding für das Array "generiere".

Ich habe dir ein lauffähiges Programm erzeugt. Ich hatte geschrieben, dass es nur Auszüge sind. Bin nicht davon ausgegangen, dass es jemand testen möchte, da ihr mit Eurer Expertise vermutlich auch "theoretisch" schon wisst, was die Ursache ist.

#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(x[0]))

// servo counter
const int numberOfServos = 12;

const int framesWalkFwd[3][numberOfServos] PROGMEM = { { 9707, 6607, 9000, 5900, 10400, 9000, 7200, 9000, 9800, 9000, 6700, 9000 },
                                                       { 12081, 7946, 9000, 5900, 11871, 9000, 5829, 9000, 9800, 9000, 6700, 9000 },
                                                       { 12357, 8266, 9000, 5900, 12048, 9000, 5652, 9000, 9800, 9000, 6700, 9000 } };

int currentFrames[32][numberOfServos];

void setup() {
  Serial.begin(9600);

  memcpy_P(currentFrames, framesWalkFwd, NUM_ELEMENTS(framesWalkFwd));

  for (uint8_t f = 0; f < NUM_ELEMENTS(framesWalkFwd); f++) {
    for (uint8_t s = 0; s < numberOfServos; s++) {
      currentFrames[f][s] = currentFrames[f][s] - 9000;
      Serial.print(currentFrames[f][s]);
      Serial.print("#");
    }
    Serial.println("");
  }

  while (1) {};
}

void loop() {
  // nichts mehr zu tun
}

Der serielle Output dazu... der erste Wert stimmt noch, dann bricht das Chaos aus.

707#-8793#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#
-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#
-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#-9000#

Übrigens Danke für das Makro (ich glaube es ist eins). Das habe ich von dir aus einem anderen Threat.

Hier noch die Originalwerte. Diese hätte ich gern in meinem Array...

{707,-2393,0,-3100,1400,0,-1800,0,800,0,-2300,0},
{3081,-1054,0,-3100,2871,0,-3171,0,800,0,-2300,0},
{3357,-734,0,-3100,3048,0,-3348,0,800,0,-2300,0},

Hallo,

nicht testbarer Sketch ist immer doof.
Habe deshalb anders verkürzt ein Bsp. erstellt.
memcpy_P funktioniert nur wenn Quelle und Ziel im Flash liegen.
Wenn man nur aus dem Flash lesen möchte muss man Hilfsfunktionen bemühen.
pgm_read... Link
Davon gibt es je nach Datentyp die passenden.

Die nächste Frage ist auch berechtigt, warum du alles aus dem Flash in den RAM kopieren möchtest. Dann muss man es auch nicht im Flash halten.

const unsigned int dataFlash [] PROGMEM {
  9707, 6607, 9000, 5900, 10400, 9000, 7200, 9000, 9800, 9000, 6700, 9000
};

const unsigned int ANZAHL {sizeof(dataFlash) / sizeof(dataFlash[0])};

unsigned int dataRAM [ANZAHL];
                                           
void copyData (void) {
  for (unsigned int i=0; i<ANZAHL; i++)  {   
    const unsigned int var {pgm_read_word_near(dataFlash + i)};   
    dataRAM[i] = var;
    Serial.print("Flash "); Serial.print(var); Serial.print('\t');
    Serial.print(" RAM ");  Serial.println(dataRAM[i]);
  }
}

void setup (void)
{ 
  Serial.begin(9600);
  Serial.println("\n RESET \n");
  copyData();
}

void loop(void)
{         

}    

Eins vielleicht, aber nicht meins.
Solche Makros habe ich seit Jahren nicht mehr geschrieben/publiziert.
Sowas braucht man nicht mehr.

Aber glaube mir das es irgendwo stand.

Iss klar....
Machst du alles, was irgendwo steht, ohne nachzudenken?

#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(x[0]))

// servo counter
const int numberOfServos = 12;

const int framesWalkFwd[3][numberOfServos] PROGMEM = { { 9707, 6607, 9000, 5900, 10400, 9000, 7200, 9000, 9800, 9000, 6700, 9000 },
                                                       { 12081, 7946, 9000, 5900, 11871, 9000, 5829, 9000, 9800, 9000, 6700, 9000 },
                                                       { 12357, 8266, 9000, 5900, 12048, 9000, 5652, 9000, 9800, 9000, 6700, 9000 } };

int currentFrames[32][numberOfServos];

void setup() {
  Serial.begin(9600);
  Serial.print("Zu kopierende Bytes: ");
  Serial.println(NUM_ELEMENTS(framesWalkFwd));
}

void loop() {
  // nichts mehr zu tun
}

Wenn du nur 3 Bytes kopierst, darfst du dich nicht wundern, dass es nicht tut, was du dir wünscht.

Das ist vermutlich meine Unwissenheit über die Speicher. Ich habe verschiedene solche Bewegungsabläufe aber im Nano nur wenig dynamischen Speicher. Die vermutlich dumme Idee war nun, die Bewegungsabläufe dort abzulegen wo ich genügend habe und nur den ich gerade brauche in den dynamischen Speicher zu legen.

Nein
Quelle im Flash
Ziel im RAM

Nein, aber wenn man es nicht besser weiß, ist man darauf angewiesen was man ließt. Das da genügend Schrott dabei ist, habe ich schon oft genug leidvoll erfahren müssen.

Bitte sage, dass das nicht wahr ist... ich hätte das mit 12 (Anzahl Servos) multiplizieren müssen. Und dann vermutlich nochmal mit 2 weil ein INT 2 Byte hat?

Ich habe es so in Erinnerung. Und ja... das kann ein sehr alter Beitrag gewesen sein. Aber wenn du dich davon distanzieren möchtest auch kein Problem. Es liegt mir fern, dir das anzudichten.

Hallo combie,

ja stimmt geht. :wink: Da hatte ich etwas vermehrt.

void copyData_memcpy (void) {
  for (unsigned int i=0; i<ANZAHL; i++)  {  
    memcpy_P (dataRAM, dataFlash, sizeof(dataFlash));
    const unsigned int varFlash {pgm_read_word_near(dataFlash + i)};  
    Serial.print("Flash "); Serial.print(varFlash); Serial.print('\t');
    Serial.print(" RAM ");  Serial.println(dataRAM[i]);
  }
}

Hallo,

wenn du einzelne Werte benötigst, dann am Besten wenn möglich lokal rausziehen mit pgm_read...()

  1. Es ist wahr
  2. Der Rest ist Unfug

distanzieren

Darum geht es nicht.
Es ist einfach nicht mehr nötig.
Zudem Fehlerträchtig, wie du gerade selber gesehen hast.
Bemerke: Wir sind hier in C++

Könntest du mir dann vielleicht bitte helfen, wie ich das lösen kann? Dafür wäre ich dir sehr dankbar. Also ich bin jetzt verwirrt auf was sich der 2. Punkt mit dem Unfug bezieht. Ich darf nicht mit 12 und 2 multiplizieren um die Größe der zu kopierenden Daten zu ermitteln? Wie macht man es richtig?

Siehe #9.
Man muss unterscheiden zwischen der Anzahl der enthaltenden Elemente und der Gesamtlänge des Arrays. sizeof gibt die Anzahl der Bytes zurück.

@Doc_Arduino Danke... das habe ich glatt übersehen. Mein Gott was bin ich gerade verpeilt. Sizeof ermittelt mir den Speicherbedarf. Was will ich da mit der Anzahl an "Arrayzeilen". Ich brauche das so oft an anderen Stellen... ich habe nicht darüber nachgedacht. Das muss ich mir leider eingestehen. Aber ich wurde auch mit mehreren Tagen Forschungsarbeit dafür bestraft. Der Rohrstock wurde ja abgeschafft.

Ich bekomme exakt das was ich möchte, wenn ich nur diese eine Zeile in meinem Coding anpasse. Der Rest ist gleich geblieben.

  memcpy_P(currentFrames, framesWalkFwd, sizeof(framesWalkFwd));