From e138f7be3fb621bd246649b38a0b517ee810d900 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Wed, 15 Jul 2020 03:21:17 -0400 Subject: [PATCH] convert to ili9341_t3n library to use full DMA transfers --- teensy/teensy-display.cpp | 63 ++++++++++----------------------------- teensy/teensy-display.h | 4 +-- teensy/teensy.ino | 16 ++++++++-- 3 files changed, 32 insertions(+), 51 deletions(-) diff --git a/teensy/teensy-display.cpp b/teensy/teensy-display.cpp index adbefe2..3d46ef3 100644 --- a/teensy/teensy-display.cpp +++ b/teensy/teensy-display.cpp @@ -9,6 +9,7 @@ #define _clock 75000000 + #define PIN_RST 8 #define PIN_DC 9 #define PIN_CS 10 @@ -29,14 +30,15 @@ #include "globals.h" #include "applevm.h" -volatile DMAMEM uint16_t dmaBuffer[240][320]; // 240 rows, 320 columns +DMAMEM uint16_t dmaBuffer[240][320]; // 240 rows, 320 columns #define RGBto565(r,g,b) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | ((b) >> 3)) #define _565toR(c) ( ((c) & 0xF800) >> 8 ) #define _565toG(c) ( ((c) & 0x07E0) >> 5 ) #define _565toB(c) ( ((c) & 0x001F) ) -ILI9341_t3 tft = ILI9341_t3(PIN_CS, PIN_DC, PIN_RST, PIN_MOSI, PIN_SCK, PIN_MISO); +//ILI9341_t3 tft = ILI9341_t3(PIN_CS, PIN_DC, PIN_RST, PIN_MOSI, PIN_SCK, PIN_MISO); +ILI9341_t3n tft = ILI9341_t3n(PIN_CS, PIN_DC, PIN_RST, PIN_MOSI, PIN_SCK, PIN_MISO); DMAChannel dmatx; DMASetting dmaSetting; @@ -100,37 +102,10 @@ TeensyDisplay::TeensyDisplay() { memset(dmaBuffer, 0x80, sizeof(dmaBuffer)); - tft.begin(); + tft.begin(_clock); tft.setRotation(3); - tft.setClock(_clock); - - // Set up automatic DMA transfers. cf. - // https://forum.pjrc.com/threads/25778-Could-there-be-something-like-an-ISR-template-function/page4 -#if 0 - dmaSetting.TCD->CSR = 0; - dmaSetting.TCD->SADDR = dmaBuffer; - dmaSetting.TCD->SOFF = 2; // 2 bytes per pixel - dmaSetting.TCD->ATTR_SRC = 1; - dmaSetting.TCD->NBYTES = 2; - dmaSetting.TCD->SLAST = -320*240*2; - dmaSetting.TCD->BITER = 320*240; - dmaSetting.TCD->CITER = 320*240; - - dmaSetting.TCD->DADDR = &LPSPI4_TDR; // FIXME is this correct? - dmaSetting.TCD->DOFF = 0; - dmaSetting.TCD->ATTR_DST = 1; - dmaSetting.TCD->DLASTSGA = 0; - - // Make it loop on itself - dmaSetting.replaceSettingsOnCompletion(dmaSetting); - - dmatx.begin(false); - dmatx.triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_TX); // FIXME what's the right source ID - dmatx = &dmaSetting; -#endif - - // LCD initialization complete - + tft.setFrameBuffer((uint16_t *)dmaBuffer); + tft.useFrameBuffer(true); tft.fillScreen(ILI9341_BLACK); driveIndicator[0] = driveIndicator[1] = false; @@ -181,12 +156,9 @@ void TeensyDisplay::flush() void TeensyDisplay::blit() { - // The goal here is for blitting to happen automatically in DMA transfers. - - // Since that isn't the case yet, here's a manual blit of the whole - // screen (b/c the rect is kinda meaningless in the final "draw - // everything always" DMA mode) - tft.writeRect(0,0,320,240,(const uint16_t *)dmaBuffer); + // Start DMA transfers if they aren't running + if (!tft.asyncUpdateActive()) + tft.updateScreenAsync(true); // draw overlay, if any, occasionally { @@ -202,15 +174,7 @@ void TeensyDisplay::blit() void TeensyDisplay::blit(AiieRect r) { - // It's probably faster to just blit the whole thing, rather than a piece, - // because of how it streams data easily when the buffer aligns properly. - tft.writeRect(0,0,320,240,(const uint16_t *)dmaBuffer); - - // ... but if we wanted to blit just part, we'd have to create a new - // subset of teh dmaBuffer that has the right row length to match - // the rect width we're blitting, and then do something like this: - // - // tft.writeRect(r.left+HOFFSET,,r.top+VOFFSET,r.right-r.left+HOFFSET,r.bottom-r.top+VOFFSET,(const uint16_t *)some_subset_of_dmaBuffer); + // Nothing to do here, since we're regularly blitting the whole screen via DMA } void TeensyDisplay::drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c) @@ -381,3 +345,8 @@ void TeensyDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t color) cacheDoubleWidePixel(x>>1, y, color); } } + +uint32_t TeensyDisplay::frameCount() +{ + return tft.frameCount(); +} diff --git a/teensy/teensy-display.h b/teensy/teensy-display.h index b36f7c5..6a96a9f 100644 --- a/teensy/teensy-display.h +++ b/teensy/teensy-display.h @@ -2,11 +2,10 @@ #define __TEENSY_DISPLAY_H #include -#include +#include #include "physicaldisplay.h" -class UTFT; class BIOS; class TeensyDisplay : public PhysicalDisplay { @@ -32,6 +31,7 @@ class TeensyDisplay : public PhysicalDisplay { virtual void cache2DoubleWidePixels(uint16_t x, uint16_t y, uint8_t colorA, uint8_t colorB); virtual void cachePixel(uint16_t x, uint16_t y, uint8_t color); + uint32_t frameCount(); private: virtual void drawPixel(uint16_t x, uint16_t y, uint16_t color); virtual void drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b); diff --git a/teensy/teensy.ino b/teensy/teensy.ino index 9e0b5a7..233d4e0 100644 --- a/teensy/teensy.ino +++ b/teensy/teensy.ino @@ -254,6 +254,7 @@ void runDisplay(uint32_t now) static uint32_t microsAtStart = 0; static uint32_t microsForNext = micros(); static uint32_t lastFps = 0; + static uint32_t displayFrameCount = 0; THREADED { // If it's time to draw the next frame, then do so @@ -278,10 +279,21 @@ void runDisplay(uint32_t now) // Once a second, start counting all over again if (now >= nextResetMicros) { - lastFps = refreshCount; + uint32_t newFrameCount = ((TeensyDisplay *)g_display)->frameCount(); + + // There are two "FPS" counters here, actually. One is how often + // we're polling the Apple //e memory to refresh the DMA buffer, + // and to show that, we'd use this: +// lastFps = refreshCount; + // The other is how often the DMA code is refreshing the actual + // display, and to show that, we'd use this: + lastFps = newFrameCount - displayFrameCount; #ifdef DEBUG_TIMING - println("Display running at ", lastFps, " FPS"); + // ... and this debugging code shows both. + println("DMA buffer refresh at ", refreshCount, " FPS"); + println("Display refresh at ", newFrameCount - displayFrameCount, " FPS"); #endif + displayFrameCount = newFrameCount; nextResetMicros = now + 1000000; refreshCount = 0; microsAtStart = now;