Why are my variables in my struct changing? - c

I am trying to set up an SD card on an Intel Board D2000 Quark. The problem, I am encountering is that my variables in my struct change at a certain point in the program. I figured out when the variables are changing but I do not have an idea how to fix it.
The reason I am using C instead of C++ is that the compiler of Intel Microcontrollers Studio does not let my use C++.
Below, I copied some of the relevant code.
SD* sdCard;
uint8_t readData(uint32_t block, uint16_t offset, uint16_t count, uint8_t* dst){
if(count == 0){
return true;
}
if((count + offset) > 512){
goto fail;
}
if(!sdCard->inBlock_ || block != sdCard->block_ || offset < sdCard->offset_){
sdCard->block_ = block;
if(sdCard->type_ != SD_CARD_TYPE_SDHC){
block <<=9;
}
uint8_t result = sendCommand(CMD17, block);
if(result){
goto fail;
}
if(!waitStartBlock()){
goto fail;
}
sdCard->offset_ = 0;
sdCard->inBlock_ = 1;
}
for(; sdCard->offset_ < offset; sdCard->offset_++){
spiRecieve();
}
for(uint16_t i = 0; i < count; i++){
dst[i] = spiRecieve();
}
sdCard->offset_ += count;
if(!sdCard->partialBlockRead_ || sdCard->offset_ >= 512){
readEnd();
}
QM_PUTS("RD FINISH");
return true;
fail:
QM_PUTS("RD FAIL");
return false;}
The moment the variables change is sdCard->block_ = block;. First it is a certain value. After this statement the value is 0xFFFFFFFF; This happens to every variable in the struct.
My struct looks like this:
typedef struct SDcard{
uint32_t block_ ;
uint8_t errorCode_;
uint8_t inBlock_;
uint16_t offset_;
uint8_t partialBlockRead_;
uint8_t status_;
uint8_t type_;
}SD;
Update for the comments:
This is my temporary main:
SD sdCard;
int main(void)
{
if(!SDInit(&sdCard)){
QM_PRINTF("ERROR1\n");
}
while(1){}
}
If anyone knows a solution or has some questions, please let me know.

You are improperly initializing sdCard. Currently you are assigning the value of sdCard to be a pointer to its own location on the stack. Instead, do SDInit(malloc(sizeof(SD)));.
Personally, I would not even have that initialization function. I would just do SD * sdCard = malloc(sizeof(SD));
EDIT: In response to Peter's point, you could also do this and ignore the instantiation function:
SD sdCard;

Related

MPU6050 motion driver library function call cause hardfault exception

Hi I'm try to use mpu6050 on my stm32 project.
I copy the motion driver library from SparkFun_MPU-9250-DMP_Arduino_Library and replace arduino function like arduino_i2c_write to stm32 write function. The replace part work fine. The stm32 board did write bytes into the imu and read from it.
However, when I try to setup the dmp funtion and use the mpu_load_firmware function, I encouter a weird situation.
int mpu_load_firmware(unsigned short length, const unsigned char *firmware,
unsigned short start_addr, unsigned short sample_rate)
{
unsigned short ii;
unsigned short this_write;
/* Must divide evenly into st.hw->bank_size to avoid bank crossings. */
#define LOAD_CHUNK (16)
unsigned char cur[LOAD_CHUNK], tmp[2];
if (st.chip_cfg.dmp_loaded)
/* DMP should only be loaded once. */
return -1;
if (!firmware)
return -1;
for (ii = 0; ii < length; ii += this_write) {
this_write = min(LOAD_CHUNK, length - ii);
if (mpu_write_mem(ii, this_write, (unsigned char*)&(firmware[ii])))
return -1;
if (mpu_read_mem(ii, this_write, cur))
return -1;
if (memcmp(firmware+ii, cur, this_write))
return -2;
}
/* Set program start address. */
tmp[0] = start_addr >> 8;
tmp[1] = start_addr & 0xFF;
if (i2c_write(st.hw->addr, st.reg->prgm_start_h, 2, tmp))
return -1;
st.chip_cfg.dmp_loaded = 1;
st.chip_cfg.dmp_sample_rate = sample_rate;
return 0;
}
When the code run to the line if (mpu_write_mem(ii, this_write, (unsigned char*)&(firmware[ii]))), it cause a hardfault. And I found out that the code cannnot call the mpu_write_mem function porperly. When I start to step in the function, the hardfault exception immediately occurred. I cannot figure it out what cause the exception and how to fix it.
I've checked the pointer, &(firmware[ii]), address, it looks just fine. But the weired thing is that in the mpu_write_mem function, the argument value all differ from the mpu_load_firmware function.(mem_addr != ii, length != this_write, ...) I'm not sure if this cause the exception or the other way around.
Can anyone give me some idea? Thank you very much ~~
Here is the mpu_write_mem function, both function are in the inv_mpu.c file
int mpu_write_mem(unsigned short mem_addr, unsigned short length,
unsigned char *data)
{
unsigned char tmp[2];
if (!data)
return -1;
if (!st.chip_cfg.sensors)
return -1;
tmp[0] = (unsigned char)(mem_addr >> 8);
tmp[1] = (unsigned char)(mem_addr & 0xFF);
/* Check bank boundaries. */
if (tmp[1] + length > st.hw->bank_size)
return -1;
if (i2c_write(st.hw->addr, st.reg->bank_sel, 2, tmp))
return -1;
if (i2c_write(st.hw->addr, st.reg->mem_r_w, length, data))
return -1;
return 0;
}

Can't pass array stored in .h file to C function

I am trying to implement a driver for a sensor(ST-VL53L5CX) on an AVR MCU (AVR128DB48).
The driver comes prewritten, with a few I2C functions for the user to fill in
(So the sensor can be implemented on different platforms).
The driver is made up of multiple c files. API.c, API.h, Buffers.h, Platform.c and Platform.h.
The firmware for the sensor is stored in the Buffers.h file as an array. e.g:
const uint8_t Sensor_Firmware[] = {0x05,...,0x01};
This needs to be written to the sensor.
To do this, I call a function I have written to write multiple bytes to the I2C line:
uint8_t WrMulti(VL53L5CX_Platform *p_platform,uint16_t
RegisterAdress,uint8_t *p_values,uint32_t size)
{
uint8_t count = 0;
uint32_t new_size = size + 2;
//Split Register address into 2 bytes
uint8_t temp0 = (uint8_t)((RegisterAdress & 0xFF00)>> 8);
uint8_t temp1 = (uint8_t)(RegisterAdress & 0x00FF);
//Create new array to hold Register Address and p_values
uint8_t temp_array[new_size] ;
for (int i = 0; i <new_size; i++)
{
temp_array[i] = 0;
}
//Fill temp_array with register address and p_values
temp_array[0] = temp0;
temp_array[1] = temp1;
for (int i = 2; i < (new_size); i++ )
{
temp_array[i] = p_values[count];
count++;
}
//I2C
uint8_t status = 255;
while(!I2C0_Open(p_platform->address)); // sit here until we get the bus..
I2C0_SetBuffer(temp_array,new_size);
I2C0_SetAddressNackCallback(I2C0_SetRestartWriteCallback,NULL); //NACK polling?
I2C0_MasterWrite();
while(I2C0_BUSY == I2C0_Close()); // sit here until finished.
/* This function returns 0 if OK */
status = 0;
return status;
}
This works when sending an array that is located in my main.c file.
e.g:
//buffer.h
const uint8_t Sensor_Firmware[] = {0x05,...,0x01};
//End buffer.h
.
//main.c
void main (void)
{
uint8_t I2C_address = 0x01;
uint8_t I2C_reg = 0x01;
uint32_t size = 16;
uint8_t temp_array[size];
for (int i = 0; i <size; i++)
{
temp_array[i] = Sensor_Firmware[i];
}
WrMulti(I2C_address, I2C_reg, &temp_array[0], size);
While(1)
{
;
}
}
//End main.c
It also work when passing an array from the .h file without the 'const' key word.
e.g:
//buffer.h
uint8_t Sensor_Firmware[] = {0x05,...,0x01};
//End buffer.h
.
//main.c
void main (void)
{
uint8_t I2C_address = 0x01;
uint8_t I2C_reg = 0x01;
uint32_t size = 16;
uint8_t temp_array[size];
WrMulti(I2C_address, I2C_reg, &Sensor_Firmware[0], size);
While(1)
{
;
}
}
//End main.c
It does not when I pass the 'Sensor_Firmwware[]' array (with the const key word) from the .h file to 'WrMulti'. It just ends up sending '0x00' for every byte that comes from 'Sensor_Firmware'.
Does anyone know why this is might be?
Kind regards

Weird correlation between I2C Transfer and Array size

So... i don't even know how to explain this...
I have a cc1310 Launchpad XL and a tiny EEPROM. My task is to write a library for easy transferring. In Code Composer Studio I'm using an Example project from TI with TIRTOS to test my functions. The weird thing is:
when i am declaring a uint8_t array larger than 304. my Transactions wont work. Itll only send 1 Byte and freezes.
Under 305, everything is fine.
Oh and im not even using the array. It just has to exist and nothing works.
void *mainThread(void *arg0)
{
uint32_t *pAddress;
int i;
uint8_t dat = 0;
uint32_t address = 0x00FEAA;
uint8_t data[305] = {0};
uint32_t datalen = sizeof(data);
for(i=0; i< 305; i++)
{
data[i]=dat;
dat++;
}
pAddress=&address;
int write = EEPROM_sWrite(pAddress, data,datalen);
return 0;
}
and
int EEPROM_sWrite(uint32_t *address, uint8_t *data, uint32_t datalen)
{
I2C_init();
//needed variables and initialization
uint8_t writebuf[258] = {0};
uint8_t blocksize = 0;
uint8_t *p = &writebuf[2];
if((*address+datalen)>maxAddress) //out of bounds?
{
return 1;
}
else
{
I2C_Transaction Transaction = {0};
Transaction.slaveAddress = slaveAddressA;
Transaction.writeBuf = writebuf;
Transaction.writeCount = blocksize;
Transaction.readBuf = NULL;
Transaction.readCount =0;
I2C_Params params;
I2C_Params_init(&params);
params.bitRate = I2C_400kHz;
params.transferMode = I2C_MODE_BLOCKING;
I2C_Handle Handle = I2C_open(0,&params );
//first block
if(*address>0xFFFF) //second half of the memory?
{
Transaction.slaveAddress = slaveAddressB;
}
blocksize = maxPagesize - (*address & 0xFF)+1;
//blocksize needs to be adjusted to the page size
writebuf[0] = (*address & 0xFF00) >> 8; //page address
writebuf[1] = (*address & 0xFF); //cell Address
if(datalen<=blocksize) //if it fits in a single page, just do it
{
memcpy(p,data,datalen);
//copies data to buffer (fills only needed cells in page)
Transaction.writeCount = datalen+2;
if(I2C_transfer(Handle, &Transaction))
{
I2C_close(Handle);
return 0;
}
else
{
I2C_close(Handle);
return 1;
}
}
memcpy(p,data,blocksize);//copies data to buffer (fills complete page)
Transaction.writeCount = blocksize+2;
if(!I2C_transfer(Handle, &Transaction))
{
I2C_close(Handle);
return 1;
}
usleep(10000);
//loop preparation
data+=blocksize;//shifts pointer forward
datalen-=blocksize; //reduces blocksize
writebuf[0]++; //next page
writebuf[1] = 0; //start cell is now 0 each time
//nth block
while(datalen>maxPagesize) //cut down to page sized blocks and write it down
{
//copy 256 bytes of data to buffer
memcpy(p,data,maxPagesize);
//send it
Transaction.writeCount = maxPagesize+2;
if(!I2C_transfer(Handle, &Transaction))
{
I2C_close(Handle);
return 1;
}
usleep(10000);
//preparation
data+=maxPagesize;
datalen-=maxPagesize;
//checks if it exceeds the first memory half
if(writebuf[0]==0xff)
{
Transaction.slaveAddress=slaveAddressB;
writebuf[0]=0;
}
else
{
writebuf[0]++; //next page
}
}
//last block
//copy last data
memcpy(p,data,datalen);
//send it
Transaction.writeCount = datalen+2;
if(!I2C_transfer(Handle, &Transaction))
{
I2C_close(Handle);
return 1;
}
I2C_close(Handle);
return 0;
}
}
edit:
#define maxAddress 0x1FFFF
#define maxPagesize 0xFF
forgot them..
A Reddit user had the right idea!
Turns out it was a simple stack overflow.
The Stack size of the thread was 1024. As i changed it to 2048, everything works.

C assign value to double pointer

I am working on some C code on micro processor stm32f103. Since allocating memory from the heap isn't stable, I am not encouraged to use the C library functions malloc() and free() etc. Instead, I thought of declaring a large chunk of static memory in advance during compilation time, and reallocating the memory to suit my pseudo dynamic memory allocation purposes. My new malloc implementation works fine when testing on my computer, but crashes on the stm32 when I do malloc for double data type.
Here is my malloc implementation. I know it is not a real dynamic memory allocation, but i do it just to practice using pointers.
pk_malloc.c
#include "pk_malloc.h"
char pool[RESERVE];
void* alloc[RESERVE];
void mem_init()
{
for (int i = 0; i != RESERVE; i++)
{
alloc[i] = NULL;
}
}
void* mem_malloc(size_t size)
{
if (size > 0)
{
for (int i = 0; i != RESERVE; i++)
{
if (alloc[i] == NULL)
{
int end;
for (end = i; end != RESERVE; end++)
{
if (alloc[end] != NULL || end - i == size + 1)
{
break;
}
}
if (end - i == size + 1)
{
for (int k = i + 1; k != end; k++)
{
alloc[k] = &pool[k];
}
return alloc[i + 1];
}
}
}
}
return NULL;
}
void* mem_realloc(void* mem, size_t new_size)
{
if (mem == NULL)
{
return mem_malloc(new_size);
}
int old_size = 0;
void** alloc_t = &alloc[(char*)(mem) - pool];
while (*alloc_t != NULL)
{
old_size++;
alloc_t++;
}
if (new_size <= old_size)
{
mem_free((char*)mem + new_size);
return mem;
}
else
{
int i = alloc_t - alloc;
int size = new_size - old_size;
int end;
for (end = i; end != RESERVE; end++)
{
if (alloc[end] != NULL || end - i == size + 1)
{
break;
}
}
if (end - i == size + 1)
{
for (int k = i; k != end - 1; k++)
{
alloc[k] = &pool[k];
}
return alloc[i];
}
else
{
void* realloc_t = mem_malloc(new_size);
if (realloc_t == NULL)
{
return mem;
}
else
{
mem_copy(realloc_t, mem);
mem_free(mem);
return realloc_t;
}
}
}
}
void mem_copy(void* dest, void* source)
{
int dest_index = (char*)(dest) - pool;
int source_index = (char*)(source) - pool;
char* writer = (char*)(source);
while (alloc[source_index] != NULL && alloc[dest_index] != NULL)
{
pool[dest_index] = pool[source_index];
dest_index++;
source_index++;
}
}
void mem_free(void* mem)
{
if (mem != NULL)
{
void** alloc_t = &alloc[(char*)(mem) - pool];
while (*alloc_t != NULL)
{
*alloc_t = NULL;
alloc_t++;
}
}
}
pk_malloc.h
#ifndef _PK_MALLOC
#define _PK_MALLOC
#include <stdlib.h>
#define RESERVE 64
void mem_init();
void* mem_malloc(size_t size);
void* mem_realloc(void* mem, size_t new_size);
void mem_copy(void* dest, void* source);
void mem_free(void* mem);
#endif
main.c
int main()
{
mem_init();
int* hoho = (int*)(mem_malloc(sizeof(int)));
*hoho = 123;
printf("%d", *hoho);
mem_free(hoho);
}
The code works on my computer, and also works on the STM32. However when I change my datatype to a double:
int main()
{
mem_init();
double* hoho = (double*)(mem_malloc(sizeof(double)));
*hoho = 0.618;
printf("%f", *hoho);
mem_free(hoho);
}
It only works on my computer, while it crashed on the STM32.
I did some testing and debugs, I find that this line works, the pointer is not NULL and it has a valid address.
double* hoho = (double*)(mem_malloc(sizeof(double)));
However this line crashed.
*hoho = 0.618;
After more testing, I find any data types occupying more than 4 bytes crashes the same way, including long long etc.
Strangely, I made some user defined structs with lots of int, float data types etc, which definitely occupies more than 4 bytes, the code works fine on the STM32.
struct ABC
{
int a;
float b;
};
This line works no problems.
struct ABC* hoho = (struct ABC*)(mem_malloc(sizeof(struct ABC)));
The variable hoho can be assigned, and its members can be accessed without ease, working both on my computer and the STM32.
Please note that all the code works on my laptop, and most data types work for the STM32 too.
I have been stuck with the problem for hours, any help appreciated.
The core in STM32F1 is a Cortex-M3. This QA here points out that while unaligned word access is allowed by Cortex-M3 for simple instructions, not all instructions support unaligned access. In your case, the C compiler uses an instruction that doesn't support an unaligned address with double.
Notice that
the standard library malloc returns a pointer that is "suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated" (C11 7.22.3)
while a pointer may be converted to another pointer, "if the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined" (C11 6.3.2.3p7).
Thus the behaviour of a program is undefined already at these lines
int *hoho = mem_malloc(sizeof(int));
double *hoho = mem_malloc(sizeof(double));
if the pointer returned is not suitably aligned for int and double respectively.
To fix the code, change it so that it always returns pointers of proper alignment. The official ARM compilers maintain an 8-byte aligned heap.

Suggestions to handle `Wframe-larger-than`-warning on kernel module

Hello and a happy new year,
I'm working on a kernel-module. It is necessary to do a numeric calculation of some parameter to set up the device correctly.
The function works perfectly but the gcc compiler (I'm using kbuild) gives me the warning:
warning: the frame size of 1232 bytes is larger than 1024 bytes [-Wframe-larger-than=]
If I'm right this means that space local variables exceed a limitation given by the machine the module compiled on.
There are some questions now:
Does this warning refer to the whole memory space needed for the module, this explicit function or this function and its sub-functions?
How critical is this?
I don't see a way to reduce the needed memory. Are there some suggestions to handle this? Any how-to?
Maybe it is helpful: The calculation uses a 64bit fixed-point-arithmetic. All the functions of this library are inline functions.
Thanks in advance
Alex
Following the advice from #Tsyvarev the problem could reduce to the allocation in a function as this example shows (I know that the code doesn't make sense - it's only for showing how I declare the variables inside the functions):
uint8_t getVal ( uint8_t )
{
uint64_t ar1[128] = {0};
uint64_t ar2[128] = {0};
uint8_t val;
// a much of stuff
return val;
}
void fun ( void )
{
uint64_t ar1[128] = {0};
uint64_t ar2[128] = {0};
uint8_t cnt;
for(cnt=0; cnt<128; cnt++)
{
ar1[cnt] = getVal(cnt);
ar1[cnt] = getVal(cnt);
}
}
to point 3:
As suggested the solution is to store the data to the heap with kmalloc instead to the stack.
uint8_t getVal ( uint8_t )
{
uint64_t *ar1;
uint64_t *ar2;
uint8_t val, cnt;
// allocate memory on the heap
ar1 = kmalloc(sizeof(uint64_t), 128);
ar2 = kmalloc(sizeof(uint64_t), 128);
// initialize the arrays
for(cnt=0; cnt<128; cnt++)
{
ar1[cnt] = 0;
ar2[cnt] = 0;
}
// a much of stuff
return val;
}
void fun ( void )
{
uint64_t *ar1;
uint64_t *ar2;
uint8_t cnt;
// allocate memory on the heap
ar1 = kmalloc(sizeof(uint64_t), 128);
ar2 = kmalloc(sizeof(uint64_t), 128);
// initialize the arrays
for(cnt=0; cnt<128; cnt++)
{
ar1[cnt] = 0;
ar2[cnt] = 0;
}
for(cnt=0; cnt<128; cnt++)
{
ar1[cnt] = getVal(cnt);
ar1[cnt] = getVal(cnt);
}
}

Resources