Dear all,
I'm having difficulty getting a simple use of the IPU to work. If I understand it right, the IPU can allocate an input and output buffer (if none is specified by the user) and perform a simple colour space conversion on the input buffer contents.
Below is some very simple code that sets up the IPU to do CSC conversion on a fixed array of 0xFF values. (The 0xFF value is not relevant, the problem happens with any value.)
When I run this, most of the time the IPU does *not* perform the CSC. The output buffer before and after the IPU task contains values of zero. BUT - occasionally it *does* work and the output buffer contains repeated correct non-zero characters.
The IPU always returns a value of zero, meaning it always thinks it was successful.
Does anyone have ideas why this mostly fails but occasionally works?
Many thanks
/******************************************************************************************
**
** IPU test
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <mxc_ipu_hl_lib.h>
int
main(int argc, char **argv)
{
int ret, test, i;
unsigned char *ptr;
ipu_lib_handle_t handle;
ipu_lib_input_param_t input;
ipu_lib_output_param_t output;
unsigned int w = 720, h = 576;
// run the IPU test 10 times
for (test = 0; test < 10; test++)
{
// setup the IPU input
memset(&input, 0x00, sizeof(input));
input.width = w;
input.height = h;
input.fmt = IPU_PIX_FMT_UYVY;
input.motion_sel = HIGH_MOTION;
input.input_crop_win.pos.x = 0;
input.input_crop_win.pos.y = 0;
input.input_crop_win.win_w = w;
input.input_crop_win.win_h = h;
input.user_def_paddr[0] = NULL;// NULL means that a buffer will be allocated
// setup the IPU output
memset(&output, 0x00, sizeof(output));
output.width = w;
output.height = h;
output.fmt = IPU_PIX_FMT_RGB565;
output.rot = IPU_ROTATE_NONE;
output.show_to_fb = 0;
output.fb_disp.pos.x = 0;
output.fb_disp.pos.y = 0;
output.fb_disp.fb_num = 0;
output.output_win.pos.x = 0;
output.output_win.pos.y = 0;
output.output_win.win_w = w;
output.output_win.win_h = h;
output.user_def_paddr[0] = NULL;// NULL means that a buffer will be allocated
memset(&handle, 0x00, sizeof(handle));
// initialise the IPU
ret = mxc_ipu_lib_task_init(&input, NULL, &output,
OP_NORMAL_MODE,
&handle);
// print the addresses and sizes of the buffers that the IPU allocated
printf("mxc_ipu_lib_task_init ret:%d"
" inbuf_start: 0x%X outbuf_start: 0x%X\n"
" ifr_size: %d ofr_size: %d\n",
ret,
(unsigned int)handle.inbuf_start[0], (unsigned int)handle.outbuf_start[0],
handle.ifr_size, handle.ofr_size);
// NOTE the printf above ALWAYS prints out (though addresses might change):
// "mxc_ipu_lib_task_init ret:0 inbuf_start: 0x2B6A0000 outbuf_start: 0x2B76B000"
// " ifr_size: 829440 ofr_size: 829440
if (ret == 0) // zero means the init worked
{
printf("DOING IPU TASK\n");
// set the IPU input buffer to all 0xFF
memset(handle.inbuf_start[0], 0xFF, handle.ifr_size);
// before executing the task, print some of the outbuffer contents
ptr = (unsigned char *)handle.outbuf_start[0];
printf("outbuf before: ");
for (i = 0; i < 10; i++, ptr++)
printf("%02X ", *ptr);
printf("\n");
// the printf above ALWAYS prints out:
// "outbuf before: 00 00 00 00 00 00 00 00 00 00"
// execute the task
ret = mxc_ipu_lib_task_buf_update(&handle, NULL, 0, 0, NULL, NULL);
printf("loop:%d, mxc_ipu_lib_task_buf_update returned:%d\n", loop, ret);
// now print some outbuf contents after the task
ptr = (unsigned char *)handle.outbuf_start[0];
if (*ptr)// check for any non-zero value in output
printf("************* IPU DID CONVERT *************\n");// very rarely prints this!
printf("outbuf after: ");
for (i = 0; i < 10; i++, ptr++)
printf("%02X ", *ptr);
printf("\n");
// almost every time, the contents of the outbuf here is printed as zero, which is wrong.
// sometimes, possibly once every 10 attempts, the outbuf contains
// sequences of 0xDF, 0xFB - which is a correct conversion
}
else
{
// NOTE: this never gets printed, so the task by implication is always OK
printf("mxc_ipu_lib_task_init FAILED:%d\n", ret);
return(0);
}
// close the task
mxc_ipu_lib_task_uninit(&handle);
}
return(0);
}
It seems to me it could be a CPU cache problem. I think the CPU cache haven't flushed every time and I suppose the IPU can work only in the main memory but not in the CPU cache.
I found what looks like is happening here. There might be a problem with the IPU library allocating it's own memory. My original code has:
output.user_def_paddr[0] = NULL;// NULL means that a buffer will be allocated
I changed this so instead of getting the IPU to allocate an output buffer, I now pass the physical address of an output buffer which was allocated via FBIO_ALLOC, there are probably other ways to allocate physical memory but this worked for me. I only use a framebuffer as a method for allocating memory and getting a physical address, I don't ask the IPU to write it's output actually to the displayable framebuffer:
FdFbAlloc = open("/dev/fb1", O_RDWR, 0); // First open a framebuffer
unsigned int phys_out_address;
phys_out_address = 100000; // initialise the phys_out_address to be the size of the required buffer
ioctl(FdFbAlloc, FBIO_ALLOC, &phys_out_address); // ask the framebuffer to allocate us some memory
output.user_def_paddr[0] = phys_out_address; // use the allocated physical mem
If you also need the virtual address of the written output buffer, you can simply mmap() the phys_out_address.
This then works without fail, the IPU always does the CSC. So maybe the library function doesn't always work when allocating memory for itself, I haven't dug into it deeper, it's now doing what I need.
I'm using BSP 11.09.01 on the i.MX53.
Since originally posting I've taken another look at this. I've scoured the IPU API document and the Freescale samples but really can't see the reason for it. I'm wondering if:
a) there is some required initialisation missing from my code that I didn't spot
b) what I'm trying to do is not possible (but then how does it occsaionally work?)
c) there is an interface difference between writing direct to framebuffer as per Freescale samples and writing to IPU dynamically allocated output buffers that's missing from my code - but there's not that much to set up really
d) maybe the Freescale side has a problem
Thanks
Which i.MX and BSP are you using?