From Section 3.1.3 of the StellarisWare GrLib Manual:
"Images are stored as an array of unsigned characters. Ideally, they would be in a structure, but the limitations of C prevents an efficient definition of a structure for an image while still allowing a compile-time declaration of the data for an image. The effective definition of the structure is as follows (with no padding between members):
typedef struct
{
//
// Specifies the format of the image data; will be one of
// IMAGE_FMT_1BPP_UNCOMP, IMAGE_FMT_4BPP_UNCOMP, IMAGE_FMT_8BPP_UNCOMP,
// IMAGE_FMT_1BPP_COMP, IMAGE_FMT_4BPP_COMP, or IMAGE_FMT_8BPP_COMP. The
// xxx_COMP varieties indicate that the image data is compressed.
//
unsigned char ucFormat;
//
// The width of the image in pixels.
//
unsigned short usWidth;
//
// The height of the image in pixels.
//
unsigned short usHeight;
//
// The image data. This is the structure member that C can not handle
// efficiently at compile time.
//
unsigned char pucData[];
}
tImage;
"
I'm trying to use the SitaraWare Graphics Library and since so little of the StellarisWare Graphics Library is changed when ported to SitaraWare, can someone explain a couple things?
1. In what way can C not handle this structure efficiently at compile time? Wouldn't this work:
const tImage g_sTILogo = {
.ucFormat = IMAGE_FMT_4BPP_COMP, .usWidth = 240, .usHeight = 13,
.pucData = {0x00, 0x00, 0x00, 0x25, 0x26, 0x25, ... }
};
I think this is acceptable in C99 as a 'flexible array member' (ISO/IEC 9899:1999, Section 6.7.2.1, paragraph 16).
2. I'm trying to write a display driver for SitaraWare GrLib for a 1BPP (monochrome) display. The function GrOffScreen1BPPInit() contains the following code:
//
// Initialize the image buffer.
//
pucImage[0] = IMAGE_FMT_1BPP_UNCOMP;
*(unsigned short *)(pucImage + 1) = lWidth;
*(unsigned short *)(pucImage + 3) = lHeight;
Both CodeSourcery's and IAR's C Compilers produce the following instructions:
//
// Initialize the image buffer.
//
pucImage[0] = IMAGE_FMT_1BPP_UNCOMP;
c1080e00: e3a00001 mov r0, #1
c1080e04: e5c10000 strb r0, [r1]
*(unsigned short *)(pucImage + 1) = lWidth;
c1080e08: e1c120b1 strh r2, [r1, #1]
*(unsigned short *)(pucImage + 3) = lHeight;
c1080e0c: e1c130b3 strh r3, [r1, #3]
This leads to funky behavior when executed because, by default, pucImage is aligned on some even boundary, therefore pucImage + 1 is NOT on an even boundary. The compilers are generating a STRH (store halfword) instruction, which, according to the ARM Architecture Reference Manual (ARM DDI 0100I), Section A4.1.104, "If the address is not halfword-aligned, the result is UNPREDICTABLE." I can confirm, single-stepping through the instructions in IAR, that STRH will overwrite the ucFormat byte with the LSB of lWidth. Perhaps this problem didn't show up in StellarisWare because the Cortex-M3 (Thumb?) instructions didn't share this limitation? Any proposals for a solution?