From dd76741c23b7c02c7ede5677897e2f60df8aef3f Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Fri, 21 Jan 2022 15:37:06 -0500 Subject: [PATCH] more DMA framebuffer updates --- teensy/RA8875_t4.cpp | 61 +++++++------------- teensy/RA8875_t4.h | 1 - teensy/teensy-display.cpp | 116 ++++++++++++++++---------------------- 3 files changed, 69 insertions(+), 109 deletions(-) diff --git a/teensy/RA8875_t4.cpp b/teensy/RA8875_t4.cpp index 3bed5ef..4817b38 100644 --- a/teensy/RA8875_t4.cpp +++ b/teensy/RA8875_t4.cpp @@ -156,7 +156,7 @@ void RA8875_t4::begin(uint32_t spi_clock, uint32_t spi_clock_read) _spi_tcr_current = _pimxrt_spi->TCR; // get the current TCR value maybeUpdateTCR(LPSPI_TCR_FRAMESZ(7)); - + _initializeTFT(); } @@ -179,7 +179,7 @@ void RA8875_t4::_initializeTFT() _writeData(RA8875_PWRR_NORMAL); delay(200); } - + // Set the sysclock _writeRegister(RA8875_PLLC1, 0x07); // same as default value: %0000 0111 == pre /=1; input /=7 delay(1); @@ -214,19 +214,8 @@ void RA8875_t4::_initializeTFT() _writeRegister(RA8875_VEAW0, (RA8875_HEIGHT-1) & 0xFF); // vertical end point of active window _writeRegister(RA8875_VEAW0+1, (RA8875_HEIGHT-1) >> 8); - delay(10); + delay(100); - // Update the sysclock - _writeRegister(RA8875_PLLC1, 0x1D); - delay(1); - _writeRegister(RA8875_PLLC1+1, 0x02); - delay(1); - _writeRegister(RA8875_PCSR, 0x82); - delay(1); - - _clock = _spi_clock; // speed up to full speed now - - delay(1); // clear memory uint8_t temp; temp = _readRegister(RA8875_MCLR); @@ -235,6 +224,23 @@ void RA8875_t4::_initializeTFT() _waitBusy(0x80); delay(1); + + // Update the sysclock. 300MHz Fpll; 150MHz sysclk; 18.75 MHz pixel + // clock. That's the fastest that seems to reliably work for me. It + // also allows a SPI bus transfer at just under 80MHz (literally + // 79.999... there must be a constant somewhere that's breaking the + // SPI module at 80, or a Teensy 4.1 bus limit, or ... ?) + _writeRegister(RA8875_PLLC1, 0x0E); + delay(1); + _writeRegister(RA8875_PLLC1+1, 0x01); + delay(1); + _writeRegister(RA8875_PCSR, 0x82); + delay(1); + + _clock = _spi_clock; // speed up to full speed now + + delay(10); + // turn on the display _writeRegister(RA8875_PWRR, RA8875_PWRR_NORMAL | RA8875_PWRR_DISPON); delay(1); @@ -272,7 +278,6 @@ void RA8875_t4::_initializeTFT() // setCursor(0,0); _writeRegister(RA8875_GPIOX, true); // turn on backlight - } void RA8875_t4::setFrameBuffer(uint8_t *frame_buffer) @@ -283,7 +288,7 @@ void RA8875_t4::setFrameBuffer(uint8_t *frame_buffer) bool RA8875_t4::asyncUpdateActive() { - return false; + return (_dma_state & RA8875_DMA_ACTIVE); } void RA8875_t4::initDMASettings() @@ -325,30 +330,6 @@ void RA8875_t4::initDMASettings() } } -// This should be removable after async updates are running -void RA8875_t4::updateScreenSync() -{ - // Set the X/Y cursor - _writeRegister(RA8875_CURV0, 0); - _writeRegister(RA8875_CURV0+1, 0); - _writeRegister(RA8875_CURH0, 0); - _writeRegister(RA8875_CURH0+1, 0); - - // start a memory write - writeCommand(RA8875_MRWC); - // Send all the screen pixel data - _startSend(); - _pspi->transfer(RA8875_DATAWRITE); - uint8_t *pfbtft_end = &_pfbtft[COUNT_PIXELS_WRITE]; - uint8_t *pftbft = _pfbtft; - while (pftbft < pfbtft_end) { - // Each pixel is 8 bpp... - _pspi->transfer(*pftbft++); - } - // done! - _endSend(); -} - bool RA8875_t4::updateScreenAsync(bool update_cont) { if (!_pfbtft) return false; diff --git a/teensy/RA8875_t4.h b/teensy/RA8875_t4.h index 156f8aa..5ec2515 100644 --- a/teensy/RA8875_t4.h +++ b/teensy/RA8875_t4.h @@ -31,7 +31,6 @@ class RA8875_t4 { void setFrameBuffer(uint8_t *frame_buffer); bool asyncUpdateActive(); - void updateScreenSync(); bool updateScreenAsync(bool update_cont = false); void drawPixel(int16_t x, int16_t y, uint16_t color); diff --git a/teensy/teensy-display.cpp b/teensy/teensy-display.cpp index 66b55c8..83440b5 100644 --- a/teensy/teensy-display.cpp +++ b/teensy/teensy-display.cpp @@ -21,10 +21,14 @@ extern const unsigned char interface_glyphs[256]; #define RA8875_HEIGHT 480 #endif -DMAMEM uint8_t dmaBuffer[RA8875_HEIGHT][RA8875_WIDTH] /*__attribute__((aligned(32))*/; +DMAMEM uint8_t dmaBuffer[RA8875_HEIGHT][RA8875_WIDTH] __attribute__((aligned(32))); #include -#define _clock 79500000u +// 30MHz: solid performance, 9 FPS +// 57.5MHz: solid performance, 14/15 FPS +// 60MHz: unexpected palatte shifts & (may be audio overruns, needs checking since bumping up buffer sizes) 17 FPS +// And I can't get the SPI bus working at 80MHz or higher. Not sure why yet... +#define _clock 57500000u #define PIN_RST 8 #define PIN_DC 9 @@ -60,18 +64,21 @@ const uint16_t loresPixelColors[16] = { 0x0000, // 0 black #define luminanceFromRGB(r,g,b) ( ((r)*0.2126) + ((g)*0.7152) + ((b)*0.0722) ) #define _565To332(c) ((((c) & 0xe000) >> 8) | (((c) & 0x700) >> 6) | (((c) & 0x18) >> 3)) - RA8875_t4 tft = RA8875_t4(PIN_CS, PIN_RST, PIN_MOSI, PIN_SCK, PIN_MISO); TeensyDisplay::TeensyDisplay() { - // tft.begin(Adafruit_800x480); - tft.begin(_clock); - tft.fillWindow(); - tft.setFrameBuffer((uint8_t *)dmaBuffer); - driveIndicator[0] = driveIndicator[1] = false; driveIndicatorDirty = true; + + // tft.begin(Adafruit_800x480); + Serial.println("begin"); + tft.begin(_clock); + Serial.println("set framebuffer"); + tft.setFrameBuffer((uint8_t *)dmaBuffer); + Serial.println("clear window"); + tft.fillWindow(); + Serial.println("ok"); } TeensyDisplay::~TeensyDisplay() @@ -80,16 +87,17 @@ TeensyDisplay::~TeensyDisplay() void TeensyDisplay::flush() { - tft.updateScreenAsync(false); } void TeensyDisplay::redraw() { - g_ui->drawStaticUIElement(UIeOverlay); + if (g_ui) { + g_ui->drawStaticUIElement(UIeOverlay); - if (g_vm && g_ui) { - g_ui->drawOnOffUIElement(UIeDisk1_state, ((AppleVM *)g_vm)->DiskName(0)[0] == '\0'); - g_ui->drawOnOffUIElement(UIeDisk2_state, ((AppleVM *)g_vm)->DiskName(1)[0] == '\0'); + if (g_vm) { + g_ui->drawOnOffUIElement(UIeDisk1_state, ((AppleVM *)g_vm)->DiskName(0)[0] == '\0'); + g_ui->drawOnOffUIElement(UIeDisk2_state, ((AppleVM *)g_vm)->DiskName(1)[0] == '\0'); + } } } @@ -114,7 +122,7 @@ void TeensyDisplay::blit() // Start updates, if they're not running already if (!tft.asyncUpdateActive()) tft.updateScreenAsync(true); - // DEBUGGING: not refreshing every time so I can see the machine boot + static uint32_t ctr = 0; // draw overlay, if any, occasionally @@ -122,9 +130,10 @@ void TeensyDisplay::blit() static uint32_t nextMessageTime = 0; if (millis() >= nextMessageTime) { if (overlayMessage[0]) { - drawString(M_SELECTDISABLED, 1, RA8875_HEIGHT - (16 + 12), overlayMessage); + drawString(M_SELECTDISABLED, 1, RA8875_HEIGHT - (16 + 12)*2, overlayMessage); + Serial.println(overlayMessage); } - nextMessageTime = millis() + 10; // DEBUGGING FIXME make 1000 again + nextMessageTime = millis() + 1000; } } } @@ -133,14 +142,17 @@ void TeensyDisplay::blit(AiieRect r) { } +// FIXME do we still need 2 different methods for drawing pixels void TeensyDisplay::drawUIPixel(uint16_t x, uint16_t y, uint16_t color) { - dmaBuffer[y][x] = _565To332(color); + if (x < RA8875_WIDTH && y < RA8875_HEIGHT) + dmaBuffer[y][x] = _565To332(color); } void TeensyDisplay::drawPixel(uint16_t x, uint16_t y, uint16_t color) { - dmaBuffer[y][x] = _565To332(color); + if (x < RA8875_WIDTH && y < RA8875_HEIGHT) + dmaBuffer[y][x] = _565To332(color); } void TeensyDisplay::drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b) @@ -180,14 +192,17 @@ void TeensyDisplay::drawCharacter(uint8_t mode, uint16_t x, uint16_t y, char c) break; } - // This does not scale when drawing, because drawPixel scales. const unsigned char *ch = asciiToAppleGlyph(c); for (int8_t y_off = 0; y_off <= ysize; y_off++) { for (int8_t x_off = 0; x_off <= xsize; x_off++) { - if (*ch & (1 << (x_off))) { - drawUIPixel(x + x_off, y + y_off, onPixel); - } else { - drawUIPixel(x + x_off, y + y_off, offPixel); + for (int8_t ys=0; ys<2; ys++) { + for (int8_t xs=0; xs<2; xs++) { + if (*ch & (1 << (x_off))) { + drawUIPixel((x + x_off)*2+xs, (y + y_off)*2+ys, onPixel); + } else { + drawUIPixel((x + x_off)*2+xs, (y + y_off)*2+ys, offPixel); + } + } } } ch++; @@ -196,61 +211,32 @@ void TeensyDisplay::drawCharacter(uint8_t mode, uint16_t x, uint16_t y, char c) void TeensyDisplay::drawString(uint8_t mode, uint16_t x, uint16_t y, const char *str) { - int8_t xsize = 8; // width of a char in this font + int8_t xsize = 8; // width of a char in this font for (int8_t i=0; i= 320) break; // FIXME constant - and pre-scaling, b/c that's in drawCharacter + x += xsize; + if (x >= (RA8875_WIDTH-xsize)/2) break; // FIXME this is a pre-scaled number, b/c drawCharacter is scaling. Klutzy. } } void TeensyDisplay::clrScr(uint8_t coloridx) { - if (coloridx == c_black) { - tft.fillWindow(); - } else if (coloridx == c_white) { - tft.fillWindow(loresPixelColors[c_white]); - } else { - uint16_t color16 = loresPixelColors[c_black]; - if (coloridx < 16) - color16 = loresPixelColors[coloridx]; - tft.fillWindow(color16); + uint8_t c = _565To332(loresPixelColors[coloridx]); + for (uint16_t y=0; y<480; y++) { + for (uint16_t x=0; x<800; x++) { + dmaBuffer[y][x] = c; + } } } -inline uint16_t blendColors(uint16_t a, uint16_t b) -{ - // Straight linear average doesn't work well for inverted text, because the - // whites overwhelm the blacks. - //return ((uint32_t)a + (uint32_t)b)/2; - -#if 0 - // Testing a logarithmic color scale. My theory was that, since our - // colors here are mostly black or white, it would be reasonable to - // use a log scale of the average to bump up the brightness a - // little. In practice, it's not really legible. - return RGBto565( (uint8_t)(logfn((_565toR(a) + _565toR(b))/2)), - (uint8_t)(logfn((_565toG(a) + _565toG(b))/2)), - (uint8_t)(logfn((_565toB(a) + _565toB(b))/2)) ); -#endif - - // Doing an R/G/B average works okay for legibility. It's not great for - // inverted text. - return RGBto565( (_565toR(a) + _565toR(b))/2, - (_565toG(a) + _565toG(b))/2, - (_565toB(a) + _565toB(b))/2 ); - -} - void TeensyDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t color) { for (int yoff=0; yoff<2; yoff++) { - dmaBuffer[(y*2)+SCREENINSET_Y+yoff][x+SCREENINSET_X] = color; + dmaBuffer[(y*2)+SCREENINSET_Y+yoff][x+SCREENINSET_X] = _565To332(loresPixelColors[color]); } } - void TeensyDisplay::cacheDoubleWidePixel(uint16_t x, uint16_t y, uint16_t color16) { for (int yoff=0; yoff<2; yoff++) { @@ -288,13 +274,7 @@ void TeensyDisplay::cache2DoubleWidePixels(uint16_t x, uint16_t y, } } -inline double logfn(double x) -{ - // At a value of x=255, log(base 1.022)(x) is 254.636. - return log(x)/log(1.022); -} - uint32_t TeensyDisplay::frameCount() { - return 0; + return tft.frameCount(); }