Skip to content

Scrolling, buffering and transitions ​

Now the idea is to smoothly scroll the menu and to have nice animations between the screens.

Scrolling ​

So the ILI9341 has a hardware scrolling feature, which is basically a pointer shift in its RAM, and by updating the pointer, it shifts the screen content.

Here is an example code on how to scroll from a totaly red screen to a blue screen.

cpp
#include <Arduino.h>
#include "ui/ILI9341_GFX.h"

ILI9341_GFX display;

// Colors
#define COLOR_RED     0xF800
#define COLOR_BLUE    0x001F
#define COLOR_GREEN   0x07E0
#define COLOR_BLACK   0x0000
#define COLOR_WHITE   0xFFFF

// Scroll parameters
const uint16_t TFA = 0;
const uint16_t BFA = 0;
const uint16_t VSA = 240;

uint16_t currentLine = 0;
uint16_t lineBuffer[320];

void writeData16(uint16_t value) {
  display.writeData(value >> 8);
  display.writeData(value & 0xFF);
}

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(10);

  display.begin();
  Serial.println("Display initialized");
  display.setRotation(1);
  // Set scroll area: whole screen scrollable
  display.writeCommand(0x33); // VSCRDEF
  writeData16(TFA);
  writeData16(VSA);
  writeData16(BFA);

  // Fill screen with RED
  display.writeCommand(0x2A); // CASET
  writeData16(0);
  writeData16(239);
  
  display.writeCommand(0x2B); // PASET
  writeData16(0);
  writeData16(319);

  display.writeCommand(0x2C); // RAMWR
  for (int y = 0; y < 320; y++) {
    for (int x = 0; x < 240; x++) {
      lineBuffer[x] = COLOR_RED;
    }
    display.pushPixels(lineBuffer, 240);
  }

  delay(1000); // Let red show before starting transition
}

void addBlueLine() {
  // Set scroll offset
  display.writeCommand(0x37); // VSCRSADD
  writeData16(currentLine);

  // Write one blue line at current scroll position
  display.writeCommand(0x2A); // CASET
  writeData16(0);
  writeData16(239);

  display.writeCommand(0x2B); // PASET
  writeData16(currentLine);
  writeData16(currentLine);

  display.writeCommand(0x2C); // RAMWR
  for (int i = 0; i < 240; i++) {
    lineBuffer[i] = COLOR_BLUE;
  }
  display.pushPixels(lineBuffer, 240);

  // Advance within scroll range
  currentLine++;
  if (currentLine >= 320) {
    currentLine = 0;
  }
}

void loop() {
  static uint32_t lastUpdate = 0;

  if (millis() - lastUpdate >= 20) { // 50 FPS
    lastUpdate = millis();
    addBlueLine();
  }
}

Buffering ​

I would like to have a double buffering system, so that when I'll have a true data transfert with hardware pulse ( I think it is called DMA), I will be able to write the next screen while the current one is displayed. BUT! The screen is 320x240 pixels, which is 76800 pixels, and each pixel is 16bits, so it is 153600 bytes, which does not fit ont the STM32. So we'll have to buffer only a part of the screen, and then scroll it. I think it makes sens to buffer 30rows, since it is the size of one line in my menu.

So I will buffer 30 rows, which is 30*320 = 9600 bytes per buffer, still a bit greedy but we'll see.