I am struggling to understand why I get random data while trying to read from multidimensional table that is stored in rom.
I have a table of bitmap character which I want to display on OLED screen. Table of characters is too big to fit into ram and rom is natural place for it. When I try to read elements from the table, data is not the one stored in the table.
Here is what I try to do. I have bitmap declared as a multidimensional array at the begging of the C-file where it is used:
rom const char number[15][4][20] = { {
{0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xf0, 0x70, 0x78, 0x38, 0x38, 0x38, 0x38, 0x78, 0x70, 0xf0, 0xe0, 0xc0, 0x00, 0x00},// row 1 columns 19
{0x00,...
This is where I try to read the data and print it to the screen:
for(i=0; i<4; i++)
{
PutImage(number[digit][i],20,4,offset,i+2);
}
Implementation of PutImage function:
void PutImage(char ptr[], unsigned char sizex, unsigned char sizey, unsigned char startx, unsigned char starty)
{
unsigned char _page, _column;
//startx += OFFSET;
OledWriteCommand(0xb0+starty);
OledWriteCommand(startx&0x0F);
OledWriteCommand(0x10 | ((startx>>4)&0x0F));
for(_column=0; _column<sizex; _column++)
{
OledWriteData(ptr[_column]);
}
}
If I change it so that data fits into ram it works just fine. So the problem has to be either that data is not stored correctly in the first place or the way I used it is incorrect.
The Pic I am using is 18F27J53 and datasheet section 7.1 (Table Reads and Table Writes) talks about some Assembler operations that are used for moving bytes between program memory and ram. As I am using C, i am not sure if that is something I need to be aware of or does the compiler know how to handle that.
Ok related question and its answer got me to (hopefully) right track: Can I make a function that accepts both ram and rom pointers in Microchip C18?
And thanks to Pandrei as well for pointing out that the implementation if PutImage could be the cause.
I got the code working by making duplicate function PutROMImage which accepts "near rom char*"
-type instead of just "char*" which defaults to ram.
So C18 does not allow pointers to point both ram and rom and PutImage -function parameter defaults to ram. So passing a pointer to array which is located in rom causes pointer point to random values.
I had not noticed this deficiency in the code and compiler wasn't smart enough to complain about that.
having the data in ROM (.txt section) or RAM (.data section) has nothing to do with the problem you are facing.
Assuming that the initialization is correct and you initialize all the elements (if you don't, the elements left out will be default initialized to 0), the problem might be in the function's implementation: PutImage.
Since you have problems when the size changes, maybe you have some hard-coded values in there...
Related
I'm writing an embedded program, which is divided in two parts: bootloader and app. (I'm targeting the STM32 and doing my development in C using the Eclipse IDE.)
I'm using a display, so I wrote some functions and 3 different fonts.
The idea is to use a sector of the microcontroller and share it.
The font area is defined with a linker (ld) script like so:
.mySegment start_of_FONT_segm : {KEEP(*(.Courier_New_Bold_20_Section))}
.mySegment1 0x8011298 : {KEEP(*(.Terminal6x8_Section))}
Then, I use an array to write in:
const unsigned char __attribute__((section (".Terminal6x8_Section"))) Terminal6x8[] = {
0x00,
0x00,
...
But how do I read it from another program (in this case, the application)?
I tried with:
unsigned char *Terminal6x8 = (volatile unsigned char*)0x08011298;
but the compiler puts the Terminal6x8 into RAM.
I'll be glad to share some functions also, but I don't know how to declare those in ld and C syntax, either.
The following line of code:
unsigned char *Terminal6x8 = (volatile unsigned char*)0x08011298;
is bad for many different reasons:
It uses a fixed (hard-coded) address, which is not very good.
It declares the data as volatile, which makes no sense in this context.
It does not declare the data as constant.
If you want the pointer to be also placed in the flash memory, you should write:
const unsigned char * const Terminal6x8 = (const unsigned char * const) 0x08011298;
I'll be glad to share some functions also, but don't know how to declare in ld and C syntax too.
The proper way to do it is to declare a vector table (i.e., a table of pointers) containing the pointers to the data and the functions you want to share between the flash segments.
Indeed the pointer *Terminal6x8 is put into RAM. If you want the pointer stored in flash, declare it const.
Although, the data pointed to by *Terminal6x8 is stored in flash at address 0x08011298 as you want. No matter where the pointer is stored.
I want to copy an uint8_t array to a uint8_t pointer
uint8_t temp_uint8_array[] = {0x15, 0x25, 0x32, 0x00, 0x52, 0xFD};
uint8_t* Buffer = temp_uint8_array;
And now :
Buffer = {0x15, 0x25, 0x32};
So I understand that my data is cut because of 0x00, is there a solution ?
As I have access to the size of tha datas to be copied I tried to use
memcpy(Buffer, &temp_uint8_array, local_length);
But it does not work
uint8_t temp_uint8_array = is not an array but a syntax error.
So I understand that my data is cut because of 0x00
No it isn't. If you try to interpret the data as a string, then the 0x00 will get treated as a null terminator. But this is not a string.
is there a solution
Don't treat raw data as a string? memcpy will work perfectly fine.
But it does not work
What doesn't work? What is local_length and where did you get it from?
The memcpy isn’t correct :
memcpy(Buffer, &temp_uint8_array, …
As temp_uint8_array is an array then you should not prefix it with & :
memcpy(Buffer, temp_uint8_array,…
Buffer is pointing to temp_iint8_array so the memcpy does nothing but erasing bytes in the same memory location. You IDE might consider that uint8 array may be handled as char string and display contents until 0x00.
Ok so actually it was my variable viewer in my IDE that cuts my variable value so I can only see the value until the 0x00 but in memory the data has been copied.
Maybe it was interpreted as string so it display the value until the null terminator.
To know that I must have check what was going on in my mcu memory with th debugger.
I have a number of arrays all of different sizes that I have stored in flash memory.
I can access single array entries with
byte j = pgm_read_byte(&(array[x]));
What I want to do is to pass the array from the flash memory as an argument to a function. I have tried giving a pointer to the array, as an argument but this gives a compilation error:
void callPGM2(byte arr_size, byte *arr) {
..
..
}
ptr2 = &pgm_read_byte(&(array_1[0]));
callPGM2(5, &ptr2);
Can full arrays be passed from flash memory as function arguments?
There's no way to directly pass a pointer to PROGMEM variables, because of the AVR's Harvard architecture with 2 address spaces that C has no way to straightforwardly express - You need to temporarily copy the memory to RAM using memcpy_P, for example.
And you want to learn about the functions provided in the pgmspace library. It holds equivalents to a number of C functions like strcmp, that allow you to work with a constant argument in program space.
To copy a string from flash memory to RAM
#include<avr/pgmspace.h>
const byte Update_1[5] PROGMEM = {0x01, 0xB2, 0x02, 0xFF, 0xFF};
byte buffer2[5];
setup {
memcpy_P (buffer2, &(Update_1),5);
}
In stm32 firmware I declare non static array:
uint8_t bufCan[8] = {0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31 };
And get it corrupted ( filled with another data) when I call function with this array as argument. While debugging I observe that this array is placed at address 0x20007fc8. RAM size is from 0x20000000 to 0x20008000. So this array is placed in stack and get corrupted.
This is not happens if I declare this array as static. In this case compiler place it array at address 0x20000234.
So what is issue of array corrupts? This should not occur even if I declare array as non static!
his is not happens if I declare this array as static
And get it corrupted ( filled with another data) when I call function with this array as argument.
I assume your code looks something like this
int another_function(int8_t *array){
//Your routine with array
}
int yourfunction(){
int8_t bufCan[8] = {0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31 };
another_function(bufCan);
}
So when you access array in another_function you find it is corrupted. But declaring this array as static solves the problem. Therefore we can assume the prblem is with the stack.
Few things may happen, first is dynamic memory allocation, let me assume that prior to calling another_function or within anoter_function body you have used dynamic memory allocator malloc(). This could lead to corrupted stack.
Another option is that you have wrote something to another array on stack and crossed its boundary which led to corrupted array again.
If you can update your post with code i can provide a more detailed answer to it.
I have a function that takes in pointers to different arrays which can look like this:
unsigned char *arr[] = {0x34, 0x10, 0x3f, 0x00, 0x00 }
I want to know how many elements (bytes) are in each array my function is getting. For example, I need a way to find that this array has 5 bytes. I pass this into a function to print the values of the array. Sizeof(arr) doesn't give me the right results.
Unless you're using a convention like "the array is null-terminated" (like C strings nominally are) you can't determine the size of the array at run-time. All you have at that point is a pointer.
This is C. and in C this does not exist. You have to somewhere remember /store the number of elements.
sizeof(arr)/sizeof(unsigned char*)
you can macro-ize this fairly easily as
#define ARRAY_LENGTH(_array_) (sizeof(_array_) / sizeof(_array_[0])
BTW, this will only work if you use it in the same scope as the array. This will not work if you pass the array to a function (and the array degrades into a pointer). If you pass the array to a function, you'll need to pass the number elements, and possibly the size of each element.