2

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

Raphael B.
  • 31
  • 5
  • image_timer3_rawDataPtr's value is out of the boundary of the datatype unsigned char it seems. Is it ok? – CNA Mar 15 '21 at 09:04
  • Hm... don't quite see it. "rawDataPtr" ist a pointer to uint8, the dsPIC33 is a 16-bit system. That's fine, isn't it? Or did I get this wrong? – Raphael B. Mar 15 '21 at 09:31
  • When troubleshooting compiler bugs, I would look at the assembly code the compiler is generating. – user253751 Mar 15 '21 at 09:55
  • @RaphaelB.No, it's not. Even though dspic33 is a 16-bit system, you only allocate 8 bit for that pointer. – CNA Mar 15 '21 at 10:42
  • 2
    @CNA what you're writing doesn't make sense. The OP has declared `rawDataPtr` as a *pointer* to a `uint8_t`, not as a `uint8_t`. It'll be allocated with whatever amount of space is required to hold a pointer. The fact that it points to a `uint8_t` is irrelevant. – brhans Mar 15 '21 at 11:31
  • 1
    @RaphaelB. I suspect that your problem has something to do with the way the PIC differentiates between pointers to RAM and pointers to Flash - as far as I remember the MSbit being set indicates that the address is in Flash (as you would expect for a pointer to a `const`). How are you dereferencing the pointer in your `LCD_draw_image` function? are you using an intermediate variable of a different type somewhere? – brhans Mar 15 '21 at 11:39

1 Answers1

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:

  1. 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.
  2. 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.
Raphael B.
  • 31
  • 5