2023-04-18 03:31 AM
Hello all
I have a custom STM32L496RGTx-based board onto which I'm migrating a legacy rendering engine. I'd really like to accelerate text rendering and I'm looking into DMA2D for a4 format font data.
I have a little test setup which attempts to populate a buffer from supplied a4 test data like this:
static void draw_a4(const uint8_t* a4) {
uint16_t w=24;
uint16_t h=24;
uint16_t buf[w * h]; // rgb565 raster buffer
uint32_t back = (uint32_t)&buf;
uint32_t data = (uint32_t)a4;
__HAL_RCC_DMA2D_CLK_ENABLE();
/* constant bg configuration */
DMA2D->BGPFCCR = (DMA2D->BGPFCCR & 0x00fc00c0) | /* DMA2D Background PFC Control Register reserved bits */
(0b11111111 << 24) | /* alpha value (0xff) */
(0 << 16) | /* alpha mode */
(0 << 8) | /* clut size */
(0 << 5 ) | /* start clut loading */
(0 << 4) | /* clut color mode */
(0b1010 << 0); /* color mode argb8888 */
DMA2D->BGCOLR = 0xff00ffff; /* DMA2D Background Color Register */
DMA2D->BGMAR = 0; /* DMA2D Background Memory Address Register */
DMA2D->BGOR = 0; /* DMA2D Background Offset Register */
/* constant fg configuration */
DMA2D->FGPFCCR = (DMA2D->FGPFCCR & 0x00fc00c0) | /* DMA2D Foreground PFC Control Register */
(0b11111111 << 24) | /* alpha value */
(0 << 16) | /* alpha mode */
(0 << 8) | /* clut size */
(0 << 5 ) | /* start clut loading */
(0 << 4) | /* clut color mode */
(0b1010 << 0); /* color mode a4 */
DMA2D->FGCOLR = 0xffffff00; /* DMA2D Foreground Color Register */
DMA2D->FGMAR = data; /* DMA2D Foreground Memory Address Register */
DMA2D->FGOR = 0; /* DMA2D Foreground Offset Register */
/* output configuration */
DMA2D->OPFCCR = (DMA2D->OPFCCR & 0xfffffff8) | (0b010 << 0); /* DMA2D output PFC control register (rgb565) */
DMA2D->OOR = 0; /* DMA2D Output Offset Register */
DMA2D->OMAR = back; /* output buffer */
DMA2D->NLR = (DMA2D->NLR & 0xc0000000) | /* DMA2D Number of Line Register */
(w << 16) | /* number of pixels per line */
(h); /* Number of lines */
DMA2D->CR = (DMA2D->CR & 0xfffcc0f8) | /* DMA2D control register */
(0b10 << 16) | /* mode (FG and BG fetch with PFC and blending) */
(0 << 13) | /* Configuration Error Interrupt Enable */
(0 << 12) | /* CLUT transfer complete interrupt enable */
(0 << 11) | /* CLUT access error interrupt enable */
(0 << 10) | /* Transfer watermark interrupt enable */
(0 << 9) | /* Transfer complete interrupt enable */
(0 << 8) | /* Transfer error interrupt enable */
(0 << 2) | /* abort */
(0 << 1) | /* suspend */
(0 << 0); /* transfer */
DMA2D->CR = DMA2D->CR | DMA2D_CR_START; /* set start bit to start the transfer */
while(DMA2D->CR & DMA2D_CR_START) { } // wait for chromart idle
As soon as I kick-off the transfer on line 58, the TEIF bit in DMA2D->ISR gets set, indicating a transfer error and the data, but I can't for the life of me work out what would cause something like that. I've tried a few different combinations for the parameters but always with the same result.
Is there anything forehead slappingly obviously wrong my code or some sort of other configuration required ?
2023-04-18 03:47 AM
Read out and check/post DMA2D registers content.
The prime suspects are the address registers - the memories have to be accessible by the DMA2D (see the very first figure in RM for routing availability from AHB bus matrix masters to slaves), and probably there are alignment requirements, too.
JW
2023-04-18 04:30 AM
The thought had occurred to me.
In this instance, the output buffer buf1 is a local variable on the stack and, as reported by the debugger, at 0x2004f678, the source buffer a4 is an initialised static array at 0x8045418. Other than one address being in RAM and the other in program flash there doesn't seem to be anything unusual about them and they're both aligned to four byte boundaries.
DMA2D DMA2D_TypeDef * 0x4002b000
CR volatile uint32_t 0x20000 (Hex)
ISR volatile uint32_t 0x1 (Hex)
IFCR volatile uint32_t 0
FGMAR volatile uint32_t 0x8045418 (Hex)
FGOR volatile uint32_t 0
BGMAR volatile uint32_t 0
BGOR volatile uint32_t 0
FGPFCCR volatile uint32_t 4278190090
FGCOLR volatile uint32_t 16776960
BGPFCCR volatile uint32_t 4278190090
BGCOLR volatile uint32_t 65535
FGCMAR volatile uint32_t 0
BGCMAR volatile uint32_t 0
OPFCCR volatile uint32_t 2
OCOLR volatile uint32_t 0
OMAR volatile uint32_t 537196152
OOR volatile uint32_t 0
NLR volatile uint32_t 1572888
LWR volatile uint32_t 0
AMTCR volatile uint32_t 0
RESERVED uint32_t [236] 0x4002b050
FGCLUT volatile uint32_t [256] 0x4002b400
BGCLUT volatile uint32_t [256] 0x4002b800
DMA2D->CR volatile uint32_t 0x20000 (Hex)
2023-04-18 05:13 AM
What debugger are you using, folks, which displays registers content in decimal? I see it so often here...
Try to move the source to RAM, just as a test whether the FLASH address is a problem. Shouldn't be, but...
JW
2023-04-18 08:04 AM
I dumped the source into a local stack-based buffer, but I get the exactly the same symptom :(
The debugger is just the regular STM32CubeIDE and I'm looking at the variables in the expression window; it's certainly possible to change the number format to hex but I guess the default must be decimal.
CR volatile uint32_t 0x20000 (Hex)
ISR volatile uint32_t 0x1 (Hex)
IFCR volatile uint32_t 0x0 (Hex)
FGMAR volatile uint32_t 0x2004f420 (Hex)
FGOR volatile uint32_t 0x0 (Hex)
BGMAR volatile uint32_t 0x0 (Hex)
BGOR volatile uint32_t 0x0 (Hex)
FGPFCCR volatile uint32_t 0xff00000a (Hex)
FGCOLR volatile uint32_t 0xffff00 (Hex)
BGPFCCR volatile uint32_t 0xff00000a (Hex)
BGCOLR volatile uint32_t 0xffff (Hex)
FGCMAR volatile uint32_t 0x0 (Hex)
BGCMAR volatile uint32_t 0x0 (Hex)
OPFCCR volatile uint32_t 0x2 (Hex)
OCOLR volatile uint32_t 0x0 (Hex)
OMAR volatile uint32_t 0x2004f660 (Hex)
OOR volatile uint32_t 0x0 (Hex)
NLR volatile uint32_t 0x180018 (Hex)
LWR volatile uint32_t 0x0 (Hex)
AMTCR volatile uint32_t 0x0 (Hex)
RESERVED uint32_t [236] 0x4002b050
FGCLUT volatile uint32_t [256] 0x4002b400
BGCLUT volatile uint32_t [256] 0x4002b800
Actually, looking at that in hex I just noticed that I have this in code:
DMA2D->BGCOLR = 0xff00ffff;
but stepping over that line, the debugger is showing me 0xffff.
I just changed to
DMA2D->BGCOLR = 0x12345678;
and the debugger is showing me 0x345678; for some reason attempting to write anything except zero for the alpha channel is ignored.
2023-04-18 08:24 AM
slight update.
if I set
DMA2D->BGPFCCR = (DMA2D->BGPFCCR & 0x00fc00c0) | /* DMA2D Background PFC Control Register reserved bits */
(0b11111111 << 24) | /* alpha value (0xff) */
(0 << 16) | /* alpha mode */
(0 << 8) | /* clut size */
(0 << 5 ) | /* start clut loading */
(0 << 4) | /* clut color mode */
(0b1010 << 0); /* color mode a4 */
DMA2D->BGCOLR = 0xff0000ff; /* DMA2D Background Color Register */
and
DMA2D->FGPFCCR = (DMA2D->FGPFCCR & 0x00fc00c0) | /* DMA2D Foreground PFC Control Register */
(0b11111111 << 24) | /* alpha value */
(0 << 16) | /* alpha mode */
(0 << 8) | /* clut size */
(0 << 5 ) | /* start clut loading */
(0 << 4) | /* clut color mode (ignored in a4 mode) */
(0b1010 << 0); /* color mode a4 */
DMA2D->FGCOLR = 0xffff0000; /* DMA2D Foreground Color Register */
DMA2D->FGMAR = data; /* DMA2D Foreground Memory Address Register */
so the a4 data and a4 mode on both fg and bg, fgcolor red, bgcolor blue I get a very plausible rendering of the test pattern. there still seems to be some glitches, but definite progress.
The glitches are
The pixels seem to come out with what appears to be a big-endian vs little endian type problem presumably explained by the in-memory data ordering shown in the datasheet.
The fg and bg colors are being basically respected but there seems to be some white slipping in and even if I set both fg and bg to 0x000000, a 0 in the a4 data always results in a pure white output pixel.