Skip to main content
Harvey White
Senior III
September 4, 2026
Question

ChromART and repeated calls

  • September 4, 2026
  • 0 replies
  • 15 views

I’ve got a working graphics system.  It does high level operations on a 32 bit virtual image of the display’s resolution.   The image is then translated to a 16 bit buffer image (RGB565 for an ILI9341 display).  That image is then transferred over SPI to the display.  The SPI drivers can be polled, interrupt driven, or DMA driven.  Software drivers are used for all of this, and work.

Moving to a different processor (U575 from L562), ChromART is available.  It could be used for filling the virtual image, translating to the RGB565 image.  2D DMA can be used to transfer modified blocks to the display.

Now the problem.

The transfer works erratically in some cases.  Some data (and I’m using mostly saturated colors) doesn’t transfer well into RGB565 (say 100% blue), it may just end up with black.  Other times, the complete color palette is transferred properly.

I’m investigating whether or not the repeated restart of the ChromART peripheral is a problem.  Mostly what happens is that the mode should remain unchanged, but the transfer source and destination change (allows partial blocks).  However, since the same hardware would be used to fill areas in the virtual image, and that will require changing more mode.

I’m working only on the ARGB8888 to RGB565 translation, Graphics plane image to RGB565 image, straight translate.  Areas are trimmed to the limits of the display.  Code is included, but trimmed.

I seem to be missing something.


switch (ILI9341_ROTATE)
{
// ************************************************************* portrait mode ********************************************************************
case 90:
case 270:
{
break;
}

// ************************************************************* landscape mode *******************************************************************
default:
{
// working
// HAL LEVEL DRIVERS
// default orientation, 0, 180
// with RB regular and bytes-regular
// blue and green are reversed

// with RB regular and bytes-swap
// blue--> red; and green--> green; red--> blue are reversed

// USE CHROMART SYSTEM TO FILL VIRTUAL MEMORY WITH A BLOCK OF DATA

int w = 2;

// WIDEN TRANSFER WINDOW
x0 = minmax(x0-w, 0, 319);
x1 = minmax(x1+w, 0, 319);
y0 = minmax(y0-w, 0, 239);
y1 = minmax(y1+w, 0, 239);

if (x0 > x1) swap32(x0,x1);
if (y0 > y1) swap32(y0,y1);

// ************************************************************* source 1 select ******************************************************************
switch (source1)
{
case TEXT_PLANE:
{
if(_QVGA_PAGES > 1)
{
srcPTR = &QVGA.Lpixel[TEXT_PLANE][y0][x0]; // text plane upper left of block to be written
}
else
{
srcPTR = &QVGA.Lpixel[GRAPHICS_PLANE][y0][x0]; // text plane upper left of block to be written
}
break;
}
case FOREGROUND_COLOR:
{
RGB1 = RGB(foreground_color); // foreground color
srcPTR = &RGB1;
break;
}
case BACKGROUND_COLOR:
{
RGB1 = RGB(background_color); // foreground color
srcPTR = &RGB1;
break;
}
default:
{
srcPTR = &QVGA.Lpixel[GRAPHICS_PLANE][y0][x0]; // graphics plane upper left of block to be written
// graphics plane is default
}
};

// ************************************************************* source 2 select ******************************************************************
switch (source2)
{
case GRAPHICS_PLANE:
{
src2PTR = &QVGA.Lpixel[TEXT_PLANE][y0][x0]; // graphics plane upper left of block to be written
break;
}
case FOREGROUND_COLOR:
{
RGB1 = RGB(foreground_color); // foreground color
src2PTR = &RGB1;
break;
}
case BACKGROUND_COLOR:
{
RGB1 = RGB(background_color); // foreground color
src2PTR = &RGB1;
break;
}
default:
{
if(_QVGA_PAGES > 1)
{
srcPTR = &QVGA.Lpixel[TEXT_PLANE][y0][x0]; // text plane upper left of block to be written
}
else
{
srcPTR = &QVGA.Lpixel[GRAPHICS_PLANE][y0][x0]; // graphics plane upper left of block to be written
}
// text plane is default
}
}


// ************************************************************* ChromART setup *******************************************************************
hdma2d.Instance = DMA2D;
dstPTR = &QVGA_image.Ppixel[y0][x0]; // upper left of block to be read
// DMA init mode
hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB565; // MUST BE SET FOR 16 BIT COLOR (REQIRED AS SET) // write output VM image mode (32 bit)
hdma2d.Init.OutputOffset = 0; // = 0 next line. =320 skips a line

// swapping bytes switches blue and green, text is green
hdma2d.Init.BytesSwap = DMA2D_BYTES_SWAP; // reverse of bytes (needed to swap blue and red)
// hdma2d.Init.BytesSwap = DMA2D_BYTES_REGULAR; // reverse of bytes (needed to swap blue and red)
hdma2d.Init.LineOffsetMode = 0; // 0 is required

// destination
// dstPTR = &QVGA_image.Lpixel[y0][x0]; // upper left of block to be read

// ************************************************************* layer 1 configuration ************************************************************
if (_QVGA_PAGES > 1)
{
switch (PLANE_MODE)
{
case PLANE_OR:
{
break;
}
default:
{
// result = page1 (GRAPHICS PLANE)

switch (source2)
{
case FOREGROUND_COLOR:
case BACKGROUND_COLOR:
{
// layer 1 config
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565; // must be set to 16 bit color (RGB565)
hdma2d.LayerCfg[1].InputOffset = 0; // does not matter
hdma2d.LayerCfg[1].InputAlpha = 0xFF; // preserve alpha
hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;

hdma2d.LayerCfg[1].RedBlueSwap = DMA2D_RB_SWAP; // reverses blue and red
// hdma2d.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR; // reverses blue and red
HAL_DMA2D_ConfigLayer(&hdma2d, 1);
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
{
Error_Handler();
}
hdma2d.Init.Mode = DMA2D_R2M; // NEEDED FOR TRANSLATE
// translate block to be updated
result = HAL_DMA2D_Start(&hdma2d,(unsigned int)srcPTR, (unsigned int) dstPTR, (x1+1-x0), (y1+1-y0) ); // X pixels * Y pixels
result = HAL_DMA2D_PollForTransfer(&hdma2d, 100);// rectangle_build_XY(&rect, x0, y0, x1, y1); // for display refresh for block
break;
}
default:
{
// layer 1 config
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888; // must be set to 32 bit color (ARGB8888)
hdma2d.LayerCfg[1].InputOffset = 0; // does not matter
hdma2d.LayerCfg[1].InputAlpha = 0xFF; // preserve alpha
hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;

hdma2d.LayerCfg[1].RedBlueSwap = DMA2D_RB_SWAP; // reverses blue and red
// hdma2d.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR; // reverses blue and red
HAL_DMA2D_ConfigLayer(&hdma2d, 1);
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
{
Error_Handler();
}
hdma2d.Init.Mode = DMA2D_M2M_PFC; // NEEDED FOR TRANSLATE
// translate block to be updated
result = HAL_DMA2D_Start(&hdma2d,(unsigned int)srcPTR, (unsigned int) dstPTR, (x1+1-x0), (y1+1-y0) ); // X pixels * Y pixels
result = HAL_DMA2D_PollForTransfer(&hdma2d, 100);// rectangle_build_XY(&rect, x0, y0, x1, y1); // for display refresh for block
}
}