All posts by Tianlittlecity

A mom of two boys. Decide to use this space as a display spot for Jason's LEGO projects.

C qualifier — volatile

volatile is mostly used in low-level C programming, when the code deals with peripheral devices, IO ports, ISRs.

With “volatile”, compiler will not do any optimisation (e.g. store the value in a register and read it back from the register) on this variable , but read the variable from the memory every time.

a few examples:

  1. a variable which contains the value of a register.
  2. Global variables modified by an interrupt service routine outside the scope.
  3. Global variables within a multi-threaded application.
Advertisements

Artefacts resulted by transparency

Below are two snapshots from videos. the left is the bad case, where the green line is blurred; the right is the good case. The bad case gets reproduced when switching from Android auto to RVC mode.

the screen reflection confirmed this too. below is the images in 0/win-0.

Screen combined a few windows together. this is the top window. Its transparency is SOURCE_OVER.

win-5-1

Open it via GIMP,  the alpha of questionable area is not 255, although the majority of the image is with alpha 255. With SOURCE_OVER transparency,  the pixels will blend over the pixels underneath them.

analysis_gmp

These are the bottom windows for the bad case:

This is the bottom window for the good case:

win-6-1-a-a

For the good case, the alpha values of the bottom window (white) are all 1s (GIMP shows 1, not 0). As it is fully transparent, there is no blending occurring.

For the bad case, the alpha values of the bottom window (blue) are 255s. so the pixels on the top window (with a non-255 alpha value) will blend over with the bottom.

Solution:

change the top (RVC) window to “TRANSPARENCY_NONE”, and use alpha 255.

Transparency & alpha blending

** alpha = opaqueness: 1 means fully opaque while 0 means fully transparent.

** Alpha blending allows pixel blending based on the alpha channel of the source pixel.

** In order to use transparency, you must use a pixel format with an alpha channel, like RGBA. Applications that want to disregard the alpha channel can choose a pixel format with an X.

Transparency can be a property of a window, or a display.

1. Window transparency

Note:  the follow definitions are used by BLIT too, specified by SCREEN_BLIT_TRANSPARENCY.

  • TRANSPARENCY_SOURCE_OVER
    • typical (and default) alpha blending: the source pixels are blended over the destination pixels.
  • TRANSPARENCY_SOURCE_COLOR
    • the destination pixels are replaced by source pixels when the source color does not match the reference color value.
  • TRANSPARENCY_SOURCE
    • destination pixels are replaced by source pixels, including the alpha channel.
  • TRANSPARENCY_NONE
    • destination pixels are replaced by fully-visiable source pixels.
  • TRANSPARENCY_DISCARD
    • destination is not modified

2. display/pipeline transparency, defines how the graphics image from one pipeline will be combined with the graphics image of those pipelines layered below it.

  • WFD_TRANSPARENCY_NONE
  • WFD_TRANSPARENCY_SOURCE_COLOR
    • the source pixels that match the defined transparent source color will be considered transparent and thus will not be combined with the corresponding pixels of the pipelines layered below it.
  • WFD_TRANSPARENCY_GLOBAL_ALPHA
    • a signal aplha blending value will be used when blending.
  • WFD_TRANSPARENCY_SOURCE_ALPHA

 

 

Logical thinking(2)

With 2 headache issues being solved, now I am relaxed. At the same time, a few things need to be learnt from.

summary of 2 issues:

#1 Kernel crash or system hang, if capture is started 5 ~ 10s after bootup. the crash point is in VPE isr handler most times. and the kernel developer’s analysis indicates that there is memory corruption.

— I have narrowed down to the VPE operation, as the issue disappeared if there is no VPE operation.

#2 Display shows stripes then system resets, if there is capture activity involved right after bootup.

—  EMIF registers were corrupted (JTAG debug), most of time 32 bytes. By setting up a firewall against EMIF registers, the analysis showed that it is VIP or VPE hit the exception a few times.

My action:

I tried the VPE max_size to restrict VPDMA to write over boundry, and it doesn’t help. then, I have no idea.

There is an idea from some else: VIP initialisation might bring some issues here. so most people focused on the VIP instantiation sequence, delay, ..coordination.. If that’s the reason, it looks that nothing I can do…

Correct way to continue:

if VIP intialization doesn’t solve the problem, we need focus on the VPE driver  — It is a memory corruption, where are we writing during an VPE VPDMA operation?  My first idea is the VPE output buffer, and didn’t check the code clearly. .. Actually, there is another write: write descriptor, which is provided to VPDMA to write into during a VPDMA transaction.

Also, register dump and dma configuration (extremely important! as it might be initialised on the stack before being passed the the hardware) are essential if the system is still reachable (via JTAG), as they will give some clue about what might be wrong. 

the  dma configuration printed in issue #2 showed that a write descriptor address is a random value (as it is defined on the stack and not gets initialised to 0), which leads to VPDMA writing to EMIF registers.

Issue analysis skill — logical thinking

We met one lockup issue recently, which was quite confusing from the symptom. There were a few facts based on the testing:

  1. CVBS input works well.
  2. LVDS/MIPI with format RGB888 works well.
  3. LVDS/MIPI with format UYVY doesn’t work well.
  4. With a non-zero verbosity, it seems to work well (later, the test confirmed that there were still failures, just less frequently).

so my first impression is that the nightmare came back — when we worked on this platform a few years ago, we had a few lockups due to the un-sturdy DMA hardware and the interaction of DMA operations between capture and display — Another developer said it should have been fixed by two changes before (don’t disable DMA, don’t disable DMA channel during the capturing) and the lockup did not happen for quite a long time.  However, I think he didn’t convince me as I don’t trust the hardware…

I did tried to not touch DMA channel, or touch it at a different time point, but they didn’t help. I also asked to use separate IPUs for display and capture, and got confirmed that no issues were seen in this configuration. Then, I signed: oh, the nightmare, it is the interaction of IDMaC channels..my instinct was: it is not fixable.. we probably can only try to avoid it.. it’s timing related…

OK…so the problem is here. Since separate IPUs don’t have the issue, I should not focus on the nightmare before, but think bout the issue using logical thinking: with single IPU being used, there are both hardware interaction and software interaction. we need think about the issue from both aspects.

one more thing, through the perplexing test result, there is another fact: we recently changed the code on capture side (and some shared control in display driver), it is possible the new change introduced this issue since the lockup had not seen for long time.

Eventually, with the help of JTAG, the root cause is that a kernel call between InterruptLock() and InterruptUnlock() leads to early enabling of interrupts, so a deadlock is formed. As the piece of code only gets executed when the hardware fails to clear the ready flag so(software clears it) and the deadlock is only formed when display interrupt is raised right after InterruptLock() is called. So it is rare to see..

Using GDB to check core file

An application crashed, and there was a core file generated.

1. Collect all the associated libraries, and run “gdb”.

(gdb) file testApp

(gdb) set solib-search-path .

(gdb) core testApp. core

it will show something like:

Program terminated with signal 11, Segmentation fault.
#0 0x781306a6 in xx_thread () from libcapture-soc-xx.so

(gdb) backtrace
#0 0x781306a6 in xxx_thread () from libcapture-soc-xxx.so
#1 0x01025a8c in timer_settime () from libc.so.3

So you want to know what the instruction is at 0x781306a6.. go to..

2.  check the disassembly code

(gdb) disassemble hw_capture_thread

it will show you the assembly code and where the crash occurs.

disassemble

(gdb) info registers

registers

so it is clear that an invalid address is being accessed: register r3 is 0.

3. Which piece of C code?

you need have a library with symbols (-g), and run “pahole libcapture-soc-xx.so”, or run “pahole xx.o”, it will show all the structures in that library/file.

the crashing point shows that the code was trying to access a member of a structure at offset 52, so you look for the structures which has a member at 52..

Note: why does the backtrace show “imer_settime()” calls “xx_thread()”?

the reason is, it is some function in C library which calls/schedules xx_thread. However, since there are no debug symbols in libC, gdb can’t locate the exact function, and can only return a static/global function which is closer.

Tips:

1. “info” is a very useful command.

  • info threads
  • info shared libraries
  • info registers

2. to check the states of other threads, ” thread apply all bt”.

3. Pohole (Poke-a-Hole) was developed to find the size of the data structures, and the holes caused due to aligning the data elements to the word-size of the CPU by the compiler. see https://lwn.net/Articles/335942/

Mapping to device memory

1. mmap_device_io()

uintptr_t mmap_device_io( size_t len, uint64_t io );

  • maps len bytes of device I/O memory at io, and makes it accessiable via the in*() and out*() function.
  • returns a handle to the device’s I/O memory, or MAP_DEVICE_FAILED if an error occurs (errnois set).

Example:

uintptr_t vin_base;

ctx->vin_base = mmap_device_io(RCAR3_VIN_SIZE, RCAR3_VIN0_BASE); 

 if (ctx->vin_base == (uintptr_t)MAP_DEVICE_FAILED) {

                 ctx->vin_base = (uintptr_t)NULL; 

                 return errno;

   } 

Access the registers:

uint32_t reg_val;

reg_val = in32(vin_base + (off));

out32(vin_base + (off), (value));

2. mmap_device_memory()

void * mmap_device_memory( void * addr, size_t len,  int prot, int flags, uint64_t physical); 

  • maps len bytes of a device’s physical memory address into the caller’s address space at the location returned by mmap_device_memory().
  • Returns the address of the mapped-in object, or MAP_FAILED if an error occurs (errno is set).

example:

 uint32_t *ipu_regp;   

ipu_regp = (uint32_t*)mmap_device_memory(NULL, IPU_REGSIZE,                   PROT_READ|PROT_WRITE|PROT_NOCACHE, 0, ipu_regbase);

if (ipu_regp == MAP_FAILED) {

                  ipu_regptr = NULL;

                  return err; 

 }  

#define ipu_regptr(offset)  (uint32_t volatile *) (((unsigned char volatile *) ipu_regp) + offset)

#define IPU_CONF         ipu_regptr(IPU_CONF_OFFSET + 0x0)

uint32_t ipu_conf_val;

ipu_conf_val = *IPU_CONF;           

*IPU_CONF = ipu_conf_val;