RA8876LiteTeensy For Teensy T36 and T40

Good Morning!

Tried hacking your one function to see if it made a difference:
Code:
void RA8876_t3::MemWrite_Down_Top_Left_Right(void)
{
/* Host Write Memory Direction (Only for Graphic Mode)
11b: Bottom .. Top then Left .. Right.
Ignored if canvas in linear addressing mode.		*/
	unsigned char temp;
	temp = lcdRegDataRead(RA8876_MACR);
	Serial.println(temp, BIN);
	
	temp |= cSetb2;
	temp |= cSetb1;
	Serial.println(temp, BIN);
	lcdRegDataWrite(RA8876_MACR, temp);
	
	temp = lcdRegDataRead(RA8876_MACR);
	Serial.println(temp, BIN);
	
}
Debug output:
Code:
Setup
0
110
110
Display looks sort of off...
IMG_1132.jpg

Also with the rotation, I might have missed it, but not sure who/if anything is updating the _width and _height members, whose values get returned by
tft.width(); and tft.height()?

Likewise the members, which in the init are set:
Code:
_scrollXL = 0;
	_scrollXR = _width;
	_scrollYT = 0;
	_scrollYB = _height;
As these are used in things like fill screen:
Code:
void RA8876_t3::fillScreen(uint16_t color) {
	drawSquareFill(_scrollXL, _scrollYT, _scrollXR, _scrollYB, color);
	check2dBusy();  //must wait for fill to finish before setting foreground color
	textColor(_TXTForeColor,_TXTBackColor);
	setTextCursor(_scrollXL,_scrollYT);
}
 
Last edited:
@KurtE
Sorry took so long to get back to you. Yep - that's off - not showing any rotation even though MACR now looks correct. As to your other question was working on it. Temporarily changed the rotate to:
Code:
void RA8876_t3::Rotate()
{
graphicMode(true);
  Serial.printf("%d, %d\n", width(), height());

	VSCAN_T_to_B();
	MemWrite_Down_Top_Left_Right();

	_width = 600;
	_height = 1024;
	SCREEN_WIDTH = _width;
	SCREEN_HEIGHT = _height;
	
	HDW = _width;
	VDH = _height;
	
	rightmarg =  (uint8_t)(_width / (_FNTwidth  * _scaleX));
	bottommarg = (uint8_t)(_height / (_FNTheight * _scaleY));
	_scrollXL = 0;
	_scrollXR = _width;
	_scrollYT = 0;
	_scrollYB = _height;
	_cursorX = _scrollXL;
	_cursorY = _scrollYT;
	CharPosX = _scrollXL;
	CharPosY = _scrollYT;
	_activeWindowXL = 0;
	_activeWindowXR = _width;
	_activeWindowYT = 0;
	_activeWindowYB = _height;
	
	// Position text cursor to default
	setTextCursor(_scrollXL, _scrollYT);
	// Setup Text Cursor
	cursorInit();
	// Set Margins to default settings
	setTMargins(0, 0, 0, 0); // Left Side, Top Side, Right Side, Bottom Side

	// Set graphic mouse cursor to center of screen
	gcursorxy(width() / 2, height() / 2);
	
  Serial.printf("%d, %d\n", width(), height());
	
	displayWindowStartXY(0,0);
	activeWindowXY(0,0);
    activeWindowWH(_width,_height);
	lcdRegWrite(0x04);
	
	setClipRect();
	setOrigin();
	setTextSize(1, 1);
 
}
but still no change. Not sure whats going on. Have more stuff to check.

EDIT: Also changed the defines for SCREEN_WIDTH, Height, HDW, VDH to int16t's and put them at the top of the CPP file.
 
Not a problem... I am also just taking a break from working out on the yard... So far three buckets of mulch spread. Another few to go.

I did some similar stuff....
Code:
void RA8876_t3::Rotate()
{

	VSCAN_T_to_B();
	MemWrite_Down_Top_Left_Right();
	 	
	displayWindowStartXY(0,0);
	activeWindowXY(0,0);
    activeWindowWH(600,1024);
	lcdRegWrite(0x04);
	_width = 	SCREEN_HEIGHT;
	_height = 	SCREEN_WIDTH;
	_scrollXL = 0;
	_scrollXR = _width;
	_scrollYT = 0;
	_scrollYB = _height;

 	setClipRect();
	setOrigin();

}
Also tried:
Code:
void RA8876_t3::MemWrite_Down_Top_Left_Right(void)
{
/* Host Write Memory Direction (Only for Graphic Mode)
11b: Bottom .. Top then Left .. Right.
Ignored if canvas in linear addressing mode.		*/
	unsigned char temp;
	temp = lcdRegDataRead(RA8876_MACR);
	Serial.println(temp, BIN);
	temp = RA8876_DIRECT_WRITE<<6|RA8876_READ_MEMORY_BTLR<<4|RA8876_WRITE_MEMORY_BTLR<<1;
	Serial.println(temp, BIN);
	lcdRegDataWrite(RA8876_MACR, temp);
	
	temp = lcdRegDataRead(RA8876_MACR);
	Serial.println(temp, BIN);
	
}
Did some additional printing of data
Code:
void setup() {
  Serial.begin(38400);
  long unsigned debug_start = millis ();
  while (!Serial && ((millis () - debug_start) <= 5000)) ;
  Serial.println("Setup");
  tft.begin(20000000);
  pinMode(BACKLITE, OUTPUT);
  digitalWrite(BACKLITE, HIGH);
  tft.backlight(true);
  tft.graphicMode(true);
  Serial.printf("Before W: %d H: %d\n", tft.width(), tft.height());
  tft.Rotate();
  Serial.printf("After W: %d H: %d\n", tft.width(), tft.height());
  tft.fillScreen(BLACK);
  //tft.textRotate(false);
  uint16_t x0, y0, x1, y1, x2, y2, c;
  tft.fillRect(0,0,400,200, RED);
  Serial.printf("MACR and End: %x\n", tft.lcdRegDataRead(RA8876_MACR));

}
Including the internal drawsquare filled and data shows:
Code:
Setup

DSF:(0 0)(1024 600) 10
DSF:(0 0)(1024 600) 10
DSF:(0 0)(1024 600) 10
DSF:(0 0)(1024 600) 10
DSF:(0 0)(1024 600) 10
DSF:(0 0)(1024 600) 10
DSF:(0 575)(1024 599) 10
DSF:(0 0)(1024 600) 10
DSF:(0 0)(1024 600) 10
DSF:(0 0)(1024 600) 10
Before W: 1024 H: 600
0

110110

110110

After W: 600 H: 1024
DSF:(0 0)(600 1024) 0
DSF:(0 0)(399 199) f800
MACR and End: 36
 
Showing some differences now, I hacked up the code some more...
Code:
void RA8876_t3::Rotate()
{

	VSCAN_T_to_B();
	MemWrite_Down_Top_Left_Right();
	 	
	displayWindowStartXY(0,0);
	activeWindowXY(0,0);
    activeWindowWH(600,1024);
	lcdRegWrite(0x04);
	_width = 	SCREEN_HEIGHT;
	_height = 	SCREEN_WIDTH;
	_scrollXL = 0;
	_scrollXR = _width;
	_scrollYT = 0;
	_scrollYB = _height;

 	setClipRect();
	setOrigin();

	// Real hack.
	pageOffset = PAGE1_START_ADDR;
	currentPage = PAGE1_START_ADDR;
	displayImageStartAddress(PAGE1_START_ADDR);
	displayImageWidth(_width);
	displayWindowStartXY(0,0);
	canvasImageStartAddress(PAGE1_START_ADDR);
	canvasImageWidth(_width);
	activeWindowXY(0,0);
	activeWindowWH(_width,_height); 
	setTextCursor(_cursorX, _cursorY);
	textColor(_TXTForeColor,_TXTBackColor);
	// Rebuild the display
	buildTextScreen();
}

Note: the hack area is code out of void RA8876_t3::selectScreen(uint32_t screenPage) {
Which also needs work as it is hard coded for the width and height. I switched this code here to use the set with and height...

Now shows two red squares...

Now off to do next couple of buckets of mulch

EDIT: before I go back out I was curious, so changed it to pause after fill screen and changed fill to yellow:
Code:
  tft.fillScreen(YELLOW);
  wait_for_keyboard();  // see if all yellow
  //tft.textRotate(false);
  uint16_t x0, y0, x1, y1, x2, y2, c;
  tft.fillRect(0,0,400,200, RED);
  Serial.printf("MACR and End: %x\n", tft.lcdRegDataRead(RA8876_MACR));
And now the screen goes fully yellow, but the one fillrect shows two rects.
 
@KurtE
Think the reason that we are seeing 2 active squares is that we are writing 2 different ways to the main window by setting canvas. I can get the same affect by using that useCanvas method and updateScreen. If you look at the due implementation its all done with the canvas so that works.

selectScreen, - just fixed it :)

Still not having any luck with rotation though
 
The other thing to be aware of with rotation is how the BTE memory transfer functions work. The low-level functions have two parameters for width...

Say you are copying a small rectangle from one part of the screen to another part. You obviously provide width and height for the size of that rectangle. The other width that's required is the stepover width. That is, when you get to the end of the first line in the rectangle, how far do you have to step over to get the first pixel of the next line? You need to select the memory location that's an entire screen width away (minus rectangle width.)

Since the RA8876 is still treating its internal memory as a landscape display, then the stepover width is always going to be the physical width of the panel, no matter what the rotation is. Maybe that register can be set during .begin() and then never changed?

I was able to set the BTE options to load an image from the Teensy in 3 of the 4 possible rotations. The 4th rotation isn't possible unless the Teensy reads out the data "sideways" to effectively do the rotation inside the Teensy before sending it to the screen. The RA8875 has fewer BTE options and needs the Teensy to do all the work for rotations. I'm currently stuck working on getting the SPI DMA to work with the RA8875.
 
The other thing to be aware of with rotation is how the BTE memory transfer functions work. The low-level functions have two parameters for width...

Say you are copying a small rectangle from one part of the screen to another part. You obviously provide width and height for the size of that rectangle. The other width that's required is the stepover width. That is, when you get to the end of the first line in the rectangle, how far do you have to step over to get the first pixel of the next line? You need to select the memory location that's an entire screen width away (minus rectangle width.)

Since the RA8876 is still treating its internal memory as a landscape display, then the stepover width is always going to be the physical width of the panel, no matter what the rotation is. Maybe that register can be set during .begin() and then never changed?

I was able to set the BTE options to load an image from the Teensy in 3 of the 4 possible rotations. The 4th rotation isn't possible unless the Teensy reads out the data "sideways" to effectively do the rotation inside the Teensy before sending it to the screen. The RA8875 has fewer BTE options and needs the Teensy to do all the work for rotations. I'm currently stuck working on getting the SPI DMA to work with the RA8875.

@MorganS

Do you have a example of that sketch? The other thing I am confuse about is that if I do a drawRectang(x,y,w,h) how would I use the bte function to move it?
 
Thanks @morganS

@mjs513, still not much progress since then, I updated the test sketch to output more stuff, both in rotation 0 and logical rotation 1...

Code:
#include <SPI.h>
#include "RA8876_t3.h"
#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

void setup() {
  Serial.begin(38400);
  long unsigned debug_start = millis ();
  while (!Serial && ((millis () - debug_start) <= 5000)) ;
  Serial.println("Setup");
  tft.begin(20000000);
  pinMode(BACKLITE, OUTPUT);
  digitalWrite(BACKLITE, HIGH);
  tft.backlight(true);
  tft.graphicMode(true);
  Serial.printf("Before W: %d H: %d\n", tft.width(), tft.height());
  tft.fillScreen(LIGHTYELLOW);
  drawTestScreen();
  wait_for_keyboard();  // see if all yellow
  
  tft.Rotate();
  Serial.printf("After W: %d H: %d\n", tft.width(), tft.height());
  tft.fillScreen(YELLOW);
  wait_for_keyboard();  // see if all yellow
  drawTestScreen();
  //tft.textRotate(false);
  uint16_t x0, y0, x1, y1, x2, y2, c;
  Serial.printf("MACR and End: %x\n", tft.lcdRegDataRead(RA8876_MACR));

}

void drawTestScreen() {
  tft.fillRect(0, 0, 50, 50, RED);
  tft.fillRect(tft.width() - 50, 0, 50, 50, GREEN);
  tft.fillRect(tft.width() - 50, tft.height() - 50 , 50, 50, BLUE);
  tft.fillRect(0, tft.height() - 50 , 50, 50, ORCHID);
  tft.drawLine(0, 0, tft.width(), tft.height(), WHITE);
  tft.drawLine(0, tft.height(), tft.width(), 0, BLACK); 
}

void loop() {
  // put your main code here, to run repeatedly:

}
void wait_for_keyboard() {
  Serial.println("Wait for any key to continue");
  while (Serial.read() == -1);
  while (Serial.read() != -1);
}

It outputs a test screen with squares of different colors in each corner plus two lines going across. First for default rotation looks correct
IMG_1133.jpg
 
@KurtE

Just ran it myself but made 1 minor change to the back color for the 1st screen. It looks like its putting the rectangles and lines in the correct spots for the rotation but the actual rotation is not occurring. Wondering if there is a BTE copy that has to be done as MorganS mentioned.
 
@KurtE - @morganS

Try changing this portion of the sketch to:
Code:
  tft.useCanvas();
  tft.Rotate();
  Serial.printf("After W: %d H: %d\n", tft.width(), tft.height());
  tft.fillScreen(BLACK);
  wait_for_keyboard();  // see if all yellow
  drawTestScreen();
  tft.updateScreen();
  //tft.textRotate(false);
  Serial.printf("MACR and End: %x\n", tft.lcdRegDataRead(RA8876_MACR));
Got it to display all Yellow but the boxes show up as gibberish at the top and bottom of the screen.

You also have to change the updateScreen function to:
Code:
void RA8876_t3::updateScreen() {
	bteMemoryCopy(PAGE2_START_ADDR,1024,0,0,
				  PAGE1_START_ADDR,_width, 0,0,
				 _width,1024);
}

EDIT: Took out the canvas stuff in ROTATE function. Its in useCanvas.
 
@mjs513 (and all) - I had a detour and re-watched the second half of a movie I fell asleep to last night... :D

Right now I am trying a bunch of random stuff to see what changes...

Maybe I need to read/reread some portions of the manual: Example:

Reg[02h] Has bits for Host Read Memory Direct and other bits for Host Write memory Direct...
I am assuming this only relates to the host and not the display.

So then I wonder what reflects what, example if I go by some my earlier code I pulled in
Code:
	displayImageStartAddress(PAGE1_START_ADDR);
	displayImageWidth(_width);
	displayWindowStartXY(0,0);
	canvasImageStartAddress(PAGE1_START_ADDR);
	canvasImageWidth(_width);
	activeWindowXY(0,0);
	activeWindowWH(_width,_height); 
	setTextCursor(_cursorX, _cursorY);
	textColor(_TXTForeColor,_TXTBackColor);
That is does the Main Image Start Address or Main image width change depending on rotation? Or is it always SCREEN_WIDTH, SCREEN_HEIGHT

Do the starting addresses always start at the logical address of Page or where 0,0 is within the page?

Again sorry maybe not explaining well enough, but again simply trying to figure out how the different coordinates, addressing modes interact with each other.
 
@mjs513 (and others)... Still playing around although been doing some other stuff.

Note: I hacked up your test sketch some more to see if anything jumps out:
Code:
#include <SPI.h>
#include "RA8876_t3.h"
#define RA8876_CS 10
#define RA8876_RESET 9
#define BACKLITE 5 //External backlight control connected to this Arduino pin
#define REG_DUMP_CNT 0x70
uint8_t reg_values[REG_DUMP_CNT];

RA8876_t3 tft = RA8876_t3(RA8876_CS, RA8876_RESET); //Using standard SPI pins

void setup() {
  Serial.begin(38400);
  long unsigned debug_start = millis ();
  while (!Serial && ((millis () - debug_start) <= 5000)) ;
  Serial.println("Setup");
  tft.begin(20000000);
  for (uint8_t reg = 0; reg < REG_DUMP_CNT; reg++) {
    reg_values[reg] = tft.lcdRegDataRead(reg);
  }

  pinMode(BACKLITE, OUTPUT);
  digitalWrite(BACKLITE, HIGH);
  tft.backlight(true);
  tft.graphicMode(true);
  Serial.printf("Before W: %d H: %d\n", tft.width(), tft.height());
  tft.fillScreen(LIGHTYELLOW);
  drawTestScreen();
  wait_for_keyboard();  // see if all yellow

  tft.Rotate();
  Serial.printf("After W: %d H: %d\n", tft.width(), tft.height());
  tft.fillScreen(YELLOW);
  wait_for_keyboard();  // see if all yellow
  drawTestScreen();
  //tft.textRotate(false);
  Serial.printf("MACR and End: %x\n", tft.lcdRegDataRead(RA8876_MACR));
}

void drawTestScreen() {
  tft.fillRect(0, 0, 50, 50, RED);
  tft.fillRect(tft.width() - 50, 0, 50, 50, GREEN);
  tft.fillRect(tft.width() - 50, tft.height() - 50 , 50, 50, BLUE);
  tft.fillRect(0, tft.height() - 50 , 50, 50, ORCHID);
  tft.drawLine(0, 0, tft.width(), tft.height(), WHITE);
  tft.drawLine(0, tft.height(), tft.width(), 0, BLACK);

  Serial.print("LCD Register dump:");
  for (uint8_t reg = 0; reg < REG_DUMP_CNT; reg++) {
    uint8_t r_value = tft.lcdRegDataRead(reg);
    if ((reg & 0xf) == 0) Serial.printf("\n%02x -", reg);
    Serial.printf(" %c%02x",
                  (r_value == reg_values[reg]) ? ' ' : '*',
                  r_value);
    reg_values[reg] = r_value;
  }
  Serial.print("\n");
}

void loop() {
  // put your main code here, to run repeatedly:

}
void wait_for_keyboard() {
  Serial.println("Wait for any key to continue");
  while (Serial.read() == -1);
  while (Serial.read() != -1);
}

I Tried a different value for Reg 2 to see if that would make difference. I could not tell from the email you received which of the orientations was not possible and if that was only the text or at all?
I read in the registers right after the tft.begin(). I then at the end of drawing the test page, read through them again and dumped the contents, comparing what I had received before and putting * next to ones that changes.

So far now progress, less hair and closer to punt :D
Code:
Setup

Before W: 1024 H: 600
LCD Register dump:
00 -  d6  82  00  00 *10  06  27  04  2f  04  2f  00 *15  00  00  00
10 -  04  05  c0  c0  7f  00  13  00  13  07  57  02  16  00  0b  09
20 -  00  00  00  00  00  04  00  00  00  00  00  00  00  00  00  00
30 -  00  00  00  00  00  00  00  00  00  00  00  00  05  14  08  0f
40 -  00  02  2c  01  ff  00  ff  ff  ff  ff  ff  ff  ff  ff  ff  ff
50 -  00  00  00  00  00  04  00  00  00  00  00  04  58  02  01  00
60 -  00  00  00  00  00  00  00  00  00  00 *58 *02  00  04 *00 *00
Wait for any key to continue

0
100
100
Rotate: After Origins
Rotate: After Saves

After W: 600 H: 1024
Wait for any key to continue

LCD Register dump:
00 -  d6  82 *04  00  10  06  27  04  2f  04  2f  00  15  00  00  00
10 -  04  05  c0  c0  7f  00  13  00  13  07  57  02  16  00  0b  09
20 -  00  00  00  00 *58 *02  00  00  00  00  00  00  00  00  00  00
30 -  00  00  00  00  00  00  00  00  00  00  00  00  05  14  08  0f
40 -  00  02  2c  01  ff  00  ff  ff  ff  ff  ff  ff  ff  ff  ff  ff
50 -  00  00  00  00 *58 *02  00  00  00  00 *58 *02 *00 *04  01  00
60 -  00  00  00  00  00  00  00  00  00  00 *00 *04 *58 *02  00  00
MACR and End: 4
 
What were you expecting this code to do?
Code:
  tft.Rotate();

I'm coming from the RA8875 end of things. I believe you mostly work with other displays? The RA8875 doesn't rotate what's already on the screen. It just sets a few variables so that anything that you draw from that point forwards will be rotated. So my code usually sets a rotation early in setup and does a clear-screen right after that.

I think the rotate-180 does rotate what's on the screen as what it's doing internally is telling the RA8875 to read out its frambuffer in the opposite direction when it's actually driving the pixels through the 40-pin LCD ribbon. But the RA8876 doesn't even have that option.

BTE has two use cases. First it can copy any area of memory to any other. That's useful if you are writing a dashboard display and you want the speedometer numbers 200 pixels tall. There's no font that big and even if there was, it would be slow. You (slowly) write characters 0-9 into an area of memory that's not displayed and then BTE can copy the digits to the visible screen very quickly. The second use case is moving data from the Teensy to the RA8875. For example, drawing a BMP image or the initial load of the characters 0-9.

In the first case, you don't rotate with BTE. The digits stay in the same orientation as you wrote them. Unless this is a handheld tablet with an orientation sensor so the user can rotate to portrait at any time? In the second case, you probably do need to rotate a pre-existing BMP image into the actual orientation that you programmed in setup(). The RA8876 datasheet on page 53 says register 0x02 can do 4 options, two of which are flipped horizontally. So that leaves two useful orientations: original and rotate-left. Register 0x12 adds an extra flip, so you can do rotate-180. But there's no combination that will do rotate-right.

It seems like maybe the same operations get used for text: there's only a rotate-left option for individual characters and (even worse) the built-in cursor advance will only advance to the right. Maybe that makes more sense if you're writing Chinese characters to the screen? It seems well-endowed with options to control double-wide Chinese characters.
 
What were you expecting this code to do?


I'm coming from the RA8875 end of things. I believe you mostly work with other displays? The RA8875 doesn't rotate what's already on the screen. It just sets a few variables so that anything that you draw from that point forwards will be rotated. So my code usually sets a rotation early in setup and does a clear-screen right after that.

I think the rotate-180 does rotate what's on the screen as what it's doing internally is telling the RA8875 to read out its frambuffer in the opposite direction when it's actually driving the pixels through the 40-pin LCD ribbon. But the RA8876 doesn't even have that option.

BTE has two use cases. First it can copy any area of memory to any other. That's useful if you are writing a dashboard display and you want the speedometer numbers 200 pixels tall. There's no font that big and even if there was, it would be slow. You (slowly) write characters 0-9 into an area of memory that's not displayed and then BTE can copy the digits to the visible screen very quickly. The second use case is moving data from the Teensy to the RA8875. For example, drawing a BMP image or the initial load of the characters 0-9.

In the first case, you don't rotate with BTE. The digits stay in the same orientation as you wrote them. Unless this is a handheld tablet with an orientation sensor so the user can rotate to portrait at any time? In the second case, you probably do need to rotate a pre-existing BMP image into the actual orientation that you programmed in setup(). The RA8876 datasheet on page 53 says register 0x02 can do 4 options, two of which are flipped horizontally. So that leaves two useful orientations: original and rotate-left. Register 0x12 adds an extra flip, so you can do rotate-180. But there's no combination that will do rotate-right.

It seems like maybe the same operations get used for text: there's only a rotate-left option for individual characters and (even worse) the built-in cursor advance will only advance to the right. Maybe that makes more sense if you're writing Chinese characters to the screen? It seems well-endowed with options to control double-wide Chinese characters.

A few points before getting into what tft.Rotate() is suppose to do and how its implemented.

All displays that we used do exactly what you described for the RA8875. Anything after setting Rotation is drawn in the with the new Rotation (0, 90, 180, 270). With the RA8876 the only rotation that you can not implement is Rotation to 270degs.

For the RA8876 using Register 0x02h and Register 0x12h you should be able to set the Rotation to 0, 90 (ccw) and 180degs. At least that is my understanding based on reading the Manual pages 52 to 57. So you should be able clear screen, set the screen Rotation to 90 degs CCW, and then do what you would normally do with the display, i.e. putpicture, drawgraphics etc.

Now for the tft.Rotate() function call. That is only a test function to rotate the screen 90degs CCW by changing the DPCR and MACR registers. In addition I extracted some other functions from the RA8876_API from RAIO to assist in that instead of changing the registers each time:
Code:
	//rotation functions
	void MemWrite_Left_Right_Top_Down(void);
	void MemWrite_Right_Left_Top_Down(void);
	void MemWrite_Top_Down_Left_Right(void);
	void MemWrite_Down_Top_Left_Right(void);
	void VSCAN_T_to_B(void);
	void VSCAN_B_to_T(void);

The memory write functions change the orientation for MACR (0x02h) and VSCAN basically changes direction for VDIR in DPCR (0x12h). So the function serves a couple of purposes:
1. Changes all the initializations for the screen orientation that is in the initialization:
Code:
	_width = 600;
	_height = 1024;
	SCREEN_WIDTH = _width;
	SCREEN_HEIGHT = _height;
	
	HDW = _width;
	VDH = _height;
		
	rightmarg =  (uint8_t)(_width / (_FNTwidth  * _scaleX));
	bottommarg = (uint8_t)(_height / (_FNTheight * _scaleY));
	_scrollXL = 0;
	_scrollXR = _width;
	_scrollYT = 0;
	_scrollYB = _height;
	_cursorX = _scrollXL;
	_cursorY = _scrollYT;
	CharPosX = _scrollXL;
	CharPosY = _scrollYT;
	_activeWindowXL = 0;
	_activeWindowXR = _width;
	_activeWindowYT = 0;
	_activeWindowYB = _height;
	
	// Position text cursor to default
	setTextCursor(_scrollXL, _scrollYT);
	// Setup Text Cursor
	cursorInit();
	// Set Margins to default settings
	setTMargins(0, 0, 0, 0); // Left Side, Top Side, Right Side, Bottom Side

	// Set graphic mouse cursor to center of screen
	gcursorxy(width() / 2, height() / 2);
	
  Serial.printf("%d, %d\n", width(), height());
  
	setClipRect();
	setOrigin();
	setTextSize(1, 1);

2. Then changes MACR/DPCR combo to Rotate 90CCW and resets the display windows:
Code:
	graphicMode(true);
	VSCAN_T_to_B();
	MemWrite_Down_Top_Left_Right();
	//MemWrite_Right_Left_Top_Down();
    Serial.printf("%d, %d\n", width(), height());
	
  	displayWindowStartXY(0,0);
	activeWindowXY(0,0);
        activeWindowWH(_width,_height);
	
	setPixelCursor(0,0);
	
	//lcdRegWrite(0x04, true);
	LCD_CmdWrite(0x04);

You might ask where I got this from - I got it direct from Raio for basically implementing what you see on Pages 52-57. Posted here for reference:
Regarding your question,
(1)
Your method of use is correct, to remind you, after turning, the setting value of Active_Window should be changed accordingly.
You can refer to the following example:

Code:
 switch(i)
 {
 case 1:
  VSCAN_T_to_B();
  
  MemWrite_Left_Right_Top_Down();
  //MemWrite_Right_Left_Top_Down();
  //MemWrite_Top_Down_Left_Right();
  //MemWrite_Down_Top_Left_Right();
 
 Main_Window_Start_XY(0,0);
 Active_Window_XY(0,0);
 Active_Window_WH(1024,768);
 Goto_Pixel_XY(0,0);
 
  LCD_CmdWrite(0x04);
  sd_showpic_16M_bin(1024,768,"Main_24.bin"); // write a 1024x768 picture.
  delay_ms(1000);
 break;
 
 case 2:
  VSCAN_T_to_B();
 
  //MemWrite_Left_Right_Top_Down();
  MemWrite_Right_Left_Top_Down();
  //MemWrite_Top_Down_Left_Right();
  //MemWrite_Down_Top_Left_Right();
 
 Main_Window_Start_XY(0,0);
 Active_Window_XY(0,0);
 Active_Window_WH(1024,768);
 Goto_Pixel_XY(0,0);
 
  LCD_CmdWrite(0x04);
  sd_showpic_16M_bin(1024,768,"Main_24.bin"); // write a 1024x768 picture.
  delay_ms(1000);
 break;
 
 case 3:
  VSCAN_T_to_B();
//  Canvas_image_width(768);
//  Main_Image_Width(768);
  //MemWrite_Left_Right_Top_Down();
  //MemWrite_Right_Left_Top_Down();
  MemWrite_Top_Down_Left_Right();
  //MemWrite_Down_Top_Left_Right();
 
 Main_Window_Start_XY(0,0);
 Active_Window_XY(0,0);
 Active_Window_WH(768,1024);
 Goto_Pixel_XY(0,0);
 
  LCD_CmdWrite(0x04);
  sd_showpic_16M_bin(1024,768,"Main_24.bin"); // write a 1024x768 picture.
  delay_ms(1000);
 break;
 
 case 4:
  VSCAN_T_to_B();
 
  //MemWrite_Left_Right_Top_Down();
  //MemWrite_Right_Left_Top_Down();
  //MemWrite_Top_Down_Left_Right();
  MemWrite_Down_Top_Left_Right();
 
 Main_Window_Start_XY(0,0);
 Active_Window_XY(0,0);
 Active_Window_WH(768,1024);
 Goto_Pixel_XY(0,0);
 
  LCD_CmdWrite(0x04);
  sd_showpic_16M_bin(1024,768,"Main_24.bin"); // write a 1024x768 picture.
  delay_ms(1000);
 break;
 
 case 5:
  VSCAN_B_to_T();
  
  MemWrite_Left_Right_Top_Down();
  //MemWrite_Right_Left_Top_Down();
  //MemWrite_Top_Down_Left_Right();
  //MemWrite_Down_Top_Left_Right();
 
 Main_Window_Start_XY(0,0);
 Active_Window_XY(0,0);
 Active_Window_WH(1024,768);
 Goto_Pixel_XY(0,0);
 
  LCD_CmdWrite(0x04);
  sd_showpic_16M_bin(1024,768,"Main_24.bin"); // write a 1024x768 picture.
  delay_ms(1000);
 break;
 
 case 6:
  VSCAN_B_to_T();
 
  //MemWrite_Left_Right_Top_Down();
  MemWrite_Right_Left_Top_Down();
  //MemWrite_Top_Down_Left_Right();
  //MemWrite_Down_Top_Left_Right();
 
 Main_Window_Start_XY(0,0);
 Active_Window_XY(0,0);
 Active_Window_WH(1024,768);
 Goto_Pixel_XY(0,0);
 
  LCD_CmdWrite(0x04);
  sd_showpic_16M_bin(1024,768,"Main_24.bin"); // write a 1024x768 picture.
  delay_ms(1000);
 break;
 
 case 7:
  VSCAN_B_to_T();
  
  //MemWrite_Left_Right_Top_Down();
  //MemWrite_Right_Left_Top_Down();
  MemWrite_Top_Down_Left_Right();
  //MemWrite_Down_Top_Left_Right();
 
 Main_Window_Start_XY(0,0);
 Active_Window_XY(0,0);
 Active_Window_WH(768,1024);
 Goto_Pixel_XY(0,0);
 
  LCD_CmdWrite(0x04);
  sd_showpic_16M_bin(1024,768,"Main_24.bin"); // write a 1024x768 picture.
  delay_ms(1000);
 break;
 
 case 8:
  VSCAN_B_to_T();
 
  //MemWrite_Left_Right_Top_Down();
  //MemWrite_Right_Left_Top_Down();
  //MemWrite_Top_Down_Left_Right();
  MemWrite_Down_Top_Left_Right();
 
 Main_Window_Start_XY(0,0);
 Active_Window_XY(0,0);
 Active_Window_WH(768,1024);
 Goto_Pixel_XY(0,0);
 
  LCD_CmdWrite(0x04);
  sd_showpic_16M_bin(1024,768,"Main_24.bin"); // write a 1024x768 picture.
  delay_ms(1000);
 break;
  }

(2)
One thing to remind you, if you use the text function of RA8876 when you rotate 90 degrees counterclockwise, please refer to datasheet[14.4 Rotate 90 Degree’s Characters], set as follows.
Code:
 Font_90_degree();
 
// VSCAN_T_to_B();
 VSCAN_B_to_T();
 
// MemWrite_Left_Right_Top_Down();
// MemWrite_Right_Left_Top_Down();
 MemWrite_Top_Down_Left_Right();
// MemWrite_Down_Top_Left_Right();
(3)
There are several hypothetical situations below, please refer to them.

If you use 90 degrees clockwise, you can only choose RA8875.
If you want to turn the LCD horizontally 90 degrees (90 degrees counterclockwise), RA8875 or RA8876 can be achieved.
If your future LCD resolution may be greater than 800x480, it is recommended to use RA8876.
 
@mjs513 - I am playing around with random tries. Ran into a few issues.

Thought I would see how bad it would be to have the rotate function call back to the RA8876Initialize function with a couple of parameters...

Wondered if maybe the 90 degree rotation might need the reg 12 change so tried it... Found that other functions like displayOn or the like blasted over it... So changed that function to preserve that bit...

Anyway got the RED box to to show up in different corner so at least showing some difference. Still not right...

But if you wish to take a look at it. I pushed up the branch GIFW_ROT

But now need to do some other stuff for awhile
 
@mjs513 - I am playing around with random tries. Ran into a few issues.

Thought I would see how bad it would be to have the rotate function call back to the RA8876Initialize function with a couple of parameters...

Wondered if maybe the 90 degree rotation might need the reg 12 change so tried it... Found that other functions like displayOn or the like blasted over it... So changed that function to preserve that bit...

Anyway got the RED box to to show up in different corner so at least showing some difference. Still not right...

But if you wish to take a look at it. I pushed up the branch GIFW_ROT

But now need to do some other stuff for awhile

Think I have been at this too long. Looks like you have VDIR going from Bottom to top. When I looked at your call back to the initialization code all that is happening is you are going from bottom to top instead of top to bottom. Still not rotating ccw90deg once I fix that. Also noticed you never changed SCREEN_HEIGHT or Width? or did I miss something
 
I know what you mean about looking at it too long. I keep trying different things and going around in circles. a

I tried to setup _width = SCREEN_WIDTH... before calling the R8876Initiialize function. Looks like I missed a few.

Also I think there are some helper functions that need helping..
 
Good Morning,

I know I must be missing something obvious in the rotations not working...
As mentioned in other communications, and above, I hacked in dumping of the registers at the end of the operations. I may add some more like when we call the fillRect()...

Again if I look at the stuff I dumped in previous posting I have:
Code:
call vscan_b_to_t 80 88
After W: 600 H: 1024
Wait for any key to continue

LCD Register dump:
00 -  d6  82 [COLOR="#FF0000"]*06[/COLOR]  00  10  06  27  04  2f  04  2f  00  15  00  00  00
10 -  04  05 [COLOR="#FF0000"]*c8 [/COLOR] c0  7f  00  13  00  13  07  57  02  16  00  0b  09
20 -  00  00  00  00 [COLOR="#006400"]*58 *02[/COLOR]  00  00  00  00  00  00  00  00  00  00
30 -  00  00  00  00  00  00  00  00  00  00  00  00  05  14  08  0f
40 - *2c *01 *00 *02  ff  00  ff  ff  ff  ff  ff  ff  ff  ff  ff  ff
50 -  00  00  00  00[COLOR="#0000CD"] *58 *02[/COLOR]  00  00  00  00 [COLOR="#FF8C00"]*58 *02 *00 *04[/COLOR]  01  00
60 -  00  00  00  00  00  00  00  00  00  00 *00 *04 *58 *02  00  00
MACR and End: 6
The red parts are showing the two mode registers which has the MACR setup to rotation 3 setting and the VScan is setup from B to T...
So some of the code I touched to preserve those appear to be working... But display still wrong!

Some of the things I would expect also to change is from logical:

displayImageWidth(_width) - Should set MIW0 and MIW1(0x24-5) 0x258=600

canvasImageWidth(_width) - RA8876_CVS_IMWTH0/1 (0x54-55) *58 *02 = 600

activeWindowWH(_width,_height); () 0x258=600 0x400=1024

So far those look reasonable... Again must be missing something obvious.

EDIT: Should check the other changed values and/or dump more registers.

The changes in the range: 0x40-43 are Graphic_Cursor_XY I think... So probably nothing.
The changes in 0x6a-6d: RA8876_DLVSR0... Look like settings we do to draw things:
And some after I stopped dumping, I think are more of the same.
 
@KurtE
I guess one major thing is that for a CCW rotation of 90degs VScan should be T_to_B not B_T per page 55 of the Manual. Also, the per RAIO the active window should be changed from 1024,600 to 600,1024. You know me and registers so the rest I am going to have to mull on.

In the latest round of questions the provided a rough out line of a test sketch which is basically an example from their Arduino Due RA8876_lite which I modified for our implementation.

View attachment RA8876Demo1.zip

The one thing I noticed is that they are using drawSquareFill to change the screen color whereas for it work correctly with our implementation I had to change that to fillScreen(color). The other thing I notice was that when using
Code:
   tft.lcdDataWrite16bbp(COLOR65K_YELLOW);//RGB565 16bpp data
to color a box created (this works by the way):
Code:
  tft.putPicture_16bpp(50,50,128,128);
The color is way off. When telling it to fill the frame with yellow its showing magenta on the screen. Same with the colors used for to draw
Code:
  tft.putPicture_16bppData16(50+128+128,50+128+128,128,128,pic16bpp_word);

Going to try something strange. But going to take a while to do.
they don't match what's expected.
 
@mjs513 - T_to_B ... Yep I had it that way for a couple of days... Thought I would try it the other way just to see if anything actually changed...

Active window as I mentioned is 600x1024.

Maybe the drawSquareFill may give some hints:
Code:
void RA8876_t3::drawSquareFill(ru16 x0, ru16 y0, ru16 x1, ru16 y1, ru16 color)
{
//  Serial.printf("DSF:(%d %d)(%d %d) %x\n", x0, y0, x1, y1, color);	
  check2dBusy();
  graphicMode(true);
  foreGroundColor16bpp(color);
  lcdRegDataWrite(RA8876_DLHSR0,x0, false);//68h
  lcdRegDataWrite(RA8876_DLHSR1,x0>>8, false);//69h
  lcdRegDataWrite(RA8876_DLVSR0,y0, false);//6ah
  lcdRegDataWrite(RA8876_DLVSR1,y0>>8, false);//6bh
  lcdRegDataWrite(RA8876_DLHER0,x1, false);//6ch
  lcdRegDataWrite(RA8876_DLHER1,x1>>8, false);//6dh
  lcdRegDataWrite(RA8876_DLVER0,y1, false);//6eh
  lcdRegDataWrite(RA8876_DLVER1,y1>>8, false);//6fh     
  lcdRegDataWrite(RA8876_DCR1,RA8876_DRAW_SQUARE_FILL, true);//76h,0xE0  
}

But then again: fillScreen calls this function?
Code:
void RA8876_t3::fillScreen(uint16_t color) {
	drawSquareFill(_scrollXL, _scrollYT, _scrollXR, _scrollYB, color);
	check2dBusy();  //must wait for fill to finish before setting foreground color
	textColor(_TXTForeColor,_TXTBackColor);
	setTextCursor(_scrollXL,_scrollYT);
}
I put code in fillScreen to print out the 5 parameters it passed to drwSquareFill and also changed the T to B passed in to the init...


Code:
Setup

Fillscreen: 0 0 1024 600 10
Fillscreen: 0 0 1024 600 10
Fillscreen: 0 0 1024 600 10
Fillscreen: 0 0 1024 600 10
Fillscreen: 0 0 1024 600 10
Fillscreen: 0 0 1024 600 10
Fillscreen: 0 0 1024 600 10
Fillscreen: 0 0 1024 600 10
Fillscreen: 0 0 1024 600 10
Before W: 1024 H: 600
Fillscreen: 0 0 1024 600 fff0
LCD Register dump:
00 -  d6  82  00  00 *10  06  27  04  2f  04  2f  00 *15  00  00  00
10 -  04  05  c0  c0  7f  00  13  00  13  07  57  02  16  00  0b  09
20 -  00  00  00  00  00  04  00  00  00  00  00  00  00  00  00  00
30 -  00  00  00  00  00  00  00  00  00  00  00  00  05  14  08  0f
40 -  00  02  2c  01  ff  00  ff  ff  ff  ff  ff  ff  ff  ff  ff  ff
50 -  00  00  00  00  00  04  00  00  00  00  00  04  58  02  01  00
60 -  00  00  00  00  00  00  00  00  00  00 *58 *02  00  04 *00 *00
Wait for any key to continue

Fillscreen: 0 0 600 1024 10
Fillscreen: 0 0 600 1024 10
Fillscreen: 0 0 600 1024 10
Fillscreen: 0 0 600 1024 10
Fillscreen: 0 0 600 1024 10
Fillscreen: 0 0 600 1024 10
Fillscreen: 0 0 600 1024 10
Fillscreen: 0 0 600 1024 10
Fillscreen: 0 0 600 1024 10
After W: 600 H: 1024
Fillscreen: 0 0 600 1024 ffe0
Wait for any key to continue

LCD Register dump:
00 -  d6  82 *06  00  10  06  27  04  2f  04  2f  00  15  00  00  00
10 -  04  05  c0  c0  7f  00  13  00  13  07  57  02  16  00  0b  09
20 -  00  00  00  00 *58 *02  00  00  00  00  00  00  00  00  00  00
30 -  00  00  00  00  00  00  00  00  00  00  00  00  05  14  08  0f
40 - *2c *01 *00 *02  ff  00  ff  ff  ff  ff  ff  ff  ff  ff  ff  ff
50 -  00  00  00  00 *58 *02  00  00  00  00 *58 *02 *00 *04  01  00
60 -  00  00  00  00  00  00  00  00  00  00 *00 *04 *58 *02  00  00
MACR and End: 6
SO pulling out hair
 
Forgot to mention: I took the modified sketch you posted/sent and ran it. Modified to turn on backlight

Then modified to call Rotate(). And what is interesting is:
IMG_1135.jpg
Th BAC image did not rotate, but the Cylinder image did.
 
@KurtE
Actually the cylinder looks like it rotated but the square and letter images did not. Still looks strange.

You might want to give the attached a try :) rotation does work its something overwriting in our library. The sketch is basically the Due library with slight mods.

View attachment RA8876_Lite_Graphic.zip
 
BUT!!!
Color is wrong!

AND!!!

This is NOT changing the orientation and positioning on the page, it is only changing what the image does...
That is both their 0 degrees and 90 degrees the do:
Code:
ra8876lite.putPicture_16bpp(50,50,128,128);
  for(i=0;i<16384;i++)
  {
   ra8876lite.lcdDataWrite16bbp(COLOR65K_YELLOW);//RGB565 16bpp data
  }

And the pinkish square shows up in the same corner of the display! Dito the BAC draws at the same location. Only which pixel is which within that image changes!
 
BUT:
Yep - mentioned that in post #194 and not sure why - something with the SPI.transfer???? Same in the current library implementation.

AND:
Agreed but at least it rotates :) in the earlier post from RAIO they suggested using:
Code:
Main_Window_Start_XY(0,0);
 Active_Window_XY(0,0);
 Active_Window_WH(768,1024);
 Goto_Pixel_XY(0,0);
 
  LCD_CmdWrite(0x04);
but haven't tried playing around with that implementation yet. Never got my second cup of coffee :) so trying to have it now.
 
Back
Top