mjs513
Senior Member+
Thanks for checkingLooks like it runs on my MMOD with ILI9488
Thanks for checkingLooks like it runs on my MMOD with ILI9488
Right now this is all on internal buffers on the T4.1 and Micromod. The T41 is using EXTRAM running at 132mhz with a ILI9488 on SPI@mjs513 are you using SDRAM buffers or internal RAM buffers for the PXP source and destination?
Thanks. Been at it again. Since its the set of functions I am using all the time I just created a new one that I am testing. This way don't have to keep copying and pasting codeLooks great!
PXP_ps_output(tft.width(), tft.height(), /* Display width and height */
FRAME_WIDTH, FRAME_HEIGHT, /* Image width and height */
s_fb, PXP_Y8, 1, /* Input buffer configuration */
d_fb, PXP_RGB565, 2, /* Output buffer configuration */
3, false, 1.5, /* Rotation, flip, scaling */
&outputWidth, &outputHeight); /* Frame Out size for drawing */
Just posted some info on the SDRAM thread.@mjs513 are you using SDRAM buffers or internal RAM buffers for the PXP source and destination?
void PXP_ps_output(uint16_t disp_width, uint16_t disp_height, uint16_t image_width, uint16_t image_height,
void* buf_in, uint8_t format_in, uint8_t bpp_in, uint8_t byte_swap_in,
void* buf_out, uint8_t format_out, uint8_t bpp_out, uint8_t byte_swap_out,
uint8_t rotation, bool flip, float scaling,
uint16_t* scr_width, uint16_t* scr_height);
Using flexio_teensy_mm image from @Rezo
=================================================================
s_fb: RAM/d_fb: DMAMEM
Rotation 0:
Capture time (millis): 128, PXP time(micros) : 114, Display time: 205
Rotation 1:
Capture time (millis): 127, PXP time(micros) : 114, Display time: 246
Rotation 2:
Capture time (millis): 128, PXP time(micros) : 113, Display time: 205
Rotation 3:
Capture time (millis): 128, PXP time(micros) : 114, Display time: 246
Rotation 0 w/flip:
Capture time (millis): 128, PXP time(micros) : 113, Display time: 205
Rotation 2 w/scaling:
Capture time (millis): 127, PXP time(micros) : 102, Display time: 178
Rotation 3 w/Scaling:
Capture time (millis): 127, PXP time(micros) : 102, Display time: 178
==================================================================
sdram/sdram
Rotation 0:
Capture time (millis): 127, PXP time(micros) : 258, Display time: 205
Rotation 1:
Capture time (millis): 127, PXP time(micros) : 261, Display time: 246
Rotation 2:
Capture time (millis): 128, PXP time(micros) : 258, Display time: 205
Rotation 3:
Capture time (millis): 127, PXP time(micros) : 261, Display time: 247
Rotation 0 w/flip:
Capture time (millis): 127, PXP time(micros) : 257, Display time: 205
Rotation 2 w/scaling:
Capture time (millis): 127, PXP time(micros) : 352, Display time: 178
Rotation 3 w/Scaling:
Capture time (millis): 127, PXP time(micros) : 358, Display time: 178
Hi I tried the new sketch with the HM0360 reading qvga on MMOD and doing the conversion to RGB and rotation. It workedOk pushed the changes mentioned up to my fork of lib and updated the examples if anyone wants to try it
GitHub - mjs513/T4_PXP at pxp_t4_mods
Teensy 4 Pixel Pipeline. Contribute to mjs513/T4_PXP development by creating an account on GitHub.github.com
The basic calling function is now (included the option for byte swap):
Code:void PXP_ps_output(uint16_t disp_width, uint16_t disp_height, uint16_t image_width, uint16_t image_height, void* buf_in, uint8_t format_in, uint8_t bpp_in, uint8_t byte_swap_in, void* buf_out, uint8_t format_out, uint8_t bpp_out, uint8_t byte_swap_out, uint8_t rotation, bool flip, float scaling, uint16_t* scr_width, uint16_t* scr_height);
Think its pretty much self-explanatory except maybe the scr_width and scr_height. Basically thats the final image width and height after rotation/scaling effects applied. They are returned values from PXP.
I tried changing to VGA and as I sort of expected, not enough memory...
Wondering if I can setup the camera to support the size: FRAMESIZE_480X320,
And if we have enough memory for that...
uint8_t s_fb[(640) * 480] __attribute__((aligned(64)));
DMAMEM uint16_t d_fb[(480) * 320] __attribute__ ((aligned (64)));
Not DMA
Finished reading frame
Capture time (millis): 210, PXP time(micros) : 204, Display time: 232
PXP rotation 2....
$$ImageSensor::readFrameFlexIO(0x200056c0, 307200, 0x0, 0, 0, 0) 307200
Not DMA
Finished reading frame
Capture time (millis): 178, PXP time(micros) : 204, Display time: 205
PXP rotation 1....
$$ImageSensor::readFrameFlexIO(0x200056c0, 307200, 0x0, 0, 0, 0) 307200
Not DMA
Finished reading frame
Capture time (millis): 282, PXP time(micros) : 204, Display time: 232
PXP rotation 1....
$$ImageSensor::readFrameFlexIO(0x200056c0, 307200, 0x0, 0, 0, 0) 307200
Not DMA
Finished reading frame
Capture time (millis): 187, PXP time(micros) : 205, Display time: 232
PXP rotation 1....
$$ImageSensor::readFrameFlexIO(0x200056c0, 307200, 0x0, 0, 0, 0) 307200
Not DMA
Finished reading frame
Capture time (millis): 207, PXP time(micros) : 205, Display time: 232
PXP rotation 1....
$$ImageSensor::readFrameFlexIO(0x200056c0, 307200, 0x0, 0, 0, 0) 307200
Not DMA
Finished reading frame
Capture time (millis): 149, PXP time(micros) : 205, Display time: 232
are the Miilis Micros labels correct? This would be 1,000 times faster?PXP takes almost as much time as either the capture or the display
Yep Milli’s and micros are correct. Display is in millisare the Miilis Micros labels correct? This would be 1,000 times faster?
PXP_ps_output(uint16_t disp_width, uint16_t disp_height, uint16_t image_width, uint16_t image_height,
void* buf_in, uint8_t format_in, uint8_t bpp_in, uint8_t byte_swap_in,
void* buf_out, uint8_t format_out, uint8_t bpp_out, uint8_t byte_swap_out,
uint8_t rotation, bool flip, float scaling,
uint16_t* scr_width, uint16_t* scr_height)
inline void do_pxp_conversion(uint16_t &outputWidth, uint16_t &outputHeight) {
#if defined(CAMERA_USES_MONO_PALETTE)
PXP_ps_output(tft.width(), tft.height(), /* Display width and height */
camera.width(), camera.height(), /* Image width and height */
camera_buffer, PXP_Y8, 1, 0, /* Input buffer configuration */
screen_buffer, PXP_RGB565, 2, 0, /* Output buffer configuration */
TFT_ROTATION, 0, 480.0 / 320.0, /* Rotation, flip, scaling */
&outputWidth, &outputHeight); /* Frame Out size for drawing */
#else
PXP_ps_output(tft.width(), tft.height(), /* Display width and height */
camera.width(), camera.height(), /* Image width and height */
camera_buffer, PXP_RGB565, 2, 0, /* Input buffer configuration */
screen_buffer, PXP_RGB565, 2, 0, /* Output buffer configuration */
TFT_ROTATION, true, 0.0, /* Rotation, flip, scaling */
&outputWidth, &outputHeight); /* Frame Out size for drawing */
#endif
}
typedef struct
{
volatile uint32_t CTRL;
volatile uint32_t STAT;
volatile uint32_t OUT_CTRL;
volatile void* OUT_BUF;
volatile void* OUT_BUF2;
volatile uint32_t OUT_PITCH;
volatile uint32_t OUT_LRC;
volatile uint32_t OUT_PS_ULC;
volatile uint32_t OUT_PS_LRC;
volatile uint32_t OUT_AS_ULC;
volatile uint32_t OUT_AS_LRC;
volatile uint32_t PS_CTRL;
volatile void* PS_BUF;
volatile void* PS_UBUF;
volatile void* PS_VBUF;
volatile uint32_t PS_PITCH;
volatile uint32_t PS_BACKGROUND;
volatile uint32_t PS_SCALE;
volatile uint32_t PS_OFFSET;
volatile uint32_t PS_CLRKEYLOW;
volatile uint32_t PS_CLRKEYHIGH;
volatile uint32_t AS_CTRL;
volatile void* AS_BUF;
volatile uint32_t AS_PITCH;
volatile uint32_t AS_CLRKEYLOW;
volatile uint32_t AS_CLRKEYHIGH;
volatile uint32_t CSC1_COEF0;
volatile uint32_t CSC1_COEF1;
volatile uint32_t CSC1_COEF2;
volatile uint32_t POWER;
volatile uint32_t NEXT;
volatile uint32_t PORTER_DUFF_CTRL;
} IMXRT_NEXT_PXP_t;
#ifdef USE_T4_PXP
inline void do_pxp_conversion(uint16_t &outputWidth, uint16_t &outputHeight) {
static bool first_time = true;
if (!first_time) {
PXP_process();
return;
}
first_time = false;
#if defined(CAMERA_USES_MONO_PALETTE)
PXP_ps_output(tft.width(), tft.height(), /* Display width and height */
camera.width(), camera.height(), /* Image width and height */
camera_buffer, PXP_Y8, 1, 0, /* Input buffer configuration */
screen_buffer, PXP_RGB565, 2, 0, /* Output buffer configuration */
TFT_ROTATION, 0, 480.0 / 320.0, /* Rotation, flip, scaling */
&outputWidth, &outputHeight); /* Frame Out size for drawing */
#else
PXP_ps_output(tft.width(), tft.height(), /* Display width and height */
camera.width(), camera.height(), /* Image width and height */
camera_buffer, PXP_RGB565, 2, 0, /* Input buffer configuration */
screen_buffer, PXP_RGB565, 2, 0, /* Output buffer configuration */
TFT_ROTATION, true, 0.0, /* Rotation, flip, scaling */
&outputWidth, &outputHeight); /* Frame Out size for drawing */
#endif
}
#endif
Maybe sort of... That is I am not sure the proper way is to do what we are trying to do.And I think it is still working
bool camera_read_callback(void *pfb) {
digitalWriteFast(3, HIGH);
frame_count_camera++;
if (tft.asyncUpdateActive()) {
digitalWriteFast(3, LOW);
return true;
}
frame_count_tft++;
uint16_t outputWidth, outputHeight;
do_pxp_conversion(outputWidth, outputHeight);
tft.updateScreenAsync();
digitalWriteFast(1, HIGH);
digitalWriteFast(3, LOW);
return true;
}
The time for the actual PXP operation is:PXP rotation 1.... $$ImageSensor::readFrameFlexIO(0x200056c0, 307200, 0x0, 0, 0, 0) 307200 Not DMA Finished reading frame Capture time (millis): 187, PXP time(micros) : 205, Display time: 232
Rotation 1:
Capture time (millis): 128, PXP time(micros) : 1342, Display time: 246
I have pushed up fork/branch with it in it:@KurtE agree it should have an option to register a callback to the PXP ISR
If your IMXRT_NEXT_PXP_t structure definition is available to the user, that could be the structure used to set up the PXP. Initializing the PXP then becomes simple matter of setting the PXP_NEXT register with a pointer to your structure. If you want to keep a local copy of the structure, you can do that with a simple memcpy(). After that is done, you can use the internal structure inside the class.Personally, I don't really think I want to use a struct to initialize another struct....
That is almost all of the calls within the T4_PXP library are setup to fill in a structure:
// Save the PXP registers to the PXP_Next array passed as parameter.
// The input pointer should point to an array of 32 uint32_t elements.
void clPXP::SaveNext(uint32_t pxnptr[]) {
uint16_t i;
volatile uint32_t *pxptr = &PXP_CTRL; // set pointer to first register
uint32_t *nxptr = &pxnptr[0]; // set pointer to first saved value
for (i = 0; i < 29; i++) { // first 29 are at 16-byte intervals
*nxptr++ = *pxptr;
pxptr += 4; // skips ahead 16 bytes to next register
}
// the last three entries are differently spaced so use register definitions
*nxptr++ = PXP_POWER;
*nxptr++ = PXP_NEXT;
*nxptr = PXP_PORTER_DUFF_CTRL;
}
@mjs513 has played a lot more with this stuff than I have. I am still trying to understand some of the basics...I used that technique in my years-old OV7670 camera libraries:
CSI-Frame Capture IRQ -> Sets up and Starts PXP to convert YUV422 to RGB565 and shrink for ILI9341
PXP-End IRQ -> Sets up starts Async transfer to LCD
This sequence captured VGA frames in a circular buffer in EXTMEM to be used by the foreground loop and stored to SD card when requested. I found that having the CSI and PSP competing for access to EXTMEM caused lots of glitches in the data, so I had to stop the CSI while the PXP was running, which reduced the overall frame rate to about 5FPS.
Have you seen similar issues with FlexIO-based camera drivers? Hopefully, avoiding the use of EXTMEM and splitting the frame buffer between DTCM and DMAMEM avoids the conflict with PXP usage.