Brief:
- Pointer to a const-int-array, nested in a struct
- Using ptr to this struct (type) in various places
- ptr-deref causes address-error, because value was changed from i.e. 0x00AE to 0x80AE -> highest bit was toggled.
Detailed:
Declarations etc:
typedef struct {
const uint8_t *rawDataPtr;
uint16_t width; ///<in Bits!
uint16_t height; ///<in Bytes!
} image_t;
const uint8_t image_data_timer_53x56[53] = {
0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xff, 0xf0, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xfc, 0x00, 0x00,
0x00, 0x03, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x00,
0x00, 0x7f, 0xff, 0xff, 0xff, 0xf0, 0x00,
0x00, 0x7f, 0xff, 0xff}
image_t image_timer3 = {image_data_timer_53x56, 53, 1};
Edit: These definitions (above) are outside of any function-body.
void LCD_draw_image(uint16_t x, uint16_t y, image_t *img, uint16_t fg_color, uint16_t bg_color);
"image_timer_3" is global and extern.
Call of function "LCD_draw_image":
LCD_draw_image(X_WIDTH_FRAME, Y_POS_ICON, &image_timer3, COL_BLACK, COL_WHITE);
...using "img" in the subroutine in various ways. Doesn't actually matter how, because the pointer is already corrupted. See debugger output: (Edit: Breakpoint BEFORE calling the subroutine mentioned => deref inside of it is not crucial to this question) Debugger output - pointer-value gets highest bit toggled
Now, I tried size-changing of the initial int-array and it does have an effect since it did work for a while. But now the error reoccurred and I assume it is a setting of the compiler but I cannot figure out what! Each time I use the pointer I get ADDRESS ERROR (traps code 2), of course, since it does not exist.
WHAT HAPPENS TO THIS POINTER?
dsPIC33EP64GS804, Mplab 5.4, XC16, ICD3
1 Answer 1
Ok, I'll answer myself, but credits to @BRHANS, who gave the correct hint!
- Default setting of XC16 memory model: "CONST IN CODE" = variables declared as CONST will be placed in flash rom. In this case it is this variable:
const uint8_t image_data_timer_53x56[53]
- The PSV-feature of the dsPIC allows using those const-rom-variables like any other variable in RAM. For more info on PSV see section "Memory Organization" in the DS.
- BUT...common "RAM"-variables will be found in the lower half of data memory space while the upper half is reserved for PSV-variables (mapped).
- So, when using a POINTER to such a variable it makes a big difference. The compiler needs to know, that the variable is PSV-managed to handle it correctly.
- This is done by the "psv" type qualifier:
const uint8_t *rawDataPtr
needs to be:
__psv__ const uint8_t *rawDataPtr
- Here we go.. it works!
2 more comments:
- If you know it (and now you and I do) you can see it in the debugger watch already: There is a "P" on the symbol and a "(PSV)" in the type-label.
- The distinction between upper and lower half of the memory space is made by bit 15 of the EA-word, which is exactly why I saw that paricular bit as "toggled" (see headline). EA<15> = 1 means PSV. So the shown address was not necessarily wrong, but the compiler didn't handle it correctly.
rawDataPtr
as a pointer to auint8_t
, not as auint8_t
. It'll be allocated with whatever amount of space is required to hold a pointer. The fact that it points to auint8_t
is irrelevant. \$\endgroup\$const
). How are you dereferencing the pointer in yourLCD_draw_image
function? are you using an intermediate variable of a different type somewhere? \$\endgroup\$