ESP8266 цикл перезагрузки в функции "memcpy_P"
Я пытаюсь изменить код, который был изначально разработан для платы Trinket (ATTiny85). Он правильно компилируется для платы ESP8266-12E (NodeMCU1.0). Но устройство перезагружается при загрузке изображения в память.
Линии с:
memcpy_P(palette, imagePalette, 2 * 3);
Вызывающее устройство будет перезагружено.
Я буду очень рад, если кто-то посоветует мне, что нужно изменить, чтобы решить эту проблему? Код взят из Github
Код:
#include <Arduino.h>
#include <Adafruit_DotStar.h>
#include <SPI.h> // Enable this line on Pro Trinket
typedef uint16_t line_t; // Bigger images OK on other boards
// CONFIGURABLE STUFF ------------------------------------------------------
#include "fire.h" // Graphics data is contained in this header file.
#define LED_DATA_PIN MOSI
#define LED_CLOCK_PIN SCK
#define SELECT_PIN 3
boolean autoCycle = false; // Set to true to cycle images by default
#define CYCLE_TIME 15 // Time, in seconds, between auto-cycle images
// -------------------------------------------------------------------------
#if defined(LED_DATA_PIN) && defined(LED_CLOCK_PIN)
// Older DotStar LEDs use GBR order. If colors are wrong, edit here.
Adafruit_DotStar strip = Adafruit_DotStar(NUM_LEDS,
LED_DATA_PIN, LED_CLOCK_PIN, DOTSTAR_BRG);
#else
Adafruit_DotStar strip = Adafruit_DotStar(NUM_LEDS, DOTSTAR_BRG);
#endif
void imageInit(void);
uint16_t readVoltage(void);
#ifdef MOTION_PIN
void sleep(void);
#endif
void setup() {
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L)
clock_prescale_set(clock_div_1); // Enable 16 MHz on Trinket
#endif
#ifdef POWER_PIN
pinMode(POWER_PIN, OUTPUT);
digitalWrite(POWER_PIN, LOW); // Power-on LED strip
#endif
strip.begin(); // Allocate DotStar buffer, init SPI
strip.clear(); // Make sure strip is clear
strip.show(); // before measuring battery
imageInit(); // Initialize pointers for default image
#ifdef SELECT_PIN
pinMode(SELECT_PIN, INPUT_PULLUP);
#endif
}
// GLOBAL STATE STUFF ------------------------------------------------------
uint32_t lastImageTime = 0L; // Time of last image change
uint8_t imageNumber = 0, // Current image being displayed
imageType, // Image type: PALETTE[1,4,8] or TRUECOLOR
*imagePalette, // -> palette data in PROGMEM
*imagePixels, // -> pixel data in PROGMEM
palette[16][3]; // RAM-based color table for 1- or 4-bit images
line_t imageLines, // Number of lines in active image
imageLine; // Current line number in image
#ifdef SELECT_PIN
uint8_t debounce = 0; // Debounce counter for image select pin
#endif
void imageInit() { // Initialize global image state for current imageNumber
imageType = pgm_read_byte(&images[imageNumber].type);
imageLines = pgm_read_word(&images[imageNumber].lines);
imageLine = 0;
imagePalette = (uint8_t *)pgm_read_word(&images[imageNumber].palette);
imagePixels = (uint8_t *)pgm_read_word(&images[imageNumber].pixels);
if(imageType == PALETTE1) memcpy_P(palette, imagePalette, 2 * 3);
else if(imageType == PALETTE4) memcpy_P(palette, imagePalette, 16 * 3);
lastImageTime = millis(); // Save time of image init for next auto-cycle
}
void nextImage(void) {
if(++imageNumber >= NUM_IMAGES) imageNumber = 0;
imageInit();
}
// MAIN LOOP ---------------------------------------------------------------
void loop() {
uint32_t t = millis(); // Current time, milliseconds
if(autoCycle) {
if((t - lastImageTime) >= (CYCLE_TIME * 1000L)) nextImage();
// CPU clocks vary slightly; multiple poi won't stay in perfect sync.
// Keep this in mind when using auto-cycle mode, you may want to cull
// the image selection to avoid unintentional regrettable combinations.
}
#ifdef SELECT_PIN
if(digitalRead(SELECT_PIN)) { // Image select?
debounce = 0; // Not pressed -- reset counter
} else { // Pressed...
if(++debounce >= 25) { // Debounce input
nextImage(); // Switch to next image
while(!digitalRead(SELECT_PIN)); // Wait for release
// If held 1+ sec, toggle auto-cycle mode on/off
if((millis() - t) >= 1000L) autoCycle = !autoCycle;
debounce = 0;
}
}
#endif
switch(imageType) {
case PALETTE1: { // 1-bit (2 color) palette-based image
uint8_t pixelNum = 0, byteNum, bitNum, pixels, idx,
*ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS / 8];
for(byteNum = NUM_LEDS/8; byteNum--; ) { // Always padded to next byte
pixels = pgm_read_byte(ptr++); // 8 pixels of data (pixel 0 = LSB)
for(bitNum = 8; bitNum--; pixels >>= 1) {
idx = pixels & 1; // Color table index for pixel (0 or 1)
strip.setPixelColor(pixelNum++,
palette[idx][0], palette[idx][1], palette[idx][2]);
}
}
break;
}
case PALETTE4: { // 4-bit (16 color) palette-based image
uint8_t pixelNum, p1, p2,
*ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS / 2];
for(pixelNum = 0; pixelNum < NUM_LEDS; ) {
p2 = pgm_read_byte(ptr++); // Data for two pixels...
p1 = p2 >> 4; // Shift down 4 bits for first pixel
p2 &= 0x0F; // Mask out low 4 bits for second pixel
strip.setPixelColor(pixelNum++,
palette[p1][0], palette[p1][1], palette[p1][2]);
strip.setPixelColor(pixelNum++,
palette[p2][0], palette[p2][1], palette[p2][2]);
}
break;
}
}
strip.show(); // Refresh LEDs
delayMicroseconds(900);
if(++imageLine >= imageLines) imageLine = 0; // Next scanline, wrap around
}
И файл fire.h:
// Don't edit this file! It's software-generated.
// See convert.py script instead.
#define PALETTE1 0
#define PALETTE4 1
#define PALETTE8 2
#define TRUECOLOR 3
#define NUM_LEDS 16
// fire.gif ----------------------------------------------------------------
const uint8_t PROGMEM palette00[][3] = {
{ 88, 80, 3 },
{ 88, 88, 23 },
{ 88, 34, 0 },
{ 88, 4, 0 },
{ 88, 49, 0 },
{ 88, 9, 0 },
{ 0, 0, 0 },
{ 88, 88, 10 },
{ 88, 17, 0 },
{ 16, 0, 0 },
{ 88, 1, 0 },
{ 88, 0, 0 },
{ 88, 68, 1 },
{ 33, 0, 0 },
{ 1, 0, 0 },
{ 7, 0, 0 } };
const uint8_t PROGMEM pixels00[] = {
0X66, 0X6E, 0X95, 0XC7, 0X05, 0XD9, 0XEB, 0XE6,
0X66, 0X6E, 0X93, 0XCC, 0X4A, 0X9F, 0X9B, 0XE6,
0X66, 0X66, 0X93, 0X4C, 0X8D, 0X99, 0XB9, 0XE6,
0X66, 0X6E, 0XD3, 0X42, 0X39, 0X9B, 0XB9, 0XE6,
0X66, 0X6F, 0XD5, 0X88, 0XD9, 0X9B, 0XB9, 0XE6,
0X66, 0X6F, 0XB8, 0X23, 0XDF, 0X9B, 0XBD, 0XE6,
0X66, 0XE9, 0XA8, 0X2A, 0X9E, 0X9B, 0XBD, 0XF6,
0X66, 0XE9, 0X32, 0X8B, 0XFE, 0X9B, 0XAB, 0XDE,
0X66, 0XED, 0X52, 0X5D, 0XE6, 0XFB, 0XA3, 0XB9,
0X66, 0XFB, 0X22, 0X59, 0XE6, 0XED, 0XA3, 0XAD,
0X66, 0X9A, 0X24, 0X39, 0X66, 0XEF, 0XA3, 0X3B,
0X6E, 0XF3, 0X24, 0X39, 0XE6, 0X6F, 0XD3, 0X3B,
0X66, 0X93, 0X44, 0X39, 0XE6, 0X6E, 0X93, 0X3A,
0X6E, 0X93, 0X44, 0X59, 0X66, 0X6E, 0X93, 0X5A,
0X6E, 0X93, 0X2C, 0X59, 0XE6, 0X6E, 0XD3, 0X5A,
0X66, 0X9A, 0X44, 0X8D, 0XF6, 0XEF, 0XA8, 0X8A,
0X66, 0XFA, 0X2C, 0X45, 0X9F, 0XFD, 0X52, 0X8B,
0X66, 0XED, 0X8C, 0X04, 0X5D, 0XD8, 0X44, 0X3D,
0X66, 0XE9, 0X3C, 0X77, 0XC4, 0X4C, 0XC4, 0XA9,
0X66, 0X69, 0XAC, 0X71, 0X77, 0X77, 0XC5, 0XBF,
0X66, 0XEF, 0XB2, 0X71, 0X11, 0X70, 0X2A, 0X9E,
0X66, 0X6F, 0XD8, 0X01, 0X11, 0X74, 0XA9, 0XF6,
0X66, 0X6E, 0X93, 0XC1, 0X17, 0XC3, 0XDE, 0X66,
0X6E, 0X6E, 0XFA, 0X47, 0X17, 0X2D, 0XF6, 0X66,
0X6E, 0XBF, 0XFD, 0X50, 0X7C, 0X89, 0XE6, 0X66,
0X6E, 0XBF, 0XFD, 0XA4, 0XCC, 0X39, 0XE6, 0X66,
0X6E, 0XFB, 0X9F, 0XD8, 0X44, 0X39, 0XE6, 0X66,
0X6E, 0X9B, 0XBD, 0X93, 0X22, 0X39, 0XE6, 0X66,
0X6E, 0XFB, 0XB9, 0X9D, 0X52, 0X5D, 0XE6, 0X66,
0X6E, 0XDB, 0XB9, 0XF9, 0X32, 0X8A, 0XF6, 0X66,
0X6F, 0XDB, 0XB9, 0XFF, 0XA2, 0X8A, 0X9E, 0X66,
0XED, 0XBA, 0XB9, 0XE9, 0XB8, 0X23, 0X9E, 0X66,
0X9B, 0XA3, 0XBF, 0XEE, 0XD5, 0X25, 0XDF, 0X66,
0X9A, 0X3A, 0XDF, 0X6E, 0X93, 0X28, 0XBF, 0X66,
0XB3, 0X5B, 0X96, 0X66, 0X93, 0X22, 0XAF, 0XE6,
0XB3, 0X3D, 0XE6, 0X6E, 0X93, 0X24, 0X39, 0XE6,
0XA3, 0X39, 0XE6, 0X66, 0X93, 0X42, 0X39, 0XE6,
0XA5, 0X39, 0XE6, 0X6E, 0X93, 0X44, 0X39, 0XE6,
0XA5, 0X3D, 0XE6, 0X66, 0XD5, 0X44, 0XA9, 0X66,
0XA8, 0X8A, 0X96, 0X6F, 0XD2, 0X44, 0XAF, 0X66,
0XB8, 0X25, 0XD9, 0XFD, 0X3C, 0XC8, 0XAF, 0XE6,
0XD5, 0X44, 0X5D, 0XD3, 0XC0, 0X08, 0XDE, 0X66,
0X9A, 0X20, 0XC4, 0X4C, 0X77, 0XC3, 0XDE, 0X66,
0XFB, 0X8C, 0X77, 0X71, 0X71, 0X43, 0XFE, 0X66,
0XE9, 0XA2, 0X01, 0X11, 0X17, 0X4B, 0XF6, 0X66,
0X6E, 0XDA, 0X47, 0X11, 0X17, 0X8D, 0XF6, 0X66,
0X66, 0XE9, 0X3C, 0X11, 0X1C, 0X39, 0XE6, 0X66,
0X66, 0X6F, 0XD2, 0X71, 0X74, 0XAF, 0XEE, 0X66 };
typedef struct {
uint8_t type; // PALETTE[1,4,8] or TRUECOLOR
line_t lines; // Length of image (in scanlines)
const uint8_t *palette; // -> PROGMEM color table (NULL if truecolor)
const uint8_t *pixels; // -> Pixel data in PROGMEM
} image;
const image PROGMEM images[] = {
{ PALETTE4 , 48, (const uint8_t *)palette00, pixels00 }
};
#define NUM_IMAGES (sizeof(images) / sizeof(images[0]))
Код ошибки: (я добавил информацию Serial.Print перед каждой строкой кода, так что я знаю, что что-то есть с memcpy_P)
Loading pgm_read_byte... OK !
Loading pgm_read_word... OK !
Loading PALETTE1 memcpy_P...
Exception (28):
epc1=0x40202fda epc2=0x00000000 epc3=0x00000000 excvaddr=0x000078ec depc=0x00000000
ctx: cont
sp: 3ffef830 end: 3ffefa40 offset: 01a0
>>>stack>>>
3ffef9d0: 3ffe8910 3ffee7d0 00000001 402022d6
3ffef9e0: 00000000 00000001 3ffee9ec 3ffe8910
3ffef9f0: 3ffee7c4 3ffe88ec 3ffee9ec 40201ff9
3ffefa00: 0001c200 0000001c 3ffee7d0 3ffeea10
3ffefa10: 3fffdad0 00000000 3ffee7d0 40202051
3ffefa20: feefeffe feefeffe 3ffeea08 40202d60
3ffefa30: feefeffe feefeffe 3ffeea20 4010070c
<<<stack<<<
Декодированная ошибка с AVR декодером:
Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
Decoding 6 results
0x40202fda: pgm_read_byte_inlined at C:\Users\Rafal\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.0-rc2\cores\esp8266/pgmspace.h line 104
0x402022d6: Adafruit_DotStar::sw_spi_out(unsigned char) at D:\Dropbox\ArduinoLib\libraries\Adafruit_DotStar/Adafruit_DotStar.cpp line 40
0x40201ff9: imageInit() at D:\Dropbox\ArduinoLib\sketch_nov16b/sketch_nov16b.ino line 167
0x40202051: setup at D:\Dropbox\ArduinoLib\sketch_nov16b/sketch_nov16b.ino line 125
0x40202d60: loop_wrapper at C:\Users\Rafal\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.0-rc2\cores\esp8266/core_esp8266_main.cpp line 57
0x4010070c: cont_norm at C:\Users\Rafal\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.0-rc2\cores\esp8266/cont.S line 109
КСТАТИ. Я пробовал несколько версий плат 2.3.0, 2.4.0 RC1 и RC2.
1 ответ
Мне удалось получить код Adafruit, который вы опубликовали выше, для работы с ESP8266, удалив все экземпляры PROGMEM из скетча. Просто используйте функцию найти и заменить в Arduino и удалить все программы и заменить ничем. Затем замените imageinit на приведенный ниже из эскиза сверхновой. Он работает, но сохраняет все шаблоны в рабочей памяти, а не во флэш-памяти. Сейчас я пытаюсь сохранить шаблоны во флэш-памяти, чтобы можно было сохранить больше шаблонов.
void imageInit() { // Initialize global image state for current imageNumber
imageType = images[imageNumber].type;
imageLines = images[imageNumber].lines;
imageLine = 0;
imagePalette = (uint8_t *)images[imageNumber].palette;
imagePixels = (uint8_t *)images[imageNumber].pixels;
// 1- and 4-bit images have their color palette loaded into RAM both for
// faster access and to allow dynamic color changing. Not done w/8-bit
// because that would require inordinate RAM (328P could handle it, but
// I'd rather keep the RAM free for other features in the future).
if(imageType == PALETTE1) memcpy_P(palette, imagePalette, 2 * 3);
else if(imageType == PALETTE4) memcpy_P(palette, imagePalette, 16 * 3);
lastImageTime = millis(); // Save time of image init for next auto-cycle
}