2
\$\begingroup\$

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

\$\endgroup\$
6
  • \$\begingroup\$ image_timer3_rawDataPtr's value is out of the boundary of the datatype unsigned char it seems. Is it ok? \$\endgroup\$
    – CNA
    Commented Mar 15, 2021 at 9:04
  • \$\begingroup\$ 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? \$\endgroup\$
    – Raphael B.
    Commented Mar 15, 2021 at 9:31
  • \$\begingroup\$ When troubleshooting compiler bugs, I would look at the assembly code the compiler is generating. \$\endgroup\$ Commented Mar 15, 2021 at 9:55
  • 2
    \$\begingroup\$ @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. \$\endgroup\$
    – brhans
    Commented Mar 15, 2021 at 11:31
  • 1
    \$\begingroup\$ @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? \$\endgroup\$
    – brhans
    Commented Mar 15, 2021 at 11:39

1 Answer 1

1
\$\begingroup\$

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.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.