map variable to IOs from different ports - c

I'm trying to map a variable to IO from different ports. The closest example I could find is this:
union {
struct
{ // specify each bit in this char byte
unsigned bit0:1 ; // name each member and size
unsigned bit1:1 ;
unsigned bit2:1 ;
unsigned bit3:1 ;
unsigned bit4to6:3 ; // example set to 3 bits
unsigned bit7:1 ;
};
unsigned char allbits; // overall type of union
} Flag ; // name of union = Flag
Flag.allbits = 0x12; // sets value of union/bits to 0x12
Flag. bit2 = 0; // clear the if (Flag. bit2==1), etc
if (Flag. bit2 == 1) etc
Is it possible that instead having bit0, bit1, bit2 etc to have IO bits from different ports? Something like this:
union {
struct
{ // specify each bit in this char byte
LATAbits.LATA5:1 ; // name each member and size
LATAbits.LATA7:1 ;
LATBbits.LATB2:1 ;
LATBbits.LATB4:1 ;
LATBbits.LATB5:1 ;
LATCbits.LATC0:1 ;
LATCbits.LATC1:1 ;
LATCbits.LATC2:1 ;
};
unsigned char allbits; // overall type of union
} Flag ; // name of union = Flag
Flag.allbits = 0x12; // sets value of union/bits to 0x12
What's important for me is to be able to set the value of the entire union and not necessarily to access individual bits.

Well, I've found a solution. It's not the most elegant but it's working for me. If you do have other ideas and want to share, please post it.
unsigned int HoltekAddress = 0; // Variable that holds the value for union
union
{
struct
{ // Specify each bit in this char byte
unsigned int bit0 :1; // Name each member and size
unsigned int bit1 :1;
unsigned int bit2 :1;
unsigned int bit3 :1;
unsigned int bit4 :1;
unsigned int bit5 :1;
unsigned int bit6 :1;
unsigned int bit7 :1;
unsigned int bit8 :1;
unsigned int bit9 :1;
unsigned int bit10 :1;
unsigned int bit11 :1;
};
unsigned int allbits; // Union variable and name of all members
} Holtek; // Name of union = Holtek
Holtek.allbits = HoltekAddress;
LATBbits.LATB6 = Holtek.bit0;
LATBbits.LATB7 = Holtek.bit1;
LATBbits.LATB8 = Holtek.bit2;
LATBbits.LATB9 = Holtek.bit3;
LATAbits.LATA0 = Holtek.bit4;
LATAbits.LATA8 = Holtek.bit5;
LATAbits.LATA7 = Holtek.bit6;
LATDbits.LATD5 = Holtek.bit7;
LATDbits.LATD4 = Holtek.bit8;
LATDbits.LATD3 = Holtek.bit9;
LATDbits.LATD1 = Holtek.bit10;
LATDbits.LATD0 = Holtek.bit11;
Thanks everyone.

Well, this is elegant enough. The idea is that you cannot auto-magically map arbitrary bits from different "ports" into a single byte/word variable. One has to copy the value of each and every bit. The union makes it easy to pass several bits between functions.
Just my humble opinion (Teule tata).

Related

What are for square brackets in an addressed-of pointer?

I've been searching for a while what are for square-brackets in an addressed-of pointer, but I continue without understanding it. Here are the lines of the function, where "id" variable is an uint32_t pointer that has been previously passed as an argument.
#define LIST_STARTED (0x0001) /*defined out of the function*/
#define LIST_FIRST (0x0002) /*defined out of the function*/
uint32_t *pointer = id;
uint16_t *flags = &((uint16_t *)pointer)[0];
uint16_t *index = &((uint16_t *)pointer)[1];
bool started = *flags & LIST_STARTED;
bool first = *flags & LIST_FIRST;
if (!started){
/* does something */
*flags = MSEC_PRM_MGMT_LIST_STARTED;
return true;
}
if (!first){
/* does something */
*flags |= MSEC_PRM_MGMT_LIST_FIRST;
*index = 1;
return true;
}
if (*index == final_index)
/* does something */
return false;
*index += 1;
I understand what the logic of the function is, but I don't understand what do the following lines. I put "all" the code above in case it helps you.
uint16_t *flags = &((uint16_t *)pointer)[0];
uint16_t *index = &((uint16_t *)pointer)[1];
I would appreciate if someone could help me!
Thank you!
I edit to say that this C code works fine in an Embedded System, I'm not modifying it, I was just watching its behaviour.
The following code tries to read a uint32_t object as an array of two uint16_t objects:
uint32_t *id = ...;
uint32_t *pointer = id;
uint16_t *flags = &((uint16_t *)pointer)[0];
uint16_t *index = &((uint16_t *)pointer)[1];
and that is undefined behaviour to read a uint32_t object as 2 uint16_t objects through flags and index pointers because that breaks strict aliasing rules.
The correct way is:
uint16_t flags = *id; // The lowest order bits of id.
uint16_t index = *id >> 16; // The highest order bits of id.
In the above assignments of uint32_t to uint16_t it truncates the highest order bits of id.
uint32_t *pointer = id;
uint16_t *flags = &((uint16_t *)pointer)[0];
it is an equivalent of.
uint32_t *pointer = id;
uint16_t *flags = (uint16_t *)pointer;
The definition:
uint16_t *index = &((uint16_t *)pointer)[1];
Is an equivalent of:
uint16_t *temp = (uint16_t *)pointer;
uint16_t *index = temp + 1;
//or
uint16_t *index = &temp[1];
This is called: pointer punning and it is considered dangerous and not portable.
You can use unions for safe punning (at least when using gcc or its derivatives)
typedef union
{
uint64_t u64;
uint32_t u32[2];
uint16_t u16[4];
uint8_t u8[8];
struct
{
uint8_t n1: 4;
uint8_t n2: 4;
}u4[8];
}union_pune_t;
uint16_t foo16(uint32_t *p32)
{
union_pune_t *d64 = (void *)p32;
return d64 -> u16[1];
}
uint8_t foo8(uint32_t *p32)
{
union_pune_t *d64 = (void *)p32;
return d64 -> u8[5];
}
uint8_t foon4(uint32_t *p32)
{
union_pune_t *d64 = (void *)p32;
return d64 -> u4[9].n2;
}

Function parameters as pointers and return value in C

In the function i need to pass in myFlg and somVar as input parameters. They are modified withing the function and then returned newLevel.
Do i pass in pointers for myFlg and somVar and how do i do that. The flg and counter need to be updated inside the function but they are not globals. So pass in two parameters/pointers and return a value, one return value and two modified values/pointers.
in flags.h
#define FlagReg1set_u 0b01000001
typedef union
{
struct
{
uint8_t Flg1 : 1;
uint8_t Flg2 : 1;
uint8_t Flg3 : 1;
uint8_t Flg4 : 1;
uint8_t Flg5 : 1;
uint8_t Flg6 : 1;
uint8_t my_Flg : 1;
uint8_t foo : 1;
} bits;
uint8_t byte;
} FlagReg1_t = FlagReg1set_u;
in level.c
uint16_t level(uint8_t Flag, uint8_t SomeVariable, uint8_t SomeCount)
{
static uint16_t newLevel = SomeVariable;
static uint8_t count = SomeCount;
static uint8_t somVar;
if (FlagReg1.bits.my_Flg == 1)
{
/* do something */
newLevel = 0xFFFF;
}
else
{
FlagReg1.bits.my_Flg = 0
}
if (somVar == SomeVariable)
{
count = 0;
}
else
{
count++;
}
return newLevel
}
in main .c
#include "flags.h"
main()
{
/* Variable Declaration */
uint16_t level(uint8_t Flag, uint8_t SomeVariable, uint8_t SomeCount);
uint8_t count = 0;
uint8_t ownlevel;
uint16_t newLevel;
level(FlagReg1_t my_Flg, ownlevel, count);
if (newLevel == 0)
{
//do something
}
else
{
//do something
}
}
Well excuses to the community I use answer space , this is more a comment but I need the tools to explain.
So , eumac , the usual purpose of a union is:
typedef union eumac_un_t
{
struct eumac_str
{
uint8_t flag_4;
uint8_t flag_3;
uint8_t flag_2;
uint8_t flag_1;
};
int the_flag;
}eumac_un;
This takes 4 bytes (a memory area) , stores the same data which can be retrieved in all the various ways.
Example if you store
eumac_un_t.eumac_str.flag_1 = 150 //(1001 0110)
eumac_un_t.eumac_str.flag_2 = 20 //(0001 0100)
what you get for
eumac_un_t.the_flag == 5270 //its 0000 0000 - 0000 0000 - 0001 0100 - 1001 0110
This is why we use a union.So in your case you won't need it.Is that clear??
Now in your case , usually you pass as pointers when you have an array.If flag is just an integer , then you can simply pass it as an integer.
So yes , exactly the function you mention is very nice
uint16_t level(FlagReg1_t *ptrToFlagReg1, uint8_t *SomeVariable, uint8_t *SomeCount)
{
ptrToFlagReg1->something = something;
ptrToFlagReg1->something_else = something_else;
return number_of_something;
}
Integers don't really have to be passed as pointers if there's no need to.
uint8_t SomeVariable, uint8_t SomeCount

C code: left shift is shifting but dropping top bits

I'm doing a small embedded project where I have 40 bits transferred through a SPI type interface. I pull these bits off of a 32 bit bus and place the upper 32 bits into a uint32_t variable and the lower 8 bits into a uint8_t variable. I'm trying to combine them into a single uint64_t. However when I shift by 8, it drops the top 8 bits. Here is my code.
uint64_t getError()
{
uint32_t * disp_addr = (uint32_t*)(MYDISPLAY);
uint64_t error_upper;
uint8_t error_lower;
uint64_t error= 0;
error_lower = *(disp_addr+1);
error_upper = *(disp_addr+0);
error = ((uint64_t) error_upper) <<8 | error_lower;
return error;
}
This code is working except for the fact that it's dropping my top 8 bits.
Any thoughts or hints would be greatly appreciated. Thanks.
edit
uint64_t getError()
{
uint32_t * disp_addr = (uint32_t*)(MYDISPLAY);
uint64_t error_upper;
uint8_t error_lower;
uint64_t error= 0;
error_lower = 0x34;
error_upper = 0xABCDEF12;
error = ((uint64_t) error_upper) <<8 | error_lower;
printf("%010x", error);
//return error;
}
Results:
00cdef1234
The printf format specifier is incorrect.
#include <stdio.h>
typedef unsigned __int64 uint64_t;
typedef unsigned char uint8_t;
int main(void) {
uint64_t error_upper, error;
uint8_t error_lower;
error_lower = 0x34;
error_upper = 0xABCEDF12;
error = (error_upper << 8) | error_lower;
printf("%x\n", error);
printf("%llx\n", error);
return 0;
}
Program output:
cedf1234
abcedf1234
Why are you saying that the upper byte is cut?
If I use your code and print the result is ok:
uint32_t temp = 0x01020304;
uint32_t *disp_addr = &temp;
uint64_t error_upper;
uint8_t error_lower;
uint64_t error= 0;
error_lower = *(disp_addr+1);
error_upper = *(disp_addr+0);
error = (error_upper<<8) | error_lower;
printf("\n%08X%08X\n", (uint32_t)(error>>32), error);
Output is
0000000102030401
Are you using %d to printout the value?
Look carefully at
uint32_t *disp_addr = &temp;
...
error_lower = *(disp_addr+0);
Because disp_addr is a ptr to uint32_t you are storing a 32bit value in a 8bit variable. Depending on your machine endiannes and how you load disp_addr you may be loading the wrong data.
You probably wanted to do:
uint32_t *disp_addr = &temp;
...
error_lower = *(uint8_t *)(disp_addr+0);
which is not the same.

typecasting char variable into unsigned int

I am trying to convert char variables into Unsigned int. my code is
char spi(char data)
{
//Start transmision
SPDR = data;
//Wait for transmision complete
while(!(SPSR & 0x80));
return SPDR;
}
unsigned int ReadAd(void)
{
unsigned int data;
ChipSelectAd(1);
//Read data
CheckStatus();
spi(0x58);
data = (spi(0xFF)<< 8);
data |= spi(0xFF);
return data;
}
Actually my problem is The spi function return an 8bit char so the above code shifts left 8bits the char variable and then assigns it to a 16bit variable, the result will always be 0.
In order to actually shift the data to the left I need to typecast them first to a 16bit type variable. I have tried like this
char spi(char data)
{
//Start transmision
SPDR = data;
//Wait for transmision complete
while(!(SPSR & 0x80));
return SPDR;
}
unsigned int ReadAd(void)
{
unsigned int data;
ChipSelectAd(1);
//Read data
CheckStatus();
spi(0x58);
data = (unsigned int)((unsigned char)spi(0xFF)<< 8);
data |= (unsigned int)((unsigned char)spi(0xFF));
return data;
}
void CheckStatus(void)
{
//char adcStatus;
adcStatus = 0xFF;
//Read status
while(!(adcStatus & 0x80))
{
spi(0x40);
adcStatus = spi(0xFF);
}
}
void ChipSelectAd(char s)
{
if(s == 1){
PORTB.3 = 0; //Switch on ADC
//while(PINB.3); //Wait for chip select pin
}
else
PORTB.3 = 1; //Switch off ADC
}
its not working. please suggest me which function i have to use.
Thanks in advance.
Your problem is not the casts. It works the same without them, due to the integral promotion rules.
#include <stdio.h>
char spi ( char data )
{
char SPDR = data;
return SPDR;
}
unsigned int ReadAd ( void )
{
unsigned int data;
data = spi ( 0x81 ) << 8;
data |= spi ( 0x42 );
return data;
}
int main ( void )
{
printf ( "Result %x\n", ReadAd() );
return 0;
}
This outputs Result ffff8142 on a system where char is a signed type. To get to the real problem, try assinging the values of spi() calls to variables and then print their values. Please also show us the declaration/definition of SPDR.
1) in embedded systems: get rid of the standard integer types, the default char type in particular. If you have a modern compiler, use uint8_t, uint16_t etc from stdint.h. If you have an ancient compiler, then typedef unsigned char uint8_t and so on. If you aren't using unsigned types of known size in embedded systems, you are asking for bugs bugs bugs.
2) Learn and understand integer promotion rules. It is frightening how many programmers there are that don't know about them or understand them.
Once you have the two above fundamentals sorted out, your code should look something like this code:
(I took the liberty to fix various suspicious, possible bugs and the crappy, inconsistent indention. Plus some style nitpicks.)
#include <stdint.h>
uint8_t spi (uint8_t data)
{
SPDR = data; //Start transmision
while((SPSR & 0x80) > 0) //Wait for transmision complete
;
return SPDR;
}
uint16_t ReadAd(void)
{
uint16_t data;
ChipSelectAd(true);
CheckStatus(); //Read data
(void) spi(0x58);
data = ((uint16_t)spi(0xFF)) << 8;
data |= (uint16_t)spi(0xFF);
return data;
}
void CheckStatus(void)
{
uint8_t adcStatus;
do
{
(void) spi(0x40);
adcStatus = spi(0xFF);
} while((adcStatus & 0x80) > 0);
}
void ChipSelectAd(bool on)
{
if(on)
{
PORTB.3 = 0; //Switch on ADC
}
else
{
PORTB.3 = 1; //Switch off ADC
}
}

DWORD variable with low/high word and low/high byte

How in C can we read and make DWORD variables with a low and high word and low and high byte?
WinAPI provides macros for the manipulations of these types, such as:
HIWORD
LOWORD
MAKELPARAM
In Win32 a DWORD is a 32 bit unsigned integer. In other contexts it could possibly mean something else.
Assuminng the Win32 definition (and other Win32 typedefs):
BYTE lsb = 0x11 :
BYTE next_lsb = 0x22 :
BYTE next_msb = 0x33 :
BYTE msb = 0x44 :
DWORD dword_from_bytes = (msb << 24) | (next_msb << 16) | (next_lsb << 8) | lsb ;
dword_from_bytes will have the value 0x44332211.
Similarly:
WORD lsw = 0x1111 :
WORD msw = 0x2222 :
DWORD dword_from_words = (msw << 16) | lsw ;
dword_from_words will have the value 0x22221111.
To extract say the third byte from dword_from_bytes for example:
next_msb = (dword_from_bytes >> 16) & 0xff ;
although the & 0xff is not strictly necessary in this case given the type of next_msb, but if the type of the receiver were larger than 8 bits, it will mask off the msb bits.
#include <stdint.h>
#include <stdio.h>
typedef union _little_endian{
struct _word{
union _msw{
struct _msw_byte{
uint8_t MSB;
uint8_t LSB;
} __attribute__((__packed__)) MSW_BYTE;
uint16_t WORD;
} MSW;
union _lsw{
struct _lsw_byte{
uint8_t MSB;
uint8_t LSB;
} __attribute__((__packed__)) LSW_BYTE;
uint16_t WORD;
} LSW;
} __attribute__((__packed__)) WORD;
uint32_t DWORD;
} DWORD;
int main(int argc, char *argv[]){
DWORD test1;
test1.WORD.MSW.MSW_BYTE.MSB = 1;
test1.WORD.MSW.MSW_BYTE.LSB = 2;
test1.WORD.LSW.LSW_BYTE.MSB = 3;
test1.WORD.LSW.LSW_BYTE.LSB = 4;
printf("test1: hex=%x uint=%u\n", test1.DWORD, test1.DWORD);
DWORD test2;
test2.DWORD = 0x08080404;
printf("test2: hex=%x uint=%u\n", test2.DWORD, test2.DWORD);
printf("test2.WORD.MSW.MSW_BYTE.MSB: uint=%u\n", test2.WORD.MSW.MSW_BYTE.MSB);
printf("test2.WORD.MSW.MSW_BYTE.LSB: uint=%u\n", test2.WORD.MSW.MSW_BYTE.LSB);
printf("test2.WORD.LSW.LSW_BYTE.MSB: uint=%u\n", test2.WORD.LSW.LSW_BYTE.MSB);
printf("test2.WORD.LSW.LSW_BYTE.LSB: uint=%u\n", test2.WORD.LSW.LSW_BYTE.LSB);
return 0;
}
I prefer to use a combination of structs and unions.
Output:
test1: hex=4030201 uint=67305985
test2: hex=8080404 uint=134743044
test2.WORD.MSW.MSW_BYTE.MSB: uint=4
test2.WORD.MSW.MSW_BYTE.LSB: uint=4
test2.WORD.LSW.LSW_BYTE.MSB: uint=8
test2.WORD.LSW.LSW_BYTE.LSB: uint=8

Resources