¿Como usar memmove para replicar datos desde la memoria FLASH a la SRAM?

Hola,

Tengo un problema que no he podido resolver y quisiera pedir su ayuda para solucionarlo, se trata de lo siguiente:

Estoy desarrollando un programa para un display POV de 16 leds RGB indexables, la imagen la tengo almacenada en una matriz bidimensional que se declara de una forma parecida a esta

#define ANCHO 10
#define ALTO 16


typedef CRGB TPixels [ALTO]; //CRGB es un tipo de datos que almacena 3 bytes




CRGB leds[ALTO]; //arreglo de leds indexables

TPixels pixels []={
  {0xFFFFFF,,,,,,,0xFFFFFF},
  {0xFFFFFF,,,,,,,0xFFFFFF},
   {}
   .....
};

declaro despues un apuntador para almacenar la direccion en la que se encuentra el arreglo pixels

const CRGB *ptr= &(pixels[0][0]);

y finalmente muevo al arreglo de leds cada columna

for(int i=0; i<ANCHO; i++)
{
  memmove(leds,ptr+i*ALTO,sizeof(TPixels))
}

todo esto funciona bien, sin embargo, estoy tratando de utilizar la misma tecnica para un arreglo de 64 pixels de ALTO por lo que requiero almacenar los valores de la imagen en la memoria FLASH, de tal modo que estoy usando la macro PROGMEM de la siguiente forma:

 TPixels const pixels [] PROGMEM={
  {0xFFFFFF,,,,,,,0xFFFFFF},
  {0xFFFFFF,,,,,,,0xFFFFFF},
   {}
   .....
};

y dejo el resto del codigo igual, en ese caso, lo que recibo es basura; pero si quito la macro PROGMEM funciona correctamente!! despues de varios dias de investigar estoy convencido que el problema radica en la forma en que estoy intentando leer los datos almacenados en la flash, el punto es que no soy muy diestro en el uso de apuntadores y estoy realmente confundido en esto

Asi pues, mi duda consiste en lo que debo hacer para seguir usando la funcion memmove en mi programa pero trayendo datos desde la flash a la sram, cualquier opinion sera muy bienvenida

saludos cordiales

Hola. Los datos almacenados como PROGMEM no pueden leerse directamente como variables normales. Hay que utilizar alguna de las funciones que acceden a dicha memoria. Prueba usando memcpy_PF a ver si obtienes mejores resultados. Saludos.

He estado haciendo algunas pruebas.
Mira a ver si este código te puede servir de inspiración para lo que quieres hacer.

const unsigned char mydata[11][10] PROGMEM =
{
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09},
{0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13},
{0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D},
{0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27},
{0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31},
{0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B},
{0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45},
{0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F},
{0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59},
{0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63},
{0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D}
};
void setup()
{
	Serial.begin(9600);
	for(int i=0; i<11; i++) {
		for (int j=0; j<10; j++) {
			Serial.print(pgm_read_byte(&mydata[i][j]), HEX);
			Serial.print(", ");
		}
		Serial.println();
	}
}

void loop()
{

}

hola, mil gracias por tus respuestas

he probado con memcpy_PF y sigo leyendo basura :(

en cuanto a la segunda solucion que me propones te comento la use como mi primera alternativa y obtuve buenos resultados en cuanto a la lectura de datos, sin embargo, la razon para no implementar este uso de un doble for y cambiarlo por memmove ha sido por mejorar el performance de la aplicacion, ya que al ser un programa de POV es indispensable eliminar el flicker de los leds que resulta al aplicar la lectura byte-a-byte del arreglo :(

una vez mas, saludos cordiales

Bueno. Si se trata de eliminar el flicker, podrías modificar el programa anterior y copiar a un array temporal:

const unsigned char mydata[11][10] PROGMEM =
{
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09},
{0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13},
{0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D},
{0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27},
{0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31},
{0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B},
{0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45},
{0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F},
{0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59},
{0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63},
{0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D}
};
void setup()
{
 Serial.begin(9600);
 byte temporal[10];
 for(int i=0; i<11; i++) {
 for (int j=0; j<10; j++) {
 temporal[j] = pgm_read_byte(&mydata[i][j]);
 }
 for (int j=0; j<10; j++) {
 Serial.print(temporal[j]);
 Serial.print(", ");
 }
 Serial.println();
 }
}

void loop()
{

}

Lo que no sé si finalmente será más rápido o no que con memcpy. Prueba a ver así, con memcpy_PF:

const unsigned char mydata[11][10] PROGMEM =
{
 {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09},
 {0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13},
 {0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D},
 {0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27},
 {0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31},
 {0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B},
 {0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45},
 {0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F},
 {0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59},
 {0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63},
 {0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D}
};
void setup()
{
 Serial.begin(9600);
 unsigned char temporal[10];
 for(int i=0; i<11; i++) {
 memcpy_PF(temporal, (uint_farptr_t) &mydata[i], 10);
 for (int j=0; j<10; j++) {
 Serial.print(temporal[j], HEX);
 Serial.print(", ");
 }
 Serial.println();
 }
}

void loop()
{

}

Bueno. Podría editar el post anterior, pero prefiero que quede constancia de la evolución. Como me imaginaba, existe el comando equivalente a memcpy_PF para puntero cercano, aunque no lo había visto en las ayudas de progmem. Me extrañaba tener que hacer el cast a uint_farptr_t de la dirección de memoria, así que miré directamente en el progmem.h y descubrí que también existe memcpy_P (sin la F de far). Puedes sustituir en el código anterior la línea

 memcpy_PF(temporal, (uint_farptr_t) &mydata[i], 10);

por esta otra

    memcpy_P(temporal, &mydata[i], 10);

No sé si supondrá una pequeña ganancia de tiempo, pero creo que es lo más optimizado que puedo hallar. Saludos.

Estoooo, rgs101, ¿te funcionó lo que te dije? Es que tengo un poquillo de curiosidad :roll_eyes: