IPU not working most of the time, but occasionally works

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

IPU not working most of the time, but occasionally works

1,426 Views
StevieRG
Contributor II

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);
}

Labels (1)
0 Kudos
4 Replies

826 Views
raimundszabo
Contributor II

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.

0 Kudos

826 Views
StevieRG
Contributor II


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.

0 Kudos

826 Views
StevieRG
Contributor II

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

0 Kudos

826 Views
Philip_FSL
Contributor IV

Which i.MX and BSP are you using?

0 Kudos