RA8876 Parallel Display Library Testing

@defragster - The wiring has changed alot since P#1 and since the introduction of variants. If you check out RA8876_t41_p/src you will find RA8876_t41_p_default_pins.h which shows the default pins for various boards. The last section is for the MM and DB5 boards but only 8-bit mode:
Code:
// FLEXIO2 pins.

#define DISPLAY_WR 7  // FLEXIO2:17
#define DISPLAY_RD 8 // FLEXIO2:16

#define DISPLAY_D0 40 // 40      B0_04   FlexIO2:4
#define DISPLAY_D1 41 // 41      B0_05   FlexIO2:5
#define DISPLAY_D2 42 // 42      B0_06   FlexIO2:6
#define DISPLAY_D3 43 // 43      B0_07   FlexIO2:7
#define DISPLAY_D4 44 // 44      B0_08   FlexIO2:8
#define DISPLAY_D5 45 // 45      B0_09   FlexIO2:9
#define DISPLAY_D6 6  // 6       B0_10   FlexIO2:10
#define DISPLAY_D7 9  // 9       B0_11   FlexIO2:11

In 16 bit mode, DISPLAY_WR and DISPLAY_RD have to be changed for 16-bit mode. I'll write up a pin list that I used for 16-bit mode on the DB5.
Have to make dinner right now but will make the list and post it afterwords...
 
Doesn't seem surprising - is that DB5 with SDRAM too?
Wonder if it is still ticking and just stuck - probably stuck - if TyComm was in use the Reset or Bootloader would trigger?
Trying to recall what it was I put in an 'am I alive' indicator - seems that was in a USB_Host project? MTP? - an interrupt doing something?
Yep - using the DB5.

If you are using @KurtE's shield on the DB5 believe these pins should work as well
Code:
#elif defined(ARDUINO_TEENSY_DEVBRD5)
// BUGBUG Nibble mode
// Will currently fail
#define DISPLAY_RD 52    // FlexIO3:10: RD
#define DISPLAY_WR 56    // FlexIO3:11 WR

#define DISPLAY_D0 40 // 40      B0_04   FlexIO2:4
#define DISPLAY_D1 41 // 41      B0_05   FlexIO2:5
#define DISPLAY_D2 42 // 42      B0_06   FlexIO2:6
#define DISPLAY_D3 43 // 43      B0_07   FlexIO2:7
#define DISPLAY_D4 44 // 44      B0_08   FlexIO2:8
#define DISPLAY_D5 45 // 45      B0_09   FlexIO2:9
#define DISPLAY_D6 6  // 6       B0_10   FlexIO2:10
#define DISPLAY_D7 9  // 9       B0_11   FlexIO2:11
/*
#define DISPLAY_D8  32
#define DISPLAY_D9  47
#define DISPLAY_D10  48
#define DISPLAY_D11  49
#define DISPLAY_D12  8
#define DISPLAY_D13  7
#define DISPLAY_D14  50
#define DISPLAY_D15  51
*/

As @wwatson mentioned things still evolving - i get confused sometimes as well but the current working repo is

 
Think there may be an issue with using DMA for the camera and CSI at the same time.
Would not surprise me.

Will play soon. May have to experiment with making sure to not try to start a display operation if the previous one was still active... Or some such things

Oops, thought this was posted a couple hours ago
 
@defragster - If you are not using @KurtE's adapter board you can wire it up using this (not sure if it will interfere with camera usage):
Code:
Dev Board 5                   RA8876
    PIN#                       PIN#
D0  40 --------------------->  15 
D1  41 --------------------->  16
D2  42 --------------------->  17
D3  43 --------------------->  18
D4  44 --------------------->  19
D5  45 --------------------->  20
D6   6 --------------------->  21
D7   9 --------------------->  22
D8  32 --------------------->  23
D9  47 --------------------->  24
D10 48 --------------------->  25
D11 49 --------------------->  26
D12  8 --------------------->  27
D13  7 --------------------->  28
D14 50 --------------------->  29
D15 51 --------------------->  30

RD  52 --------------------->   5
WR  53 --------------------->   6
CS  11 --------------------->   7
RS  13 --------------------->   8
RST 12 --------------------->  11
BL  3.3V (BACKLITE) -------->  14
In your sketch you would initialize this way:
Code:
//#define use_spi
#if defined(use_spi)
#include <SPI.h>
#include <RA8876_t3.h>
#else
//#include <RA8876_t3.h>
#include <RA8876_t41_p.h>
#endif
//#include <math.h>

#if defined(use_spi)
#define RA8876_CS 10
#define RA8876_RESET 9
#define BACKLITE 5 //External backlight control connected to this Arduino pin
RA8876_t3 tft = RA8876_t3(RA8876_CS, RA8876_RESET); //Using standard SPI pins
#else

// Setup DC(also called RS), CS and RST. 
uint8_t dc = 13; 
uint8_t cs = 11;
uint8_t rst = 12;
RA8876_t41_p lcd = RA8876_t41_p(dc,cs,rst); //(dc, cs, rst)

#define BACKLITE 5 //External backlight control connected to this Arduino pin
#endif

uint8_t busSpeed = 12; // 12MHz max in 16-bit mode. 20 or greater in 8-bit mode.

void setup() {
  while (!Serial && millis() < 3000) {} //wait for Serial Monitor
  Serial.printf("%c DB5 board and RA8876 parallel 8080 mode testing (8-Bit/16-bit,DMA/ASYNC)\n\n",12);
//  Serial.print(CrashReport);

  // Un-comment to set 16bit mode
  lcd.setBusWidth(16); // Sets 16-bit mode

  // DB5.0 WR pin, RD pin, D0 pin.
  // ----- Set for DB5 board. -----
  lcd.setFlexIOPins(53,52,40);  //Set this to match your board configuration.

#if defined(use_spi)
  lcd.begin();
#else
  lcd.begin(busSpeed); // 20 is working in 8bit and 16bit mode on T41
#endif
//  if(!lcd.begin(busSpeed)) Serial.printf("lcd.begin(busSpeed) FAILED!!!\n");
  delay(100);

  Serial.print("Bus speed: ");
  Serial.print(busSpeed,DEC);
  Serial.println(" MHZ");
  Serial.print("Bus Width: ");
  Serial.print(lcd.getBusWidth(),DEC);
  Serial.println("-bits");

  lcd.graphicMode(true);
  lcd.fillScreen(0x0000);
  lcd.setRotation(0);
}

This is just an example that happens to work on my DB5 wired to a RA8876...
 
Is there a post in these 10 pages that would show the wiring needed for the RA8876? That would be nice in p#1 too.
Suppose I can wait at this point for the updated board from @KurtE and just set up SPI for now if I get anxious - and free time.
Been awhile since I hooked up up to SPI... Other than use the one I have with a Teensy 4.1 plugged into the back of the SPI
version of the RA8876
1721778193919.png

The board is setup with all of the default jumpers (shunts). The board was also setup that allowed me to plug in
a 4.3 inch RA8875

1721778424194.png

1721778473649.png

Needless to say you need
GND (1 and or 2m plus others 39, 40)
VDD -Mine is setup for +5v - Pins 3 or 4 or 37, 38
5 - Chip select
6 - SDO (MISO) - does not play well with others
7 MOSI
8 SCLK
11 reset
14 backlight control depending on jumpers...
Probably not hard to change yours to Parallel...
1721779157651.png

Just unsolder some jumpers shown as shorted for 4 wire Serial and solder some other

I think @wwatson, mentioned the wiring as well
 
Thanks @all - helpful info.
Keep getting to help others - neighbor's poor phone on the porch moving pictures to a Flash drive as it had NO SPACE left - Android OS was even throwing a 'NO SPACE' warning. 4,500+ photos on a 24 GB phone ... moving 500 off (after smaller batches first) taking 1.5 hours ... 3,500 more to go ... And the morning before lunch weeding with local 'Apple service' friend who felt he owed me some hours ...
 
@KurtE - Decided to try your FB version of testDMA.ino. After updating my version of MemoryHexDump and setting busSpeed to 12MHz it worked great in 8-bit and 16-bit modes:D If it is ok with you I would like to add it to the testCases folder...
 
Setup setup the RA8876 SPI version. Running into a few issues. Got tired of commenting and un-commenting "use_spi" so I created a config header file to stick the defines like that in:
Code:
/* RA8876_Config.h
 A file to place user defines and configs.
*/

#ifndef RA8876_CONFIG_H
#define RA8876_CONFIG_H

// Uncomment to use SPI interface instead of 8080 interface.
#define USE_SPI

// Uncomment to use FT5206 touch.
#define USE_FT5206_TOUCH

#endif // RA8876_CONFIG_H

It's not that I am lazy (even though I can be) but going through all of the examples in all of the modes can be tedious and error prone. With some of the examples I am getting 2D failed messages and in FontTest4 OpenSans24 fails. I had the same problem once before in 8080 mode. Will have to test again. I am using the DB4.5 board for SPI testing. Will push up changes when finished...
 
Quick update, playing around with simple OV5640 to RA8876 parallel sketch to try out DMA stuff...
Can be cleaned up, but current version looks like:
C++:
#include <stdint.h>

#include <RA8876_t41_p.h>

#include "Teensy_Camera.h"

#define USE_DB5_SHIELD
#define useRA9976
#define DVP_CAMERA_OV5640

#ifdef DVP_CAMERA_OV2640
#include "Teensy_OV2640/OV2640.h"
OV2640 omni;
Camera camera(omni);
#define CameraID OV2640a
#define MIRROR_FLIP_CAMERA
#else
//define DVP_CAMERA_OV5640
#include "Teensy_OV5640/OV5640.h"
OV5640 omni;
Camera camera(omni);
#define CameraID OV5640a
#define MIRROR_FLIP_CAMERA
#endif
//set cam configuration - need to remember when saving jpeg
framesize_t camera_framesize = FRAMESIZE_SVGA; // FRAMESIZE_1024X600;
pixformat_t camera_format = RGB565;
bool useGPIO = false;


//Set up Display
#ifdef ARDUINO_TEENSY_DEVBRD4
#undef USE_MMOD_ATP_ADAPTER
#define TFT_CS 10  // AD_B0_02
#define TFT_DC 25  // AD_B0_03
#define TFT_RST 24
#define VSYNC_PIN 21

#elif defined(ARDUINO_TEENSY_DEVBRD5)
#undef USE_MMOD_ATP_ADAPTER
#define DB5_USE_CSI
#define VSYNC_PIN 21

uint8_t dc = 55;
uint8_t cs = 53;
uint8_t rst = 54;
#endif
RA8876_t41_p tft = RA8876_t41_p(dc, cs, rst);  //(dc, cs, rst)

#if defined(ARDUINO_TEENSY_DEVBRD4) || defined(ARDUINO_TEENSY_DEVBRD5)
extern "C" bool sdram_begin(uint8_t external_sdram_size, uint8_t clock, uint8_t useDQS);
#endif

#define TFT_BLACK BLACK
#define TFT_YELLOW YELLOW
#define TFT_RED RED
#define TFT_GREEN GREEN
#define TFT_BLUE BLUE
//#define CENTER RA8876_t3::CENTER

// Setup framebuffers
DMAMEM uint16_t FRAME_WIDTH, FRAME_HEIGHT;
uint16_t *frameBuffer = nullptr;
uint16_t *frameBuffer2 = nullptr;

void setup() {
    Serial.begin(921600);
    while (!Serial && millis() < 5000) {}
#if defined(USB_DUAL_SERIAL) || defined(USB_TRIPLE_SERIAL)
    SerialUSB1.begin(921600);
#endif

    if (CrashReport) {
        Serial.print(CrashReport);
        Serial.println("Press any key to continue");
    }

    tft.setBusWidth(16);
    tft.setFlexIOPins(56, 52, 40);
    tft.begin(12);

    tft.fillScreen(TFT_BLACK);
    delay(500);

    tft.fillScreen(TFT_BLACK);

    // try using the CSI pins on devboard 5
    camera.setPins(65, 64, 17, 16, 57, 27, 26, 67, 66, 21, 20, 23, 22, 58);

    //  FRAMESIZE_VGA = 0,
    //  FRAMESIZE_QQVGA,    // 160x120
    //  FRAMESIZE_QVGA,     // 320x240
    //  FRAMESIZE_480X320,
    //  FRAMESIZE_320X320,  // 320x320
    //  FRAMESIZE_QVGA4BIT,
    //  FRAMESIZE_QCIF,
    //  FRAMESIZE_CIF,
    //  FRAMESIZE_SVGA, //800, 600
    //  FRAMESIZE_UXGA, //1500, 1200
    //  FRAMESIZE_1024X600
    uint8_t status = 0;
    status = camera.begin(camera_framesize, camera_format, 30, CameraID, useGPIO);

    Serial.printf("Begin status: %d\n", status);
    if (!status) {
        Serial.println("Camera failed to start again program halted");
        while (1) {}
    }

    frameBuffer = (uint16_t *)((((uint32_t)(sdram_malloc(camera.width() * camera.height() * 2 + 32)) + 32) & 0xffffffe0));
    frameBuffer2 = (uint16_t *)((((uint32_t)(sdram_malloc(camera.width() * camera.height() * 2 + 32)) + 32) & 0xffffffe0));

    Serial.printf("Camera Buffers: %p %p\n", frameBuffer, frameBuffer2);

    //camera.setBrightness(0);          // -2 to +2
    //camera.setContrast(0);            // -2 to +2
    //camera.setSaturation(0);          // -2 to +2
    //omni.setSpecialEffect(RETRO);  // NOEFFECT, NEGATIVE, BW, REDDISH, GREEISH, BLUEISH, RETRO
    //omni.setWBmode(0);                  // AWB ON, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home

    Serial.println("Camera settings:");
    Serial.print("\twidth = ");
    Serial.println(camera.width());
    Serial.print("\theight = ");
    Serial.println(camera.height());
    //Serial.print("\tbits per pixel = NA");
    //Serial.println(camera.bitsPerPixel());
    Serial.println();
    Serial.printf("TFT Width = %u Height = %u\n\n", tft.width(), tft.height());

    FRAME_HEIGHT = camera.height();
    FRAME_WIDTH = camera.width();
    Serial.printf("ImageSize (w,h): %d, %d\n", FRAME_WIDTH, FRAME_HEIGHT);

    /**********************************************************/
    tft.graphicMode(true);
    tft.setRotation(2);
    tft.onDMACompleteCB(&dma_complete_cb);
    wait_for_user_input();
}


int end_wait_char = 0;

void wait_for_user_input() {
    while (Serial.read() != -1) {}
    Serial.println("Press any key to continue");
    while ((end_wait_char = Serial.read()) == -1) {}
    while (Serial.read() != -1) {}
}

uint8_t loop_count = 0;
volatile bool dma_active = false;
void dma_complete_cb() {
    tft.updateScreen();
    dma_active = false;
}

void loop() {
    if (Serial.available()) {
        wait_for_user_input();
    }
    loop_count++;
    uint16_t *pframeBuffer = (loop_count & 1) ? frameBuffer : frameBuffer2;

    memset(frameBuffer, 0, camera.width() * camera.height() * 2);
    camera.readFrame(pframeBuffer, camera.width() * camera.height());
    int start_x = (tft.width() - camera.width()) / 2;
    int start_y = (tft.height() - camera.height()) / 2;
    if (end_wait_char == 'w') {
        tft.writeRect(start_x, start_y, camera.width(), camera.height(), pframeBuffer);
        delay(500);
    } else {
        while (dma_active) {}
        dma_active = true;
        tft.useCanvas(true);
        tft.pushPixels16bitDMA(pframeBuffer, start_x, start_y, camera.width(), camera.height());  // FLASHMEM buffer
        //delay(750);
    }
}

Couple of notes: Still wish we combine the callback code for Interrupt and DMA, such that the end user code does not necessarily have to differentiate between FlexIO that supports DMA and does not...

And: tft.onDMACompleteCB(&dma_complete_cb);
checked in code does not work... It never will call your function.
My current code has the following changes:
Code:
--- a/RA8876_t41_p/src/RA8876_t41_p.cpp
+++ b/RA8876_t41_p/src/RA8876_t41_p.cpp
@@ -994,9 +994,9 @@ FASTRUN void RA8876_t41_p::flexDma_Callback() {
   however, it seems like a waste of time to wait here, since the process otherwise completes in the background and the shifter buffers are ready to receive new data while the transfer completes.
   I think in most applications you could continue without waiting. You can start a new DMA transfer as soon as the first one completes (no need to wait for FlexIO to finish shifting). */
   WR_DMATransferDone = true;
-  if(isDMACB) {
+  //if(isDMACB) {
     _onDMACompleteCB();
-  }
+  //}
 }


 void RA8876_t41_p::DMAerror() {
@@ -1009,7 +1009,6 @@ void RA8876_t41_p::DMAerror() {
 FASTRUN void RA8876_t41_p::pushPixels16bitDMA(const uint16_t * pcolors, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
   uint32_t area = (x2)*(y2);
   while(WR_DMATransferDone == false) {}    //Wait for any DMA transfers to complete
-
   graphicMode(true);
   activeWindowXY(x1,y1);
   activeWindowWH(x2,y2);
diff --git a/RA8876_t41_p/src/RA8876_t41_p.h b/RA8876_t41_p/src/RA8876_t41_p.h
index ab52137..7a65974 100644
--- a/RA8876_t41_p/src/RA8876_t41_p.h
+++ b/RA8876_t41_p/src/RA8876_t41_p.h
@@ -184,7 +184,7 @@ class RA8876_t41_p : public RA8876_common {
     const FlexIOHandler::FLEXIO_Hardware_t *hw;


     // DMA
-    bool isDMACB = false;
+    //bool isDMACB = false;
     void _onDMACompleteCB();
        CBF _DMAcallback;
        void onDMACompleteCB(CBF callback) {_DMAcallback = callback; }


D:\github\TeensyRA8876Combined>

If you want, I can create a PR, or...
 
Quick update, playing around with simple OV5640 to RA8876 parallel sketch to try out DMA stuff...
Can be cleaned up, but current version looks like:
C++:
#include <stdint.h>

#include <RA8876_t41_p.h>

#include "Teensy_Camera.h"

#define USE_DB5_SHIELD
#define useRA9976
#define DVP_CAMERA_OV5640

#ifdef DVP_CAMERA_OV2640
#include "Teensy_OV2640/OV2640.h"
OV2640 omni;
Camera camera(omni);
#define CameraID OV2640a
#define MIRROR_FLIP_CAMERA
#else
//define DVP_CAMERA_OV5640
#include "Teensy_OV5640/OV5640.h"
OV5640 omni;
Camera camera(omni);
#define CameraID OV5640a
#define MIRROR_FLIP_CAMERA
#endif
//set cam configuration - need to remember when saving jpeg
framesize_t camera_framesize = FRAMESIZE_SVGA; // FRAMESIZE_1024X600;
pixformat_t camera_format = RGB565;
bool useGPIO = false;


//Set up Display
#ifdef ARDUINO_TEENSY_DEVBRD4
#undef USE_MMOD_ATP_ADAPTER
#define TFT_CS 10  // AD_B0_02
#define TFT_DC 25  // AD_B0_03
#define TFT_RST 24
#define VSYNC_PIN 21

#elif defined(ARDUINO_TEENSY_DEVBRD5)
#undef USE_MMOD_ATP_ADAPTER
#define DB5_USE_CSI
#define VSYNC_PIN 21

uint8_t dc = 55;
uint8_t cs = 53;
uint8_t rst = 54;
#endif
RA8876_t41_p tft = RA8876_t41_p(dc, cs, rst);  //(dc, cs, rst)

#if defined(ARDUINO_TEENSY_DEVBRD4) || defined(ARDUINO_TEENSY_DEVBRD5)
extern "C" bool sdram_begin(uint8_t external_sdram_size, uint8_t clock, uint8_t useDQS);
#endif

#define TFT_BLACK BLACK
#define TFT_YELLOW YELLOW
#define TFT_RED RED
#define TFT_GREEN GREEN
#define TFT_BLUE BLUE
//#define CENTER RA8876_t3::CENTER

// Setup framebuffers
DMAMEM uint16_t FRAME_WIDTH, FRAME_HEIGHT;
uint16_t *frameBuffer = nullptr;
uint16_t *frameBuffer2 = nullptr;

void setup() {
    Serial.begin(921600);
    while (!Serial && millis() < 5000) {}
#if defined(USB_DUAL_SERIAL) || defined(USB_TRIPLE_SERIAL)
    SerialUSB1.begin(921600);
#endif

    if (CrashReport) {
        Serial.print(CrashReport);
        Serial.println("Press any key to continue");
    }

    tft.setBusWidth(16);
    tft.setFlexIOPins(56, 52, 40);
    tft.begin(12);

    tft.fillScreen(TFT_BLACK);
    delay(500);

    tft.fillScreen(TFT_BLACK);

    // try using the CSI pins on devboard 5
    camera.setPins(65, 64, 17, 16, 57, 27, 26, 67, 66, 21, 20, 23, 22, 58);

    //  FRAMESIZE_VGA = 0,
    //  FRAMESIZE_QQVGA,    // 160x120
    //  FRAMESIZE_QVGA,     // 320x240
    //  FRAMESIZE_480X320,
    //  FRAMESIZE_320X320,  // 320x320
    //  FRAMESIZE_QVGA4BIT,
    //  FRAMESIZE_QCIF,
    //  FRAMESIZE_CIF,
    //  FRAMESIZE_SVGA, //800, 600
    //  FRAMESIZE_UXGA, //1500, 1200
    //  FRAMESIZE_1024X600
    uint8_t status = 0;
    status = camera.begin(camera_framesize, camera_format, 30, CameraID, useGPIO);

    Serial.printf("Begin status: %d\n", status);
    if (!status) {
        Serial.println("Camera failed to start again program halted");
        while (1) {}
    }

    frameBuffer = (uint16_t *)((((uint32_t)(sdram_malloc(camera.width() * camera.height() * 2 + 32)) + 32) & 0xffffffe0));
    frameBuffer2 = (uint16_t *)((((uint32_t)(sdram_malloc(camera.width() * camera.height() * 2 + 32)) + 32) & 0xffffffe0));

    Serial.printf("Camera Buffers: %p %p\n", frameBuffer, frameBuffer2);

    //camera.setBrightness(0);          // -2 to +2
    //camera.setContrast(0);            // -2 to +2
    //camera.setSaturation(0);          // -2 to +2
    //omni.setSpecialEffect(RETRO);  // NOEFFECT, NEGATIVE, BW, REDDISH, GREEISH, BLUEISH, RETRO
    //omni.setWBmode(0);                  // AWB ON, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home

    Serial.println("Camera settings:");
    Serial.print("\twidth = ");
    Serial.println(camera.width());
    Serial.print("\theight = ");
    Serial.println(camera.height());
    //Serial.print("\tbits per pixel = NA");
    //Serial.println(camera.bitsPerPixel());
    Serial.println();
    Serial.printf("TFT Width = %u Height = %u\n\n", tft.width(), tft.height());

    FRAME_HEIGHT = camera.height();
    FRAME_WIDTH = camera.width();
    Serial.printf("ImageSize (w,h): %d, %d\n", FRAME_WIDTH, FRAME_HEIGHT);

    /**********************************************************/
    tft.graphicMode(true);
    tft.setRotation(2);
    tft.onDMACompleteCB(&dma_complete_cb);
    wait_for_user_input();
}


int end_wait_char = 0;

void wait_for_user_input() {
    while (Serial.read() != -1) {}
    Serial.println("Press any key to continue");
    while ((end_wait_char = Serial.read()) == -1) {}
    while (Serial.read() != -1) {}
}

uint8_t loop_count = 0;
volatile bool dma_active = false;
void dma_complete_cb() {
    tft.updateScreen();
    dma_active = false;
}

void loop() {
    if (Serial.available()) {
        wait_for_user_input();
    }
    loop_count++;
    uint16_t *pframeBuffer = (loop_count & 1) ? frameBuffer : frameBuffer2;

    memset(frameBuffer, 0, camera.width() * camera.height() * 2);
    camera.readFrame(pframeBuffer, camera.width() * camera.height());
    int start_x = (tft.width() - camera.width()) / 2;
    int start_y = (tft.height() - camera.height()) / 2;
    if (end_wait_char == 'w') {
        tft.writeRect(start_x, start_y, camera.width(), camera.height(), pframeBuffer);
        delay(500);
    } else {
        while (dma_active) {}
        dma_active = true;
        tft.useCanvas(true);
        tft.pushPixels16bitDMA(pframeBuffer, start_x, start_y, camera.width(), camera.height());  // FLASHMEM buffer
        //delay(750);
    }
}

Couple of notes: Still wish we combine the callback code for Interrupt and DMA, such that the end user code does not necessarily have to differentiate between FlexIO that supports DMA and does not...

And: tft.onDMACompleteCB(&dma_complete_cb);
checked in code does not work... It never will call your function.
My current code has the following changes:
Code:
--- a/RA8876_t41_p/src/RA8876_t41_p.cpp
+++ b/RA8876_t41_p/src/RA8876_t41_p.cpp
@@ -994,9 +994,9 @@ FASTRUN void RA8876_t41_p::flexDma_Callback() {
   however, it seems like a waste of time to wait here, since the process otherwise completes in the background and the shifter buffers are ready to receive new data while the transfer completes.
   I think in most applications you could continue without waiting. You can start a new DMA transfer as soon as the first one completes (no need to wait for FlexIO to finish shifting). */
   WR_DMATransferDone = true;
-  if(isDMACB) {
+  //if(isDMACB) {
     _onDMACompleteCB();
-  }
+  //}
 }


 void RA8876_t41_p::DMAerror() {
@@ -1009,7 +1009,6 @@ void RA8876_t41_p::DMAerror() {
 FASTRUN void RA8876_t41_p::pushPixels16bitDMA(const uint16_t * pcolors, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
   uint32_t area = (x2)*(y2);
   while(WR_DMATransferDone == false) {}    //Wait for any DMA transfers to complete
-
   graphicMode(true);
   activeWindowXY(x1,y1);
   activeWindowWH(x2,y2);
diff --git a/RA8876_t41_p/src/RA8876_t41_p.h b/RA8876_t41_p/src/RA8876_t41_p.h
index ab52137..7a65974 100644
--- a/RA8876_t41_p/src/RA8876_t41_p.h
+++ b/RA8876_t41_p/src/RA8876_t41_p.h
@@ -184,7 +184,7 @@ class RA8876_t41_p : public RA8876_common {
     const FlexIOHandler::FLEXIO_Hardware_t *hw;


     // DMA
-    bool isDMACB = false;
+    //bool isDMACB = false;
     void _onDMACompleteCB();
        CBF _DMAcallback;
        void onDMACompleteCB(CBF callback) {_DMAcallback = callback; }


D:\github\TeensyRA8876Combined>

If you want, I can create a PR, or...
Might as well. Then we can test. I'll finish testing on this end and put it up and then do the PR...
 
@KurtE - @wwatson

Just synched with the PR and ran the sketch in post #261 and got some strangeness.

1. If I send a 'w' for writeRect it does not work, i.e., nothing is displayed ? I do see data in the serial monitor

Code:
$$Count of RxFifoFull ISRs:7501
$$ImageSensor::readFrameCSI(0x80000020, 480000, 0x0, 0)
After start capture
    CSI_CSICR1: 401e0912
    CSI_CSICR2: c0000000
    CSI_CSICR3: 61020
    CSI_CSISTATFIFO: 0
    CSI_CSIRFIFO: 88108a1
    CSI_CSIRXCNT: 9600
    CSI_CSISR: 80004000
    CSI_CSIDMASA_STATFIFO: 0
    CSI_CSIDMATS_STATFIFO: 0
    CSI_CSIDMASA_FB1: 80000020
    CSI_CSIDMASA_FB2: 80000020
    CSI_CSIFBUF_PARA: 0
    CSI_CSIIMAG_PARA: 6400258
    CSI_CSICR18: 8002d210
    CSI_CSICR19: 10
    CSI_CSIRFIFO: 88108a1
$$Count of RxFifoFull ISRs:7501
Press any key to continue

2. Using pushpixels DMA method get noticeable delay between frames. Dont remember that with the earlier sketch.
 
@KurtE - @wwatson

Just synched with the PR and ran the sketch in post #261 and got some strangeness.

1. If I send a 'w' for writeRect it does not work, i.e., nothing is displayed ? I do see data in the serial monitor

Code:
$$Count of RxFifoFull ISRs:7501
$$ImageSensor::readFrameCSI(0x80000020, 480000, 0x0, 0)
After start capture
    CSI_CSICR1: 401e0912
    CSI_CSICR2: c0000000
    CSI_CSICR3: 61020
    CSI_CSISTATFIFO: 0
    CSI_CSIRFIFO: 88108a1
    CSI_CSIRXCNT: 9600
    CSI_CSISR: 80004000
    CSI_CSIDMASA_STATFIFO: 0
    CSI_CSIDMATS_STATFIFO: 0
    CSI_CSIDMASA_FB1: 80000020
    CSI_CSIDMASA_FB2: 80000020
    CSI_CSIFBUF_PARA: 0
    CSI_CSIIMAG_PARA: 6400258
    CSI_CSICR18: 8002d210
    CSI_CSICR19: 10
    CSI_CSIRFIFO: 88108a1
$$Count of RxFifoFull ISRs:7501
Press any key to continue

2. Using pushpixels DMA method get noticeable delay between frames. Dont remember that with the earlier sketch.
I noticed as well.

1) This has the try to do the updateScreen on the DMA callback, I will probably move it out of there... WIll add some elapsedMicros on some of the areas to get an idea of where the time is spent...

2) Noticed. Was not sure if it was due to some hacking, where I was trying to add a camera resolution of 1024x600.
 
I noticed as well.
Wasn't sure if it was me doing something wrong or not.

Oh, did try our regular OV5640_ra8876 sketch and looks like the framerates I was seeing when doing 'F' and 'm' went down using the hack I had put in to increase frame rate. Going to investigate more
 
I pushed up another change to the PR to fix:
1. If I send a 'w' for writeRect it does not work, i.e., nothing is displayed ? I do see data in the serial monitor
The issue is the writeRect for rotation 2 was trying to allocate a full size duplicate buffer w * h * 2 bytes, which in
this case was 800*600*2 bytes which failed... But the code actually only used one row of the array:
Code:
while (h) {
                    for (int i = 0; i < w; i++) rotated_buffer[w-i-1] = *pcolors++;
So I reduced it down to one row worth of space...

The Test sketch has not changed much but here it is again:
C++:
#include <stdint.h>

#include <RA8876_t41_p.h>

#include "Teensy_Camera.h"

#define USE_DB5_SHIELD
#define useRA9976
#define DVP_CAMERA_OV5640

#ifdef DVP_CAMERA_OV2640
#include "Teensy_OV2640/OV2640.h"
OV2640 omni;
Camera camera(omni);
#define CameraID OV2640a
#define MIRROR_FLIP_CAMERA
#else
//define DVP_CAMERA_OV5640
#include "Teensy_OV5640/OV5640.h"
OV5640 omni;
Camera camera(omni);
#define CameraID OV5640a
#define MIRROR_FLIP_CAMERA
#endif
//set cam configuration - need to remember when saving jpeg
framesize_t camera_framesize = FRAMESIZE_SVGA; // FRAMESIZE_1024X600;
pixformat_t camera_format = RGB565;
bool useGPIO = false;


//Set up Display
#ifdef ARDUINO_TEENSY_DEVBRD4
#undef USE_MMOD_ATP_ADAPTER
#define TFT_CS 10  // AD_B0_02
#define TFT_DC 25  // AD_B0_03
#define TFT_RST 24
#define VSYNC_PIN 21

#elif defined(ARDUINO_TEENSY_DEVBRD5)
#undef USE_MMOD_ATP_ADAPTER
#define DB5_USE_CSI
#define VSYNC_PIN 21

uint8_t dc = 55;
uint8_t cs = 53;
uint8_t rst = 54;
#endif
RA8876_t41_p tft = RA8876_t41_p(dc, cs, rst);  //(dc, cs, rst)

#if defined(ARDUINO_TEENSY_DEVBRD4) || defined(ARDUINO_TEENSY_DEVBRD5)
extern "C" bool sdram_begin(uint8_t external_sdram_size, uint8_t clock, uint8_t useDQS);
#endif

#define TFT_BLACK BLACK
#define TFT_YELLOW YELLOW
#define TFT_RED RED
#define TFT_GREEN GREEN
#define TFT_BLUE BLUE
//#define CENTER RA8876_t3::CENTER

// Setup framebuffers
DMAMEM uint16_t FRAME_WIDTH, FRAME_HEIGHT;
uint16_t *frameBuffer = nullptr;
uint16_t *frameBuffer2 = nullptr;

void setup() {
    Serial.begin(921600);
    while (!Serial && millis() < 5000) {}
#if defined(USB_DUAL_SERIAL) || defined(USB_TRIPLE_SERIAL)
    SerialUSB1.begin(921600);
#endif

    if (CrashReport) {
        Serial.print(CrashReport);
        Serial.println("Press any key to continue");
    }

    tft.setBusWidth(16);
    tft.setFlexIOPins(56, 52, 40);
    tft.begin(12);

    tft.fillScreen(TFT_BLACK);
    delay(500);

    tft.fillScreen(TFT_BLACK);

    // try using the CSI pins on devboard 5
    camera.setPins(65, 64, 17, 16, 57, 27, 26, 67, 66, 21, 20, 23, 22, 58);

    //  FRAMESIZE_VGA = 0,
    //  FRAMESIZE_QQVGA,    // 160x120
    //  FRAMESIZE_QVGA,     // 320x240
    //  FRAMESIZE_480X320,
    //  FRAMESIZE_320X320,  // 320x320
    //  FRAMESIZE_QVGA4BIT,
    //  FRAMESIZE_QCIF,
    //  FRAMESIZE_CIF,
    //  FRAMESIZE_SVGA, //800, 600
    //  FRAMESIZE_UXGA, //1500, 1200
    //  FRAMESIZE_1024X600
    uint8_t status = 0;
    status = camera.begin(camera_framesize, camera_format, 30, CameraID, useGPIO);

    Serial.printf("Begin status: %d\n", status);
    if (!status) {
        Serial.println("Camera failed to start again program halted");
        while (1) {}
    }
    camera.debug(false);
    frameBuffer = (uint16_t *)((((uint32_t)(sdram_malloc(camera.width() * camera.height() * 2 + 32)) + 32) & 0xffffffe0));
    frameBuffer2 = (uint16_t *)((((uint32_t)(sdram_malloc(camera.width() * camera.height() * 2 + 32)) + 32) & 0xffffffe0));

    Serial.printf("Camera Buffers: %p %p\n", frameBuffer, frameBuffer2);

    //camera.setBrightness(0);          // -2 to +2
    //camera.setContrast(0);            // -2 to +2
    //camera.setSaturation(0);          // -2 to +2
    //omni.setSpecialEffect(RETRO);  // NOEFFECT, NEGATIVE, BW, REDDISH, GREEISH, BLUEISH, RETRO
    //omni.setWBmode(0);                  // AWB ON, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home

    Serial.println("Camera settings:");
    Serial.print("\twidth = ");
    Serial.println(camera.width());
    Serial.print("\theight = ");
    Serial.println(camera.height());
    //Serial.print("\tbits per pixel = NA");
    //Serial.println(camera.bitsPerPixel());
    Serial.println();
    Serial.printf("TFT Width = %u Height = %u\n\n", tft.width(), tft.height());

    FRAME_HEIGHT = camera.height();
    FRAME_WIDTH = camera.width();
    Serial.printf("ImageSize (w,h): %d, %d\n", FRAME_WIDTH, FRAME_HEIGHT);

    /**********************************************************/
    tft.graphicMode(true);
    tft.setRotation(2);
    tft.onDMACompleteCB(&dma_complete_cb);
    wait_for_user_input();
}


int end_wait_char = 0;

void wait_for_user_input() {
    while (Serial.read() != -1) {}
    Serial.println("Press any key to continue");
    while ((end_wait_char = Serial.read()) == -1) {}
    while (Serial.read() != -1) {}
    tft.fillScreen(BLUE);
}

uint8_t loop_count = 0;
volatile bool dma_active = false;
void dma_complete_cb() {
    dma_active = false;
}

void loop() {
    if (Serial.available()) {
        wait_for_user_input();
    }
    loop_count++;
    uint16_t *pframeBuffer = (loop_count & 1) ? frameBuffer : frameBuffer2;

    //memset(pframeBuffer, 0, camera.width() * camera.height() * 2);
    uint32_t start_time = micros();
    camera.readFrame(pframeBuffer, camera.width() * camera.height());
    uint32_t after_read_frame = micros();
    int start_x = (tft.width() - camera.width()) / 2;
    int start_y = (tft.height() - camera.height()) / 2;
    if (end_wait_char == 'w') {
        tft.useCanvas(false);
        //Serial.printf("Call WriteRect(%d, %d, %d, %d, %p\n", start_x, start_y, camera.width(), camera.height(), pframeBuffer);
        tft.writeRect(start_x, start_y, camera.width(), camera.height(), pframeBuffer);
        //delay(500);
    } else {
        while (dma_active) {}
        uint32_t after_dma_active = micros();
        tft.updateScreen();
        uint32_t after_updateScreen = micros();
        dma_active = true;
        tft.useCanvas(true);
        tft.pushPixels16bitDMA(pframeBuffer, start_x, start_y, camera.width(), camera.height());  // FLASHMEM buffer
        uint32_t after_push_pixels = micros();
        Serial.printf("%u %u %u %u\n", after_read_frame - start_time, after_dma_active - after_read_frame,
                 after_updateScreen - after_dma_active,    after_push_pixels - after_updateScreen);

        //delay(750);
    }
}
 
Backed up and did the PR. Downloaded and will test tomorrow. I will probably create another WIP branch for the SPI stuff. It has problems with 2D errors. Need to investigate what is going on or who is calling who;)
 
For the fun of it, I was setting up a resolution for the camera of 1024x600 and tried the above sketch with it.
It does display the image properly using writeRect, however the
Code:
tft.pushPixels16bitDMA(pframeBuffer, start_x, start_y, camera.width(), camera.height());
looks like it is only drawing like the bottom row of pixels...
Will investigate.
 
Here is a simpler sketch that demonstrates the issue. This is a stripped-out version of your testDMA sketch,
But I allocate PSRAM the size 1024x600*2... I do some pretty simple fill of the memory, mostly RED, with a BLUE edge of about 10 pixels and the far outside a ring 1 pixel wide of green.

writeRect displays it correctly
the dma code does not.
And also after this the fillScreen does not fill the whole screen.
C++:
//#define use_spi
#if defined(use_spi)
#include <SPI.h>
#include <RA8876_t3.h>
#else
//#include <RA8876_t3.h>
#include <RA8876_t41_p.h>
#endif
//#include <math.h>

#if defined(use_spi)
#define RA8876_CS 10
#define RA8876_RESET 9
#define BACKLITE 5                                   //External backlight control connected to this Arduino pin
RA8876_t3 tft = RA8876_t3(RA8876_CS, RA8876_RESET);  //Using standard SPI pins
#else
#if defined(ARDUINO_TEENSY_DEVBRD5)
#undef USE_MMOD_ATP_ADAPTER
#define DB5_USE_CSI
#define USE_DB5_SHIELD
#define VSYNC_PIN 21

#ifdef USE_DB5_SHIELD
uint8_t dc = 55;
uint8_t cs = 53;
uint8_t rst = 54;
#else
uint8_t dc = 13;
uint8_t cs = 11;
uint8_t rst = 12;
#endif
#define BACKLITE 5  //External backlight control connected to this Arduino pin
//RA8876_t41_p lcd = RA8876_t41_p(dc,cs,rst); //(dc, cs, rst)
RA8876_t41_p lcd = RA8876_t41_p(dc, cs, rst);  //(dc, cs, rst)
#endif
#endif
uint32_t start = 0;
uint32_t end = 0;
uint8_t busSpeed = 12;

uint16_t *sdram_image;

void setup() {
    while (!Serial && millis() < 3000) {}  //wait for Serial Monitor
    Serial.printf("%c MicroMod Board and RA8876 parallel 8080 mode testing (8Bit/DMA)\n\n", 12);
    //  Serial.print(CrashReport);

    // Set 16bit mode
    //  lcd.setBusWidth(16);
    // DB5.0 WR pin, RD pin, D0 pin.
    //  lcd.setFlexIOPins(53,52,40);

#if defined(use_spi)
    lcd.begin();
#else
#ifdef USE_DB5_SHIELD
    lcd.setBusWidth(16);
    lcd.setFlexIOPins(56, 52, 40);
#endif
    lcd.begin(busSpeed);  // 20 is working in 8bit and 16bit mode on T41
#endif
    delay(100);

    Serial.print("Bus speed: ");
    Serial.print(busSpeed, DEC);
    Serial.println(" MHZ");
    Serial.print("Bus Width: ");
    Serial.print(lcd.getBusWidth(), DEC);
    Serial.println("-bits");

    lcd.graphicMode(true);
    lcd.setRotation(0);

    sdram_image = (uint16_t*)sdram_malloc(1024*600*2);

    // lets fill it with RED, have a blue ring around edges. and Green one pixel around the edge.
    uint32_t x, y;
    uint16_t *pb = sdram_image;
    for (x = 0; x < (1024 * 600); x++) pb[x] = RED;

    for (x = 0; x < 1024; x++) pb[x] = GREEN;
   
    for (y = 1; y < 11; y++) {
        pb = &sdram_image[y * 1024];
        for (x = 1; x < 1023; x++) pb[x] = BLUE;
        pb[0] = GREEN;
        pb[1023] = GREEN;
    }
    for (; y < 589; y++) {
        pb = &sdram_image[y * 1024];
        pb[0] = GREEN;
        pb[1023] = GREEN;

        for (x = 1; x < 11; x++) pb[x] = BLUE;
        for (x = 1003; x < 1023; x++) pb[x] = BLUE;
    }
    for (; y < 599; y++) {
        pb = &sdram_image[y * 1024];
        for (x = 1; x < 1023; x++) pb[x] = BLUE;
        pb[0] = GREEN;
        pb[1023] = GREEN;
    }
    pb += 1024; // last row.
    for (x = 0; x < 1024; x++) pb[x] = GREEN;

}

void loop() {
    lcd.fillScreen(YELLOW);
    waitforInput();
    lcd.writeRect(0, 0, 1024, 600, sdram_image);
    waitforInput();
    lcd.fillScreen(MAGENTA);
    waitforInput();
    lcd.pushPixels16bitDMA(sdram_image, 0, 0, 1024, 600);  // FLASHMEM buffer
    waitforInput();
}

void waitforInput() {
    Serial.println("Press anykey to continue");
    while (Serial.read() == -1)
        ;
    while (Serial.read() != -1)
        ;
}
running it on DB5 could run on DB4 or 4.5 as well. Otherwise could try 4.1 with PSRAM or save image to file that is included... Or other
full size image

Edit the DMA x, y, w, h were wrong... updated Still does not work. I also added in another blank screen between the two as to
make sure
 
Last edited:
@KurtE @mjs513 - Today has been a real eye opener. First I never noticed that the examples were still in the Ra8876_t3 folder. They all work perfectly on the SPI display. The reason I was getting the 2D errors was:
Code:
#if defined(USE_SPI)

#define TFT_CS 10
#define TFT_RST 9

// #define TFT_CS 30
// #define TFT_RST 28
// #define TFT_BL 29

RA8876_t3 tft = RA8876_t3(TFT_CS, TFT_RST);
#else
uint8_t dc = 13;
uint8_t cs = 11;
uint8_t rst = 12;
RA8876_t41_p tft = RA8876_t41_p(dc,cs,rst); //(dc, cs, rst)
#endif
the CS and RST were setup for another board. Fixed that and the 2D errors went away:) Correct me if I am wrong, but do we really need two example folders? I removed the examples folder in the Ra8876_t3 folder and I am able to run all examples in SPI and 8080 modes. Just have to define "USE_SPI" in the RA8876_Config.h file.
@KurtE - Just tried your DMS test from P#272. And it does not finish the transfer from SDRAM. Will have to check it out...
 
Correct me if I am wrong, but do we really need two example folders? I removed the examples folder in the Ra8876_t3 folder and I am able to run all examples in SPI and 8080 modes. Just have to define "USE_SPI" in the RA8876_Config.h file.
Had a thought about moving all the examples from the t4 branch and putting them in the GFX library instead of having 2 separate folders with the same sketches.

Thoughts.
 
Examples: Maybe depends on final layout of library/libraries. Right now we have more or less 3 Arduino projects in the same Github project, which is fine, although I end up creating 3 links... Alternative could create one logical library, with maybe GFX as sub-directory...
Not sure what is best.
 
Back
Top