Raspberry Pi 3 bare metal: unexpected behaviour from arrays and switch statements - c

I currently have a simple program that sets up a framebuffer that can be written to.
I am encountering behaviour where values stored i arrays, once retrieved, come back as seemingly random values, with no relation to the originals.
I have also noticed some similarly strange and.unexpected behaviour from switch statements - I suspect this has something to do with how both arrays and switch statements are statically allocated in memory.
As an example, here I have some code that should draw a hardcoded number, followed by 7 other hardcoded numbers that have been stored in an array:
unsigned int cols[7] = { 0xFFFF0000, 0xFFFF7F00, 0xFFFFFF00, 0xFF00FF00, 0xFF0000FF, 0xFF4B0082, 0xFF9400D3 };
drawNum(&display, 0x1234ABCD);
for (int i=0; i<7; i++)
drawNum(&display, cols[i]);
The first drawNum() call with the hardcoded value works fine, but all of the calls with array accesses give seemingly random results.
Assigning the array values at runtime doesn't have this problem, like so:
unsigned int cols[7];
cols[0] = 0xFFFF0000;
cols[1] = 0xFFFF7F00;
cols[2] = 0xFFFFFF00;
cols[3] = 0xFF00FF00;
cols[4] = 0xFF0000FF;
cols[5] = 0xFF4B0082;
cols[6] = 0xFF9400D3;
drawNum(&display, 0x1234ABCD);
drawNum(&display, (int)cols);
for (int i=0; i<7; i++)
drawNum(&display, cols[i]);
I've also experienced similarly unpredictable behaviour when returning values from switch statements.
I cannot say for sure, but this leads me to believe that this is a problem with the compiler or linker being used - I am using arm-none-eabi.

Just a shot in the dark, but you may want to try a different value in your array where the highest bit is 0 instead of 1 like in your hardcoded example.
unsigned int cols[7] = { 0x7FFF0000, 0x7FFF7F00, 0x7FFFFF00, 0x7F00FF00, 0x7F0000FF, 0x7F4B0082, 0x7F9400D3 };
This is assuming that drawNum takes an int instead of an unsigned int. You might just have a conversion problem. Without seeing what drawNum does it's hard to say.

And here my shot in the dark. You have a memory overwrite anywhere and this kills cols[]. If you move the variable from global scope to local scope the outcome varies. Add some 'detector' code:
volatile unsigned int cols[7] = { 0xFFFF0000, 0xFFFF7F00, 0xFFFFFF00, 0xFF00FF00, 0xFF0000FF, 0xFF4B0082, 0xFF9400D3 };
drawNum(&display, 0x1234ABCD);
//test code
drawNum(&display, cols[0]==0xFFFF0000);
drawNum(&display, cols[1]==0xFFFF7F00);
for (int i=0; i<7; i++)
drawNum(&display, cols[i]);
//test code
drawNum(&display, cols[0]==0xFFFF0000);
drawNum(&display, cols[1]==0xFFFF7F00);
I added the volatile keyword to avoid optimizations by the compiler. It shouldn't mask away the observed wrong output.

Related

Another invert char array in C

That code will run on a payment device (POS). I have to use legacy C (not C# or C++) for that purpose.
I am trying to prepare a simple Mifare card read/write software data. Below document is my reference and I am trying to achieve what is on page 9, 8.6.2.1 Value blocks explains.
http://www.nxp.com/documents/data_sheet/MF1S50YYX_V1.pdf
I just know very basics of C. All my searches in The Internet have failed. According to document:
1- There is integer variable with value of 1234567.
2- There is char array[4] which should have hex of above value which is 0x0012D687
3- I am supposed to invert that char array[4] and reach value of 0xFFED2978
I need to do some other things but I have stuck in number 3 above. What I have tried lastly is
int value = 1234567;
char valuebuffer[4];
char invertbuffer[4];
sprintf(valuebuffer, "%04x", value);
for(i = 0; i < sizeof(valuebuffer); i++ )
{
invertbuffer[i] ^= valuebuffer[i];
}
When I print, I read some other value in invertbuffer and not 0xFFED2978
Seems like you're making it more complicated than it needs to be. You can do the binary inversion on the int variable rather than messing around with individual bytes.
int value = 1234567;
int inverted= ~ value;
printf("%x\n",value);
printf("%x\n",inverted);
gives you output of
12d687
ffed2978
First of all, you must use the types from stdint.h and not char, because the latter has implementation-defined signedness and is therefore overall unsuitable for holding raw binary data.
With that sorted, you can use a union for maximum flexibility:
#include <stdint.h>
#include <stdio.h>
typedef union
{
uint32_t u32;
uint8_t u8 [4];
} uint32_union_t;
int main (void)
{
uint32_union_t x;
x.u32 = 1234567;
for(size_t i=0; i<4; i++)
{
printf("%X ", x.u8[i]);
}
printf("\n");
x.u32 = ~x.u32;
for(size_t i=0; i<4; i++)
{
printf("%X ", x.u8[i]);
}
printf("\n");
}
Notably, the access order of the u8 is endianess dependent. This might be handy when dealing with something like RFID, which doesn't necessarily have the same network endianess as your MCU.

Cache optimization of C loop: Why doesn't this work?

I'm trying to duplicate the first piece of code on this article
http://www.drdobbs.com/parallel/cache-friendly-code-solving-manycores-ne/240012736
Namely:
static volatile int array[Size];
static void test_function(void)
{
for (int i = 0; i < Iterations; i++)
for (int x = 0; x < Size; x++)
array[x]++;
}
I'm running on OS X with an Ivy Bridge processor, and therefore have 64KiB of L1 cache. However, no matter how much I change around the array size, it takes the same amount of time. Here's my code:
#define ARRAY_SIZE 16 * 1024
#define NUM_ITERATIONS 200000
volatile int array[ARRAY_SIZE];
int main(int argc, const char * argv[])
{
for (int i = 0; i < NUM_ITERATIONS; i++)
for (int x = 0; x < ARRAY_SIZE; x++)
array[x]++;
return 0;
}
Now, according to the logic suggested by the article, array should be 64KiB and utilize all my L1 cache. However, I've tried this with many difference combinations of ARRAY_SIZE (up to 160 * 1024), setting NUM_ITERATIONS accordingly, but every combination about takes the same amount of time.
I'm using gcc -o cachetest cachetest.c to compile, with no other options. Is there some kind of optimization going on that I don't know about, even though volatile is used? Or are there so many parallel processes and context switching that I can't even tell? What's going on here? I'm so confused.
Thanks SO!
There are 2 things:
Compiler may do some default optimization to your code
Your code does not use array in any other code/functions, it only increment the array value inside loop, so compiler may optimize it more by changing your program to do nothing (just return 0), which is still correct.
I recommend to:
Add more code inside the loop so the compiler will not eliminate your code, for example: printf the array value, or add the array value to a sum variable then print the sum variable at the end of the loop.
Turn off all compiler optimization when compiling by using -O0 option.
Check the assembly file of the code generated by compiler by using -S option

Strange behaviour when casting array char to array short

I have 2 array: the first one is 8 unsigned char, and the second one is 4 unsigned short, for some algorithm compatibility issue i need to use the short array with the values of the char array, to do so i'm doing a loop
j = 0;
for(i=0; i<8; i+=2)
{
short_array[j] = *(unsigned short*) (char_array + i);
j++;
}
Everything work fine here, but in some previous attempt to build this up, i've tried the following (this is obviously not the correct answer)
j = 0;
for(i=0; i<8; i+=2)
{
short_array[j] = (unsigned short*) *(&(char_array + i));
j++;
}
QUESTION:
Assuming the following char_array = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88}
When I do the first one short_array = {0x1122, 0x3344, 0x5566, 0x7788}
But when I do the second one, short_array = {0x3344, 0x5566, 0x7788, ???} (where ??? is undefined since it is a value in the memory and may change).
Can you explain why this i happening?
PS: My compiler suite is C251 from Keil
I've compared the 2 solutions (even if the second is not a working one), and this is definitly a compiler issue, first of all the compiler shouldn't let me compile &(char_array + i) , then I've find out (when inspecting the assembly code) that the char_array is incremented before accessing it in the loop for the second case; and the increment is made after reading the variable in the first case (the correct one). There seem to be no more explanation than a compiler implementation problem...
I would suggest to manually read out each element in your char array and build each pair of chars into a short. I know that there are probably faster methods, but you are implicitly stepping over the bounds of the type you have specific in the char array otherwise. Also, I would claim that my version is slightly easier to read in terms of your intent, albeit more kludgy.
That is, something like this:
IGNORE THIS FIRST CODE BLOCK... THIS IS WHAT HAPPENS WHEN I DON'T SLEEP!
j=0;
uint16_t temp; // recommend to use these types for portability
for(i=0; i<8; i+=2) {
temp = 0x0000;
temp += (uint16_t)(char_array[i] << 8);
temp += (uint16_t)(char_array[i+1]);
short_array[j] = temp;
j++;
}
Also, here's a faster method I came up with after thinking about the problem a bit more, and giving myself a well-deserved self-imposed code review.
j=0;
for(i=0; i<8; i+=2) {
short_array[j] = (char_array[i] << 8) | char_array[i+1]; // use bitwise operations
j++;
}

Declared array of size [x][y] and another array with size [y-1]

I am using Code::Blocks 10.05, and the GNU GCC Compiler.
Basically, I ran into a really strange (and for me, inexplicable) issue that arises when trying to initialize an array outside it's declared size. In words, it's this:
*There is a declared array of size [x][y].
*There is another declared array with size [y-1].
The issue comes up when trying to put values into this second, size [y-1] array, outside of the [y-1] size. When this is attempted, the first array [x][y] will no longer maintain all of its values. I simply don't understand why breaking (or attempting to break) one array would affect the contents of the other. Here is some sample code to see it happening (it is in the broken format. To see the issue vanish, simply change array2[4] to array2[5] (thus eliminating what I have pinpointed to be the problem).
#include <stdio.h>
int main(void)
{
//Declare the array/indices
char array[10][5];
int array2[4]; //to see it work (and verify the issue), change 4 to 5
int i, j;
//Set up use of an input text file to fill the array
FILE *ifp;
ifp = fopen("input.txt", "r");
//Fill the array
for (i = 0; i <= 9; i++)
{
for (j = 0; j <= 5; j++)
{
fscanf(ifp, "%c", &array[i][j]);
//printf("[%d][%d] = %c\n", i, j, array[i][j]);
}
}
for (j = 4; j >= 0; j--)
{
for (i = 0; i <= 9; i++)
{
printf("[%d][%d] = %c\n", i, j, array[i][j]);
}
//PROBLEM LINE*************
array2[j] = 5;
}
fclose(ifp);
return 0;
}
So does anyone know how or why this happens?
Because when you write outside of an array bounds, C lets you. You're just writing to somewhere else in the program.
C is known as the lowest level high level language. To understand what "low level" means, remember that each of these variables you have created you can think of as living in physical memory. An array of integers of length 16 might occupy 64 bytes if integers are size 4. Perhaps they occupy bytes 100-163 (unlikely but I'm not going to make up realistic numbers, also these are usually better thought of in hexadecimal). What occupies byte 164? Maybe another variable in your program. What happens if you write to one past your array of 16 integers? well, it might write to that byte.
C lets you do this. Why? If you can't think of any answers, then maybe you should switch languages. I'm not being pedantic - if this doesn't benefit you then you might want to program in a language in which it is a little harder for you to make weird mistakes like this. But reasons include:
It's faster and smaller. Adding bounds checking takes time and space, so if you're writing code for a microprocessor, or writing a JIT compiler, speed and size really do matter a lot.
If you want to understand machine architecture and go into hardware, e.g. if you're a student, it's a good gateway from programming into OS/hardware/electrical engineering. And much of computer science.
Being close to machine code, it's standard in a way that many other languages and systems have to, or can easily, support some degree of compatibility with.
Other reasons that I would be able to give if I ever actually had to work this close to the machine code.
The moral is: In C, be very careful. You must check your own array bounds. You must clean up your own memory. If you don't, your program often won't crash but will start just doing really weird things without telling you where or why.
for (j = 0; j <= 5; j++)
should be
for (j = 0; j <= 4; j++)
and array2 max index is 3 so
array2[j] = 5;
is also going to be a problem when j == 4.
C array indexes start from 0. So an [X] array valid indexes are from 0 to X-1, thus you get X elements in total.
You should use the < operator, instead of <=, in order to show the same number in both the array declaration [X] and in the expression < X. For instance
int array[10];
...
for (i=0 ; i < 10 ; ++i) ... // instead of `<= 9`
This is less error prone.
If you're outside the bounds of one array, there's always a possibility you'll be inside the bounds of the other.
array2[j] = 5; - This is your problem of overflow.
for (j = 0; j <= 5; j++) - This is also a problem of overflow. Here also you are trying to access 5th index, where you can access only 0th to 4th index.
In the process memory, while calling each function one activation records will be created to keep all the local variables of the function and also it will have some more memory to store the called function address location also. In your function four local variables are there, array, array2, i and j. All these four will be aligned in an order. So if overflow happens it will first tries to overwrite in the variable declared above or below which depends on architecture. If overflow happens for more bytes then it may corrupt the entire stack itself by overwriting some of the local variables of the called functions. This may leads to crash also, Sometimes it may not but it will behave indifferently as you are facing now.

Syntax error while copying an multidimensional array to another in C

We are programming a ST269 microcontroller which has two IR distance sensors. To calibrate these sensors we made one table for each sensor with the distance we measured and the corresponding value we get from the ADC.
Now we want to use one function to approximate the values in between. So we defined two two-dimensional arrays (one for each sensor) as global variables. In our function we then want to copy the one array we want to work with to a working array and approximate our values.
So here's the code:
...
unsigned int ir_werte_re[][] = {
{8,553},
...
{83,133}
};
unsigned int ir_werte_li[][] = {
{8,566},
...
{83,147}
};
...
unsigned int geradenaproximation(unsigned int messwert, unsigned int seite)
{
unsigned int working_array[16][16];
unsigned int i = 0;
if (seite == 0) {
for (i = 0; i < sizeof(working_array); i++) {
working_array[i][0] = ir_werte_li[i][0];
i++;
}
}
else {
for (i = 0; i < sizeof(working_array); i++) {
working_array[i][0] = ir_werte_re[i][0];
i++;
}
}
i = 0;
unsigned int y1 = 0;
unsigned int x1 = 0;
...
}
This code is in a file called sensor.c. We didn't write anything about our global arrays in the sensor.h should we? The sensor.h of course is included in our main.c and there the function is called.
We also tried to copy the arrays via
memcpy(working_array, ir_werte_li, sizeof(working_array));
And in every way we do this we get a
syntax error near unsigned
in the line where we're declaring
unsigned int y1 = 0;
and I'm pretty sure that there is no syntax error in this line : )
The last time I spend coding in C is a few years away so I'm not sure if the way we try to do this is good. Perhaps we can solve this by using a pointer instead of really copying the array or something. So please help me out I'll appreciate your bits on this.
In C (pre-C99), all variable definitions must appear at the top of the current block scope.

Resources