I am working on the S12G processor (9s12g128 specificaly) and am going to be doing 2D and 3D table interpolations.
I have my table interpolation function working by using structs:
typedef struct{
float *X;
float *Y;
}Table2D;
typedef struct{
float *X;
float *Y;
float *Table;
}Table3D;
Now I want to move my tables into absolute addresses in EEPROM so they can be reprogrammed on the fly
I have a number of predefined tables, but their size and values will be flexible.
I am trying to structure my code thusly:
float x[5] = {3300, 3400, 3500, 3700, 4000} @ *some_address*
float y[5] = {2150, 1750, 1450, 1300, 1200}; @ *address continued from x*
float *x_pntr = x @ *defined address*
float *y_pntr = y @ *defined address*
Table2D SlipPower ={
*x_pntr,
*y_pntr
};
so if the sized of the table chages, then the addresses of where x and y start can change, but the pointers to those addresses stay in the same place
But I can still use the structures I created before so
temp = table->X[index]; // an example from my interpolation funtion
still works
Original Attachment has been moved to: tables.h.zip
Original Attachment has been moved to: control_gains.h.zip
Original Attachment has been moved to: tables.c.zip
Why not just let the compiler and linker place your tables in EEPROM, instead of trying to force them to specific adresses? E.g.:
#pragma DATA_SEG EEPROM_DATA
float x[5];
float y[5];
#pragma DATA_SEG DEFAULT
in the prm-file's PLACEMENT-section:
EEPROM_DATA INTO EEPROM;
/Sten
Sten,
The reason is the tables will need to vary in size:
if I start with a x[5], y[5] table then y[] starts at adress x+5, but if I need to reflash with a x[6] y[6] table then at adress x+5 is x[5], not y[1].
If you look at my code the interpolation functions measure the size of the table e.g. while(&x[x_size] < &y[0]) x_size++
So I am trying to set up a predefined location in memory that is a pointer to the start of x[] and another pointer to the start of y[] that will be reflashed with a new value if the size of the tables change. If the size of a table changes then where y[] starts will shift as will every table that comes after.
IMO it is a bad trick producing not portable and not clean code, which depends on linking order and data alignment.
It is better to use sizeof() to determine size of an array.
This is not a smart at all. It wastes a lot of CPU cycles to determine size of array. Instead you should use sizeof(). Even if you want to export array declaration, which wil make sizeof() unable to determine size of array with undefined dimensions, you still can have something like this:
// h-file
extern const int myarray[];
extern const unsigned int myarraysizeb;
extern const unsigned int myarraysize;
// c-file
const int myarray[] = {1,2,3,4};
const int myarraysizeb = sizeof(myarray); // size, bytes
const int myarraysize = sizeof(myarray)/sizeof(myarray[0]); // size, elements
Ed,
Thank you for the suggestion, however:
1- I understand the way I have it coded is using more cycles to compute but I have the resourses to do it and I need to do it that way because:
2- when all said and done I will not be be creating tables in code, but will have pointers to where the tables start, which will run upto the start of the next table so that I can ISP a new tables into the EEPROM and adjust the starting addresses (based on table sizes) while the micro is still running
it will look something like this (not C compliant code, but to get the idea):
*table1_pnt @0x0400
*table2_pnt @0x4002
struct table2D{
table1_pnt;
table2_pnt;
}table
for(size=1; &table->(*table1_pntr)[size] < table->(*table2_pnt);size++){} /* read size of table in x direction */
in this example the table pointers are pointing to the start of the tables, and when I develope the table that will give me my table size so I can load the table and at the same time load the address into the pointer
But you can ISP not only pointers and data, but also sizes of your data, isn't it. Maybe it's just micro or milliWatts*second, but still some CPU cycles and power waster. It is always better to use compile time constants instead of calculating the same at runtime.
Unfortunately it is not trivial to make what you do portable, other targets will have different float sizes or struct / array alignment. In case of Codewarrior smartlinker you can rely on optimization out of unused variables to determine array size. Dummy arrays will be optimized out. Hope it will give you some ideas
#define data1 {3300, 3400, 3500, 3700, 4000}
#define data2 {2150, 1750, 1450, 1300, 1200}
float __dummy1[] = data1;
float __dummy2[] = data2;
const struct {
float *t1ptr;
float *t2ptr;
int t1size;
int t2size;
float t1[sizeof(__dummy1)/sizeof(__dummy1[0])];
float t2[sizeof(__dummy2)/sizeof(__dummy2[0])];
} mydata = {
mydata.t1,
mydata.t2,
sizeof(__dummy1)/sizeof(__dummy1[0]),
sizeof(__dummy2)/sizeof(__dummy2[0]),
data1,
data2
};
Ed,
I have modified the code for measuring the size of the table to speed up the process:
x_size = (&Y[0] - &X[0]) / sizeof(X[0];
However that still doesn't answer my original question, when trying:
float Torque_x[13] @ 0x460 = {0, 250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000}; // Fan Speed
float Torque_y[13] @ 0x494 = {0, 2, 8, 20, 35, 55, 79, 108, 140, 177, 220, 265, 317}; // Max Variable Fan Speed
void *T_x @ 0x426 = Torque_x;
void *T_y @ 0x428 = Torque_y;
Table2D TorqueCurve={
(float*)*T_x,
(float*)*T_y
};
gives me C1806 errors (illegal cast operation) in the struct definition.
What is the proper way to do this?
It's because of extra star here
(float*)*T_x
I wish to take the value 0x460, put it into a variable and then typecast the variable as a float*
so:
float Torque_x[13] @ 0x460 = {0, 250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000}; // Fan Speed
float Torque_y[13] @ 0x494 = {0, 2, 8, 20, 35, 55, 79, 108, 140, 177, 220, 265, 317}; // Max Variable Fan Speed
variable X @ 0x426 = &Torque_x[0];
variable Y@ 0x428 = &Torque_y[0];
Table2D TorqueCurve={
(float*) X, // float* to address 0x460
(float*) Y // float* to address 0x494
};
So why don't you
float Torque_x[13] @ 0x460 = {0, 250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000}; // Fan Speed
float Torque_y[13] @ 0x494 = {0, 2, 8, 20, 35, 55, 79, 108, 140, 177, 220, 265, 317}; // Max Variable Fan Speed
Table2D TorqueCurve={
&Torque_x[0],
&Torque_y[0]
};
Ed,
Thank you, I was already doing that, but your comment helped me realize that I can locate the Tabel2D structure at the address I need:
float Torque_x[13] @ 0x460 = {0, 250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000}; // Fan Speed
float Torque_y[13] @ 0x494 = {0, 2, 8, 20, 35, 55, 79, 108, 140, 177, 220, 265, 317}; // Max Variable Fan Speed
Table2D TorqueCurve @ 0x422 ={
Torque_x,
Torque_y
};