Hi all I have a strange problem when I'm trying to cast buffers by arm compiler. Here an example:
char* pbuf; ... unsigned short val = *((unsigned short*)(pbuf+3));
When I compile this code, my generated assembly code uses LDRH,STRH. Then because my pbuf+3 is not multiple of 2 and those 2 instruction can only work with even value addresses, processor hangs up. What I should to do that compiler generates a code that works in all cases?
Regards
I have an I2C FRAM, I read data from it with the below code. And the code works.
But after reading this thread, I am not so sure about that, if my code just works by luck? Do I need to use shift and or to handle this?
(Performance is not an issue to me.)
union { int Data_int; char Data_char[4]; } Counter_tmp; void FRAM_Reader( void ) { int i, j, index; Dummy_Write = 1; I2C_M2S_SAddr = SLAVE_ADDR; I2CEngine(); if ( (I2C_M2S_DatBuf[0] == 'H') && (I2C_M2S_DatBuf[1] == 'i') && (I2C_M2S_DatBuf[2] == 'd') && (I2C_M2S_DatBuf[3] == 'e') ) { index = 4; for ( i = 0; i < 6; i++ ) { for ( j = 0; j < 4; j++ ) { Counter_tmp.Data_char[j] = I2C_M2S_DatBuf[index++]; } The_DI_Counter[i] = Counter_tmp.Data_int; } } else { FRAM_Writer(); } }
My FRAM_Writer:
void FRAM_Writer( void ) { int i, j, index; I2C_M2S_DatBuf[0] = 'P'; I2C_M2S_DatBuf[1] = 'K'; I2C_M2S_DatBuf[2] = 'G'; I2C_M2S_DatBuf[3] = 'O'; index = 4; for ( i = 0; i < 6; i++ ) { Counter_tmp.Data_int = The_DI_Counter[i]; for ( j = 0; j < 4; j++ ) { I2C_M2S_DatBuf[index++] = Counter_tmp.Data_char[j]; } } Dummy_Write = 0; I2C_M2S_SAddr = SLAVE_ADDR; I2CEngine(); }
The compiler will align the union in relation to the member that has the highest alignment requirements. So the int will be properly aligned.
Your program will store data in the EEPROM in the byte order for the processor and since the EEPROM is not likely to be moved to a different processor with different size of an int or different byte order, you should be fine.
The problem for the OP was that he used a typecast for a data type larger than a char, when the pointer could be on an odd address.
So while your code will store different data into the EEPROM if moved between a little-endian and big-endian processor, or between a 16-bit, 32-bit or 64-bit processor, you should be fine. Using a union to get/set bytes from an integer is just an alternative way to using shifts and and/or operations.
Hi Per,
Many thanks to your explanation.
I remember that I had read some other threads discussing the data alignment issues, and I did encountered a data alignment problem, and fixed that problem with the hints from the KEIL forum.
I think that I must mix something up, and then got confused.
Bit field is something implementation dependent. Data alignment rule within a struct or union is defined by C-Standard or Processor-Architecture. __packed is a feature that KEIL provides.
These stuff are really difficult to me.