Curious issue, likely easily solved but not seeing it.
I'm using the arduino IDE, programming a Pi Pico MCU which is connected to a pair of ILI9341 displays using the Adafruit driver. Displays have separate CS pins but otherwise wiring is the same on the hardware SPI bus.
with a single display it works fine, add a second display and that also works but the behaviour is curious, the code is below but in outline is to declare two instances of the Adafruit_ILI9341 object class, using the two different pins, and then in theory they should work individually.
behaviour however is a tad odd.
the first screen initialises correctly, however the second screen duplicates it - this is with or without the second screen even being initialised.
I can then write to the second screen which only goes to the second screen, however later in the code anything written to either screen appears on both.
the full code is as below, this also talks to the Kerbal Space Programme game, that side of the code works however the screens keep overwriting each other with the same display, which is the bug I'm trying to nail down.
I tried a google search on the library with multiple screens but didn't get very far
any help of thoughts appreciated
#include "KerbalSimpit.h"
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#define TFT_DC 9
#define TFT_CS0 10
#define TFT_CS1 11
#define TFT_CS1 12
#define TFT_CS1 13
KerbalSimpit ksp(Serial);
// screens, could use an array but with only four in the end this seems reasonable
Adafruit_ILI9341 tft0 = Adafruit_ILI9341(TFT_CS0, TFT_DC);
Adafruit_ILI9341 tft1 = Adafruit_ILI9341(TFT_CS1, TFT_DC);
//Adafruit_ILI9341 tft2 = Adafruit_ILI9341(TFT_CS2, TFT_DC);
//Adafruit_ILI9341 tft3 = Adafruit_ILI9341(TFT_CS3, TFT_DC);
bool isInFlight = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
tft0.begin();
tft1.begin();
tft0.setRotation(3);
tft0.fillScreen(ILI9341_BLACK);
tft0.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
tft0.setTextSize(1);
tft0.drawRect(0, 0, 320, 240, ILI9341_YELLOW);
WriteText("KSP Data Viewer", 2, &tft0);
WriteText("Waiting for Connection", 12, &tft0);
tft1.setRotation(3);
tft1.fillScreen(ILI9341_BLACK);
tft1.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
tft1.setTextSize(1);
tft1.drawRect(4, 0, 316, 240, ILI9341_YELLOW);
WriteText("Screen 1", 2, &tft1);
while (!ksp.init()) {
delay(100);
}
WriteText("Connected!", 20, &tft0);
delay(1000);
tft0.fillScreen(ILI9341_BLACK);
tft1.fillScreen(ILI9341_BLACK);
// write the headers
tft0.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
tft0.setTextSize(3);
WriteText("Apoapsis", 2, &tft0);
WriteText("Periapsis", 120, &tft0);
tft1.setTextSize(3);
WriteText("Altitude", 2, &tft1);
WriteText("Velocity", 120, &tft1);
ksp.inboundHandler(messageHandler);
ksp.registerChannel(APSIDES_MESSAGE);
ksp.registerChannel(APSIDESTIME_MESSAGE);
ksp.registerChannel(SCENE_CHANGE_MESSAGE);
ksp.registerChannel(FLIGHT_STATUS_MESSAGE);
ksp.registerChannel(ALTITUDE_MESSAGE);
ksp.registerChannel(APSIDES_MESSAGE);
}
void loop() {
// put your main code here, to run repeatedly:
ksp.update();
}
void WriteText(const char *S, uint16_t y, Adafruit_ILI9341 *tft)
{
int16_t x1, y1;
uint16_t w, h;
tft->getTextBounds(S, 0, y, &x1, &y1, &w, &h);
tft->setCursor(160 - (w/2), y);
tft->print(S);
}
void messageHandler(byte messageType, byte msg[], byte msgSize)
{
switch (messageType)
{
case ALTITUDE_MESSAGE:
{
if (msgSize == sizeof(altitudeMessage))
{
altitudeMessage D = parseMessage<altitudeMessage>(msg);
if (!isInFlight)
{
char Buffer[20];
tft0.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft0.setTextSize(3);
FormatDistance(D.sealevel, Buffer); sprintf(Buffer, "Abs: %s", Buffer); WriteText(Buffer, 40, &tft0);
FormatDistance(D.surface, Buffer); sprintf(Buffer, "Radar: %s", Buffer); WriteText(Buffer, 80, &tft0);
}
}
break;
}
case VELOCITY_MESSAGE:
{
if (msgSize == sizeof(velocityMessage))
{
velocityMessage D = parseMessage<velocityMessage>(msg);
if (!isInFlight)
{
char Buffer[20];
tft0.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft0.setTextSize(3);
FormatDistance((int)D.orbital, Buffer); sprintf(Buffer, "Orb: %s", Buffer); WriteText(Buffer, 160, &tft0);
FormatDistance((int)D.surface, Buffer); sprintf(Buffer, "Surf: %s", Buffer); WriteText(Buffer, 200, &tft0);
}
}
break;
}
case FLIGHT_STATUS_MESSAGE:
{
if (msgSize == sizeof(flightStatusMessage))
{
flightStatusMessage D = parseMessage<flightStatusMessage>(msg);
isInFlight = D.isInFlight();
if (!isInFlight)
{
char Buffer[20] = " ";
tft0.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft0.setTextSize(4);
WriteText(Buffer, 40, &tft0);
WriteText(Buffer, 80, &tft0);
WriteText(Buffer, 160, &tft0);
WriteText(Buffer, 200, &tft0);
tft0.setTextSize(3);
WriteText(Buffer, 40, &tft1);
WriteText(Buffer, 80, &tft1);
WriteText(Buffer, 160, &tft1);
WriteText(Buffer, 200, &tft1);
}
}
break;
}
case SCENE_CHANGE_MESSAGE:
{
char Buffer[20] = " ";
tft0.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft0.setTextSize(4);
WriteText(Buffer, 40, &tft0);
WriteText(Buffer, 80, &tft0);
WriteText(Buffer, 160, &tft0);
WriteText(Buffer, 200, &tft0);
break;
}
case APSIDES_MESSAGE:
{
if (isInFlight)
{
if (msgSize == sizeof(altitudeMessage))
{
apsidesMessage D = parseMessage<apsidesMessage>(msg);
tft0.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft0.setTextSize(3);
char Buffer[30] = {0};
FormatDistance(D.apoapsis, Buffer); WriteText(Buffer, 40, &tft0);
FormatDistance(D.periapsis, Buffer); WriteText(Buffer, 160, &tft0);
}
}
break;
}
case APSIDESTIME_MESSAGE:
{
if (isInFlight)
{
if (msgSize == sizeof(apsidesTimeMessage))
{
apsidesTimeMessage D = parseMessage<apsidesTimeMessage>(msg);
tft0.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft0.setTextSize(3);
char Buffer[30] = {0};
FormatTime(D.apoapsis, Buffer); WriteText(Buffer, 80, &tft0);
FormatTime(D.periapsis, Buffer); WriteText(Buffer, 200, &tft0);
}
}
break;
}
}
}
void FormatDistance(float myDistance, char *S)
{
// need to add the thousands seperators and set appropriate units
// first determine the units, the value is in "m" to start with, anything below 10km should use meters
// anything over 999,999,000m should use "M", everything else is using Km
float Divider = 1.0; // m
float V = 0.0;
char Units[3] = "m";
if (myDistance > 10000)
{
if (myDistance > 999999999)
{
Divider = 1000000.0; // Mm
sprintf(Units, "Mm");
}
else
{
Divider = 1000.0; // Km
sprintf(Units, "Km");
}
}
V = myDistance / Divider;
// now we need to split V into thousands groupings
int U0 = (int)(V * 1000.0) % 1000; // produces three digit fraction
int U1 = (int)(V) % 1000;
int U2 = (int)(V / 1000.0) % 1000;
// now ready for printing
if (U2 > 0)
{
sprintf(S, "%d,%03d.%02d %s", U2, U1, U0, Units);
}
else
{
sprintf(S, "%3d.%02d %s", U1, U0, Units);
}
}
void FormatTime(uint32_t myTime, char *S)
{
uint32_t Y = (myTime/9201600); // how many years do we have (426 days to a year)
uint32_t D = (myTime/21600) % 426; // how many days do we have (six hour days)
uint32_t h = (myTime/3600) % 6; // how many hours do we have?
uint32_t m = (myTime/60) % 60; // how many minutes do we have?
uint32_t s = myTime % 60; // how many seconds do we have?
// how we format this depends what we have
if (Y > 0)
{
// we have a time measured in years, formatting in years and days works
sprintf(S, " %d Y %d D ", Y, D);
}
else if (D > 0)
{
// time is at least a day
sprintf(S, " %d D %02d:%02d ", D, h, m);
}
else
{
sprintf(S, " %02d:%02d:%02d ", h, m, s);
}
}