SRAM Data Corruption

Hi All,

I’m running into a weird glitch with the onboard memory of the Arduino and would like some help.

Problem: First image’s data is corrupted.

Project Goal: To display 3 images on an E-ink Display with a delay between them.

Analysis: When I upload and loop one image, the display works correctly. When I upload and loop two images, the display works correctly. But when I upload and loop three images the first image becomes corrupted. This issue occurs as I increase the number of images.

Since this failure only shows up when I have 3 or more images, I suspect the issue is because of how the Arduino stores data in the SRAM and how it’s being called. However, I’m not sure how to fix this problem.

Equipment: Arduino Mega 2560 R3 from Relegoo & WaveShare 7.5" E-ink display & E-paper Hat

**Hat:**https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT

**Image of a Working and Corrupted Display:**https://imgur.com/a/5C8qFaD

Primary Code:

#include <SPI.h>
#include <epd7in5.h>
#include "image1.h"
#include "image2.h"
#include "image3.h"

void setup() {
  // put your setup code here, to run once:
      Serial.begin(9600);
    Epd epd;
    if (epd.Init() != 0) {
        Serial.print("e-Paper init failed");
        return;
    }
    delay(50);
    while(true)
    {
  epd.DisplayFrame(IMAGE1);
  delay(20000);
  epd.DisplayFrame(IMAGE2);
  delay(20000);
  epd.DisplayFrame(IMAGE3);
  delay(20000);
    }
}

Hex File for Image 1

extern const unsigned char IMAGE1[];

CPP File for Image 1: All other images follow this same pattern.

#include "image1.h"
#include <avr/pgmspace.h>

const unsigned char IMAGE1[] PROGMEM = { 
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,...};

BookShelf.zip (718 KB)

I guess the function epd.DisplayFrame accepts a pointer to PROGMEM, not a far pointer to PROGMEM.

What is a "far pointer?" I tried googling for this term but only get info on normal pointers.

Do you have a recommendation on how to fix my function to accept far pointers?

Does everything work the way you expect with a simple program that displays a single small image?

Here is an example Koepel/Progmem_far.ino

Some documentation <avr/pgmspace.h>: Program Space Utilities

And I’m back, sorry I was busy the last few days.

@Coding Badly; I can’t send it a smaller image. The code is looking for an image of a particular size and each pixel must have a value.

@Whandall; I tried updating the code to accept far pointers however that didn’t work. Below I’ve attached the code for the DisplayFrame Function

.cpp file:
FYI, EPD_Width and EPD_Height are the size of my display. If I understand this function correctly it’s going pixel by pixel and assigning a hex value to display based on the byte read from the image.

The original code used: temp1 = pgm_read_byte(&frame_buffer*). The new code includes the “_far”*
```

  • void Epd::DisplayFrame(const unsigned char* frame_buffer) {
        unsigned char temp1, temp2;
        SendCommand(DATA_START_TRANSMISSION_1);
        for(long i = 0; i < EPD_WIDTH / 8 * EPD_HEIGHT; i++) { 
            temp1 = pgm_read_byte_far(&frame_buffer[i]);
            for(unsigned char j = 0; j < 8; j++) {
                if(temp1 & 0x80)
                    temp2 = 0x03;
                else
                    temp2 = 0x00;
               
                temp2 <<= 4;
                temp1 <<= 1;
                j++;
                if(temp1 & 0x80)
                    temp2 |= 0x03;
                else
                    temp2 |= 0x00;
                temp1 <<= 1;
                SendData(temp2);
            }
        }
        SendCommand(DISPLAY_REFRESH);
        DelayMs(100);
        WaitUntilIdle();
    }*
    * *.h file* *
    public:
        Epd();
        ~Epd();
        int  Init(void);
        void WaitUntilIdle(void);
        void Reset(void);
        void SetLut(void);
        void DisplayFrame(const unsigned char
    frame_buffer);
        void SendCommand(unsigned char command);
        void SendData(unsigned char data);
        void Sleep(void);*
    ```

ateevg:
I tried updating the code to accept far pointers however that didn't work.

How could it?

const unsigned char* frame_buffer

has only 16 bit, the parameter should be (unsigned) long.

The macro to get such an address is pgm_get_far_address(var).

Something like the following could work I think

epd.DisplayFrame(pgm_get_far_address(IMAGE1));


    void DisplayFrame(uint32_t frame_buffer);


void Epd::DisplayFrame(uint32_t frame_buffer) {
  ...
        temp1 = pgm_read_byte_far(frame_buffer+i);

It worked! Thank you so much for your help!