All fixed:
PXP_OUT_PS_LRC had to be set to ((479) << 16) | (319); (was 480, 320)
and
PXP_OUT_LRC has to be set to ((95) << 16) | (319); (was 96, 320)
void start_pxp(){
PXP_init();
Serial.printf("bwitdh: %d, bheight: %d\n", bwidth, bheight);
SetCorner(PXP_OUT_PS_ULC, 0, 0);
SetCorner(PXP_OUT_PS_LRC, (bwidth - 1), (bheight - 1));
PXP_input_buffer(s_fb, 2, bwidth, bheight);
PXP_input_format(PXP_RGB565);
PXP_output_buffer(d_fb, 2, bheight, bwidth);
PXP_output_format(PXP_RGB565);
}
void pxp_rotation(int r) {
if(!pxpStarted) {
Serial.println("You forgot to start PXP, use 's' to start.....");
} else {
capture_frame(false);
PXP_rotate(r);
PXP_process();
draw_frame();
}
}
void draw_frame() {
//arm_dcache_flush(d_fb, sizeof(d_fb)); // always flush cache after writing to DMAMEM variable that will be accessed by DMA
tft.writeRect(CENTER, CENTER, tft.width(), tft.height(), (uint16_t *)d_fb );
}
camera.useDMA(true);
camera.readFrame(s_fb , sizeof_s_fb);
arm_dcache_flush((uint16_t*)s_fb, sizeof_s_fb); // always flush cache after writing to DMAMEM variable that will be accessed by DMA
memset((uint8_t *)d_fb, 0, sizeof_d_fb);
PXP_rotate_position(1); //Rotation position, 1=input <------- added to the rotation on the input buffer
capture_frame(false);
PXP_rotate(r);
PXP_process();
draw_frame();
Not an expert on this by far - was torture just trying to get rotation semi working. I do know that you can set up the source input buffer as RG565 and then setup the out buffer to RGB888 and it should convert. No clue how to actually try it though and set up the out buffer for RGB888.For example with the ILI9488_t3 code, we typically store the pixels in 16 bit 565 format, but the SPI interface does not handle this, so we convert into a 24 bit 666 (or 888) format. We have code in place that when we write to the screen we convert each pixel.
Thanks for joining the fray here. Right now I am using QVGA with a ILI9341 so using 2 full size buffers:I had a very had time with the rotation. But eventually got it working using a frame sized destination buffer and two 1/10th source buffers - not a standard implementation at all.
With SDRAM can go full sized frame buffers and let it do its thing.
DMAMEM uint16_t s_fb[320*240] __attribute__ ((aligned (64)));
uint16_t d_fb[320*240] __attribute__ ((aligned (64)));
PXP_init();
Serial.printf("bwitdh: %d, bheight: %d\n", bwidth, bheight);
SetCorner(PXP_OUT_PS_ULC, 0, 0);
SetCorner(PXP_OUT_PS_LRC, (bwidth - 1), (bheight - 1));
PXP_input_buffer(s_fb, 2, bwidth, bheight);
PXP_input_format(PXP_RGB565);
PXP_output_buffer(d_fb, 2, bheight, bwidth);
PXP_output_format(PXP_RGB565);
So for the ILI9341 the lower is 320x240 or should it be 240x320??????? Note didn't help if I changed it, by that I mean still get a square of 240x240. Found that @mborgerson used a setCorner macro - lazy so am using it (SetCorner(reg, h, v) reg = (h<<16 | v))PXP_OUT_LRC:
This register contains the size, or lower right coordinate, of the output buffer NOT rotated. It is implied that the upper left coordinate of the output surface is always [0,0]. When rotating the framebuffer, the PXP will automatically swap the X/Y, or WIDTH/ HEIGHT, to accomodate the rotated size.
PXP_OUT_PS_ULC
This register contains the upper left coordinate of the Processed Surface in the output frame buffer (in pixels).
PXP_input_buffer(s_fb, 2, bwidth, bheight);
PXP_output_buffer(d_fb, 2, bheight, bwidth);
next_pxp.OUT_BUF = buf; <---------------------- assmuing ptr to buffer
next_pxp.OUT_PITCH = PXP_PITCH(bytesPerPixel * width); <--------------- bytes per output row????
next_pxp.OUT_LRC = PXP_XCOORD(width-1) | PXP_YCOORD(height-1); <--------------- just noticed this, so dont have to do in sketch......
//Call to make sure the last process is finished before using the buffer with a display
void PXP_finish();
Will give it a try - but question on lrc/ulc - do these change with rotation@mjs513 try copy the destination buffers content to a file in littleFS and convert it to a bitmap on your computer to make sure the issue is the PXP and not the lcd driver, or the interface between the two.
To me it looks like a rotation issue on the display driver (from my days writing the FlexIO 8080 library)
void pxp_rotation(int r) {
if(!pxpStarted) {
Serial.println("You forgot to start PXP, use 's' to start.....");
} else {
memset((uint8_t *)d_fb, 0, sizeof_d_fb);
PXP_rotate_position(0); //Rotation position, 1=input
capture_frame(false);
if(r == 0 || r == 2) {
PXP_output_clip(bheight-1, bwidth-1);
} else {
PXP_output_clip( bwidth-1, bheight-1);
}
PXP_rotate(r);
PXP_process();
draw_frame();
}
}
Have to swap the values for the OUT_LRC register - didn;t register (pardon the pun) that this was different than PXP_OUT_PS_LRC. PXP_OUT_LRC appears to set the display LRC, hence the need for:So what was it?![]()
if(r == 0 || r == 2) {
PXP_output_clip(bheight-1, bwidth-1);
} else {
PXP_output_clip( bwidth-1, bheight-1);
}
Thanks, will take a look.@KurtE the partial output buffers only work with the eLCDIF handshake.
The only way to use this on a non SDRAM Teensy is to use one screen size source buffer and two partial destination buffers
I was able to rotate a landscape frame generated by LVGL with this method on a MicroMod.
LVGL wrote into the full frame buffer, and I then while rotating into one destination buffer, would transfer into the other.
You might be able to do it with a smaller source buffer, but it will be very complex.
There is no full DMA service to write directly to SPI or read from SPI into the PXP.
The only advantage here is you can offload the tasks from the main core. So while reading into one destination buffer it rotates the other and then sends it off to the display and vice versa.
You can see the code I posted here - https://forum.pjrc.com/index.php?threads/t4-pixel-pipeline-library.64860/post-320150
The PXP can be very useful for some applications. A little over 3 years ago, I used it to manipulate images for a slide show app. The PXP made possible things like fade-in, fade-out, moving transitions, and Ken Burns effect (combination of translation and scaling). A search of the forum for "Slide Show" will find the post demonstrating the PXP-enabled effects as displayed on a PC host.The only real problem with on-screen rotation such as the ILI9341/9488 is that while we can rotate by changing the MADCTL register on the display, the actual pixels are still displayed in portrait mode, top to bottom (bottom being where the ribbon cable is), regardless of rotation settings. When optimizing for high frame rate, this causes visible tearing and cannot be avoided.
By rotating with the PXP before sending the data out to the display (keeping the MADCRL rotation at 0 degrees) you can avoid that tearing affect.
The real benefits of the PXP in my eyes are:
- Rotation of a buffer when using the eLCDIF
- 2D accelerations specifically for rotating objects, alpha blending and image scaling - mostly when using a GUI framework
- Color conversions
If it's none of the above, I don't see a good excuse to use it.
Thanks,The PXP can be very useful for some applications. A little over 3 years ago, I used it to manipulate images for a slide show app. The PXP made possible things like fade-in, fade-out, moving transitions, and Ken Burns effect (combination of translation and scaling). A search of the forum for "Slide Show" will find the post demonstrating the PXP-enabled effects as displayed on a PC host.
At some point it will be interesting to play with some of these more advanced features!This is an improved Slide Show display. The QVGA slide images and transitions were recorded with the Win10 screen recorder. The slide images and transitions were sent to the PC host application using the T4.1 Dual serial connection so a dedicated USB channel was available for the image data. At the same time, the slide show was sent to an ILI9341 display. Sending to both at the same time dis not seem to slow the display significantly. Ah, the wonders of well-written drivers using DMA!
Now that I'm not limited to the QVGA resolution of the ILI93341, I plan to replace the .BMP file with full VGA versions and see how long it takes to do the transitions and display with 4 times as many pixels.
#define PXP_OUT_PS_X(x) (((uint32_t)(((uint32_t)(x)) << 16)) & (0x3FFF0000U))
#define PXP_OUT_PS_Y(x) ((uint32_t)((uint32_t)(x)) & (0x3FFFU))
void PXP_SetOutputCorners(uint16_t ulc_x, uint16_t ulc_y, uint16_t lrc_x, uint16_t lrc_y)
{
next_pxp.OUT_PS_ULC = PXP_OUT_PS_Y(ulc_y) | PXP_OUT_PS_X(ulc_x);
next_pxp.OUT_PS_LRC= PXP_OUT_PS_Y(lrc_y) | PXP_OUT_PS_X(lrc_x);
}
void PXP_setScaling(uint16_t inputWidth, uint16_t inputHeight, uint16_t outputWidth, uint16_t outputHeight)
and
void PXP_GetScaleFactor(uint16_t inputDimension, uint16_t outputDimension, uint8_t *dec, uint32_t *scale)
which setScaling calls