#include inside a struct declaration? What the hell?
I'm not a master in C programming, but to me it looks wrong?
Why don't you do it in the correct way, declaring the arrays properly?
At least use a define:
#define IMAGE1_DATA \
0x35, 9x44, 0x11, 0x42, 0x76, \
111, 104, 84, 10, 84, 92, \
'l', 'i', 'n', 'e', '3', \
You need add "\" to make it multiline \
This is the last line (No "\")
With that, you could simply type "IMAGE1_DATA" in the initialization array.
But it's not a tidy or proper way to do that...
the code below does not initialise the array (all the values are just initialised to 0x00) in the globally defined structure. Any idea why?
Since the code most certainly does initialize the array in a hosted environment (I checked), the reason is most likely due to the environment you are using.
It may be, that XC32 2.5 does not initialize data structures defined in RAM properly. (In e.g. Arduino, these are initialized by storing a copy of the initialized object in Flash, and copying initialized objects to RAM during startup.) Lessee, okay, an XC32 manual I found on the net has a section 12.3.4 about this. It says the compiler should do this properly; it actually uses initialization records, for this. So the underlying problem is unclear.
However, if the image data is not modified during run time, you really should put that part of the data in Flash/ROM. According to that random XC32 manual,
const suffices for this.
So, what I would recommend for you, is to use something like the following instead:
typedef struct {
const uint8_t *data[2];
uint32_t ui32IndxOfFirstByteOfCurrentlyPrintingLine;
bool bIndxImageBeingPrinted;
} image_spec;
const uint8_t imageTest_data[] = {
#include"TestImage_1.txt"
};
image_spec imageTest = {
.data = { imageTest_data, imageTest_data },
.ui32IndxOfFirstByteOfCurrentlyPrintingLine = 0
.bIndxImageBeingPrinted = 0,
};
This way, you only use RAM for the two
pointers to the data, and the two other members, and the actual image data is in Flash. (The XC32 manual said you have an unified address space, where both RAM and Flash are accessible using the same instructions, just at different addresses, so this should work without issues.)
In general, when writing code for resource-constrained embedded targets, you do need to consider what data you can keep in Flash/ROM, and what needs to be in RAM because you wish to be able to manipulate it. Above, instead of incorporating the data into the image definition, we use a pointer to the data, so that the data can be anywhere else (RAM, Flash, wherever, since we have an unified address space). This also means the data appears only once in Flash, so actually
saves you resources there too.
I'm not telling you anything new, for sure you know far more more than me about C.
But this code hurts my eyes!
It's not about the fact he's including the txt file, it's about WHAT he's trying to achieve with it.
The txt file has just comma separated values, so how on earth would this work? (ignoring the fact it's being declared twice)
.arrImage_data =
{{
#include"TestImage_1.txt"
},{
#include"TestImage_1.txt"
}},
#include simply tells the compiler to search for resources in that file following the line where it was declared.
But that initialization actually does this, #include does absolutely nothing inside it:
.arrImage_data =
{{
},{
}},
It's like inserting any random preprocessor stuff:
.arrImage_data =
{{
#define This_does_nothing
},{
#define Neither_this
}},
Actually, it's strange that the compiler isn't dropping any error, because a random text not following any syntax would definitely shoudl fail.
Perhabs the compiler is ignoring it due not being a standard C file extension (.c, or .h).
David Alfa,
#include, by very definition, includes another file. Fancy copy-paste, ranging from very crude automated copypaste on old compilers, to a bit fancier which can track file names and line numbers to show errors/warnings properly; but still just a copy-paste).
The most typical use a beginner sees, it's used to include the headers of libraries (the actual binaries to be linked later). For this use, it's quite a crappy tool but neither C nor C++ has any better, so #include it has to be. Basically, the compiler copy pastes the declarations (but not definitions or contents, because they are not in the .h files) of all library functions every time to your code (compilation unit). If anything, this standard use would hurt the eye of someone who has seen something better in other languages.
Example shown here is different: this is the most proper use case for a file "copy paste" type of include. You have some externally autogenerated data. You don't want to manually copy-paste every time that data changes, which could be even for every compilation. You don't want to have the ugly thousand-line hex blob visible in the code because it tells you nothing. So you #include it; make the compiler copy-paste it automagically for you. This would be the most appropriate use case for #include, it should not hurt your eyes.
Preprocessor commands (starting with #) are all very simple, like automated text processing features. It's helpful to understand this.
@ricko_uk:
Please check if a simpler/test version of this works in your environment. I recommend you do this as a separate project. For example,
#include <stdint.h>
typedef struct {
uint32_t a;
int8_t b;
uint8_t c[2][64];
} data_struct;
data_struct test_data_struct = {
.a = 0xdeadbeef,
.b = -42,
.c = { {
1, 2, 3, 4, 5, 6, 7, 8,
-1,-2,-3,-4,-5,-6,-7,-8,
32,33,34,35,36,37,38,39,
47,46,45,44,43,42,41,40,
16,17,18,19,20,21,22,23,
24,25,26,27,28,29,30,31,
55,54,53,52,51,50,49,48,
56,57,58,59,60,61,62,63,
}, {
1,63,62,61,60,59,58,57,
56, 1,54,53,52,51,50,49,
48,47, 1,45,44,43,42,41,
40,39,38, 1,36,35,34,33,
32,31,30,29, 1,27,26,25,
24,23,22,21,20, 1,18,17,
16,15,14,13,12,11, 1, 9,
8, 7, 6, 5, 4, 3, 2, 1,
} },
};
The sum of test_data_struct.c[0] is 3944 (104, if you sum as uint8_t), and the sum of test_data_struct.c[1] is 1828 (36, if you use uint8_t), if you want to use a test loop to verify all the data is still there.
If you see at runtime zeroes here, then you have a minimal, complete verifiable example or MCVE, as needed for proper bug reports.
If this works correctly, then I'd expand the size, duplicating the shown data or using random data, up to around the same size as in your proper project. If it suddenly stops working, it means that your environment has a limit of how much it can initialize data. Perhaps it is running out of Flash/ROM, or perhaps it is some configurable limit.
It this works correctly as a separate example, but fails in your own project, then your project has a serious bug where something clears the memory after it has been initialized; most likely, your own code does an equivalent of memset(pointer, 0, size) where pointer, size, or both are bogus. A particular case I've seen is when supplied size is negative: since the parameter is of type size_t, the size is cast to an unsigned type, leading to a very large size.
Just a point, XC32 is just GCC for MIPS. It shouldn't in itself do anything weird or special.
Now of course, initializers for global data are put in the .data section, and the copy in the actual objects in RAM is done in the startup code. The startup code for your particular project could be worth taking a look at - although, if it didn't copy initializers properly, absolutely no initializer in your code would work. Thus, something as simple as a global like: "int n = 5;" would not hold the value '5' either... which can be checked very easily.
Note that - even if you still should find out what is wrong here - you can try declaring your variable with a 'const' qualifier, if it's not going to be modified. Then it should be read directly from program memory and not copied in RAM. If that works, then you have an additional clue as to what could be wrong. (And BTW, if said variable is not going to be modified in your code, you definitely *should* declare it 'const' anyway.)