If I want to write a thread-safe method that simultaneously sets and clears some internal bits, I might do it with two arguments: a 32-bit mask of the internal bits to modify, and a 32-bit mask indicating whether to set the internal bits specified by the first parameter to 0 or 1.
What is the convention for naming these two parameters?
I have not heard of any overall standards, although many places I have worked have had naming standards, etc.
Each bit in the mask gets defined individually, for example:
#define TANK_GAUGE_OK (0x80) // 1 when the gauge is properly initialized and working
#define TANK_FULL (0x08) // 1 when tank is filled completely
#define TANK_HIGH (0x04) // 1 when tank is at least 1/4 full
#define TANK_LOW (0x02) // 1 when tank is at least 1/8 full
#define TANK_NOTEMPTY (0x01) // 1 when there is some fuel in tank
#define TANK_LIGHTS_MASK (TANK_FULL | TANK_HIGH | TANK_LOW | TANK_NOTEMPTY )
For function names --
SET_ON(unsigned setMask), SET_OFF(unsigned clearMask)
To update specific bits in a register:
Update(changeMask, valueMask)
where changeMask contains the bits you want to update, to 1, and valueMask contains the bits values you want to set.
You would use them like this code for an embedded fuel gauge monitor:
static unsigned short fuelGaugeRegisterValue = 0x0000;
extern unsigned short *fuelGaugeRegister;
. . .
void UpdateFuelGauge(unsigned changeMask, unsigned valueMask) {
// code to grab mutex goes here...
fuelGaugeRegisterValue &= (~changeMask);
fuelGaugeRegisterValue |= ( changeMask & valueMask);
*fuelGaugeRegister = fuelGaugeRegisterValue;
// code to release mutex goes here...
}
. . .
void SetFuelGaugeFromLevel(unsigned byte currentLevel)
if ( currentLevel == 0xFF ) {
UpdateFuelGauge( TANK_LIGHTS_MASK, TANK_LIGHTS_MASK );
}
else if (level >= 0x03 ) {
UpdateFuelGauge( TANK_LIGHTS_MASK, (TANK_HIGH | TANK_LOW | TANK_NOTEMPTY) );
}
else if (level >= 0x02 ) {
UpdateFuelGauge( TANK_LIGHTS_MASK, (TANK_LOW | TANK_NOTEMPTY) );
}
else if (level > 0x01 ) {
UpdateFuelGauge( TANK_LIGHTS_MASK, TANK_NOTEMPTY );
}
else {
UpdateFuelGauge( TANK_LIGHTS_MASK, 0 );
}
}
Some other notes:
Try to name the bits and standard masks in a manner that you can make an educated guess as to what the bit would mean when it is "asserted". For instance, "EMPTY_FLAG" makes you guess as to whether "1" means "empty", of "not empty".
Wikipedia has an article on signal masking that uses some terminology, but currently it does mention any naming conventions.
Related
I found the following #define in a header file for an NXP processor:
/*! #name GLOBAL - LPUART Global Register */
/*! #{ */
#define LPUART_GLOBAL_RST_MASK (0x2U)
#define LPUART_GLOBAL_RST_SHIFT (1U)
/*! RST - Software Reset
* 0b0..Module is not reset.
* 0b1..Module is reset.
*/
#define LPUART_GLOBAL_RST(x) (((uint32_t)(((uint32_t)(x)) << LPUART_GLOBAL_RST_SHIFT)) & LPUART_GLOBAL_RST_MASK)
and I wonder how it is supposed to be used. Any explanation will be greatly appreciated.
M'
To clarify how NXP sets up its defines in the SDK:
Pretty much every register gets a "set", a bitmask, and a shift define for every field in the register. The shift isn't really useful generally, but it's used in their "set" define.
If you just want to set (or clear) a field in a register, it's sufficient to just OR/NAND the mask into the register eg
LPUART0->GLOBAL |= LPUART_GLOBAL_RST_MASK; // set
LPUART0->GLOBAL &= ~LPUART_GLOBAL_RST_MASK; // clear
Sometimes, it's more useful to use the "set" macro, typically when the data encompasses more than one bit. It's "safer" in that it won't let you set bits that you aren't supposed to.
LPUART0->GLOBAL |= LPUART_GLOBAL_RST(1); // Sets the value of the reset field to 1.
LPUART0->GLOBAL |= LPUART_GLOBAL_RST(0xFF); // Still just sets the value of the reset field to 1 and doesn't break anything else.
It's also useful to use the full set macro when you're setting all bits of a register at once. That way, you can explicitly set all bits to 1 or zero.
For example, here's some code that sets up sets up my ADC0 CFG1 register on a KL27:
ADC0->CFG1 = ADC_CFG1_ADLPC( 0 ) |
ADC_CFG1_ADIV( 3 ) |
ADC_CFG1_ADLSMP_MASK |
ADC_CFG1_MODE( 1 ) |
ADC_CFG1_ADICLK( 0 );
Without needing to think about things, I'm setting ADIV to 3 (both bits set), ADLSMP to 1, and the mode to 1, while explicitly setting all other bits to 0. Note that the "set" macros whose value is 0 do nothing, and are merely shown for better readability.
In kernel/ipc.h Tanenbaum defines the system call bits as:
/* System call numbers that are passed when trapping to the kernel. The
* numbers are carefully defined so that it can easily be seen (based on
* the bits that are on) which checks should be done in sys_call().
*/
#define SEND 1 /* 0 0 0 1 : blocking send */
#define RECEIVE 2 /* 0 0 1 0 : blocking receive */
#define SENDREC 3 /* 0 0 1 1 : SEND + RECEIVE */
#define NOTIFY 4 /* 0 1 0 0 : nonblocking notify */
#define ECHO 8 /* 1 0 0 0 : echo a message */
but then in kernel/table.c the system call bits are defined as:
/* Define system call traps for the various process types. These call masks
* determine what system call traps a process is allowed to make.
*/
#define TSK_T (1 << RECEIVE) /* clock and system */
#define SRV_T (~0) /* system services */
#define USR_T ((1 << SENDREC) | (1 << ECHO)) /* user processes */
Why is everything bit shifted over to the left? 1 << RECEIVE would be 0100 instead of 0010. Doesn't that mean that the clock and system tasks can NOTIFY but not RECEIVE?
The values formed in the code you show from kernel/table.c are not the values of the code numbers for system calls. They are bit masks for the system calls.
Bit masks are commonly used to implement sets. Suppose we have three objects, such as an apple, a banana, and a cherry, and we wish to record whether some set X does or does not contain an apple, does or does not contain a banana, and does or does not contain a cherry.
We can do this by assigning the bit at position 0 (value 1) to represent an apple, the bit at position 1 (value 2) to represent a banana, and the bit at position 2 (value 4) to represent a cherry. Then whether any set X does or does not contain these items can be represented by a number which does or does not have the corresponding bits set. For example, the number 5 has bits at positions 0 and 2 set, so it represents a set that contains an apple and a cherry but not a banana.
The code in kernel/table.c assigns bits in a bit mask so that the system call with code i is represented by the bit at position i. Thus, the value of the bit in the bit mask for the system call with code i has value 1 << i.
Here is a table showing the values of the call codes and the values of their bit masks:
Call Name Code Number Bit Mask
SEND 1 2
RECEIVE 2 4
SENDREC 3 8
NOTIFY 4 16
ECHO 8 256
The way these are used is that, to represent a set containing several calls, the bit mask values for those calls are added together (or, equivalent, combined with a bitwise OR operation). So the set containing SEND, RECEIVE, and SENDREC is represented by 2+4+8 = 14.
So 1 << SENDREC is the value of the bit that represents SENDREC in the mask, and 1 << ECHO is the value of the bit that represents ECHO in the mask. The OR of these values, 1 << SENDREC | 1 << ECHO, is a bit mask that includes SENDREC and ECHO but does not include SEND or the other codes.
Some operations on bit masks are:
If i is the number of an item, 1<<i is the value of the bit that represents it in the set.
To add one item i to a set X, OR the bit into the set, with X |= 1<<i.
To take the union of two sets X and Y, OR them, with X | Y.
To take the intersection of two sets X and Y, AND them, with X & Y.
I am working on a Motorola HCS08 µCU in CodeWarrior V10.6, I am trying to create an extern bitfield which has bits from existing registers. The way the bitfields are created in the µCU header is like
typedef unsigned char byte;
typedef union {
byte Byte;
struct {
byte PTAD0 :1;
byte PTAD1 :1;
byte PTAD2 :1;
byte PTAD3 :1;
byte PTAD4 :1;
byte PTAD5 :1;
byte PTAD6 :1;
byte PTAD7 :1;
} Bits;
} PTADSTR;
extern volatile PTADSTR _PTAD #0x00000000;
#define PTAD _PTAD.Byte
#define PTAD_PTAD0 _PTAD.Bits.PTAD0
#define PTAD_PTAD1 _PTAD.Bits.PTAD1
#define PTAD_PTAD2 _PTAD.Bits.PTAD2
#define PTAD_PTAD3 _PTAD.Bits.PTAD3
#define PTAD_PTAD4 _PTAD.Bits.PTAD4
#define PTAD_PTAD5 _PTAD.Bits.PTAD5
#define PTAD_PTAD6 _PTAD.Bits.PTAD6
#define PTAD_PTAD7 _PTAD.Bits.PTAD7
Which will let the register value be changed either by PTAD = 0x01, or PTAD_PTAD0 = 1, for example. This definition is basically the same for PTAD, PTBD, PTCD, ... PTGD, the only thing changing is the address.
My attemp to create a custom bitfield out of the previous existing variables is
typedef union {
byte Byte;
struct {
byte *DB0;
byte *DB1;
byte *DB2;
byte *DB3;
byte *DB4;
byte *DB5;
byte *DB6;
byte *DB7;
} Bits;
} LCDDSTR;
I would create and initialize the bitfield as LCDDSTR lcd = {{&PTGD_PTGD6, &PTBD_PTBD5, ...}}, because by some reason, the initialization like LCDSTR lcd = {*.Bits.DB0 = &PTGD_PTGD6, *.Bits.DB1 = &PTBD_PTBD5, ...} (treating it as a struct, please correct me again) advice in How to initialize a struct in accordance with C programming language standards does not work with this compiler (it does work on an online compiler).
However, as you may see I am sort of grouping the bits, and (if it would work) I would be able to change the values of the actual register by doing *lcd.Bits.DB0 = 1, or something like that, but if I do lcd.Byte = 0x00, I would be changing the last (I think) byte of the memory address contained in lcd.Bits.DB0, you know, because the struct doesn't actually contains the data, but the pointers instead.
How would I go on achieving a struct that is able to contain and modify bits from several registers? (I guess the problem here is that in memory the bits are not one next to the other, which I guess would make it easier). Is it even possible? I hope it is.
How would I go on achieving a struct that is able to contain and modify bits from several registers? (I guess the problem here is that in memory the bits are not one next to the other..
I don't think you can do it with a struct. That is because bitfields by definition have to occupy the same or contiguous addresses.
However macros may be useful here
#define DB0 PTGD_PTGD6
#define DB1 PTBD_PTBD5
....
And to clear the bits to all 0's or set to all 1's you can use a multiline macro
#define SET_DB(x) do { \
PTGD_PTGD6 = x; \
PTBD_PTBD5 = x; \
...... \
} while(0)
How would I go on achieving a struct that is able to contain and modify bits from several registers?
You can't.
A structure must represent a single, continuous block of memory -- otherwise, operations like taking the sizeof the structure, or performing operations on a pointer to one would make no sense.
If you want to permute the bits of a value, you will need to find some way of doing so explicitly. If the order of your bits is relatively simple, this may be possible with a few bitwise operations; if it's weirder, you may need to use a lookup table.
Beyond that: bitfields in C are pretty limited. The language does not make a lot of guarantees about how a structure containing bitfields will end up laid out in memory; they are generally best avoided for portable code. (Which doesn't apply here, as you're writing code for a specific compiler/microcontroller combination, but it's worth keeping in mind in general.)
Your union does unfortunately not make any sense, because it forms a union of one byte and 8 byte*. Since a pointer is 16 bit on HCS08, this ends up as 8*2 = 16 bytes of data, which can't be used in any meaningful way.
Please note that the C structure called bit-fields is very poorly specified by the standard and therefore should be avoided in any program. See this.
Please note that the Codewarrior register maps aren't remotely close to following the C standard (nor MISRA-C).
Please note that structs in general are problematic for hardware register mapping, since structs can contain padding. You don't have that problem on HCS08 specifically, since it doesn't require alignment of data. But most MCUs do require that.
It is therefore better to roll out your own register map in standard C if you have that option. The port A data register could simply be defined like this:
#define PTAD (*(volatile uint8_t*)0x0000U)
#define PTAD7 (1U << 7)
#define PTAD6 (1U << 6)
#define PTAD5 (1U << 5)
#define PTAD4 (1U << 4)
#define PTAD3 (1U << 3)
#define PTAD2 (1U << 2)
#define PTAD1 (1U << 1)
#define PTAD0 (1U << 0)
As we can tell, defining the bit masks is mostly superfluous anyway, as PTAD |= 1 << 7; is equally readable to PTAD |= PTAD7;. This is because this was a pure I/O port. Defining textual bit masks for status and control registers on the other hand, increases the readability of the code significantly.
If you want to modify bits from several registers, you'd do something like the following:
Assume we have a RGB (red-green-blue) LED, common cathode, with 3 colors connected to 3 different pins on 3 different ports. Instead of beating up the PCB designer, you could do this:
#define RGB_RED_PTD PTAD
#define RGB_RED_PTDD PTADD
...
#define RGB_BLUE_PTD PTBD
#define RGB_BLUE_PTDD PTBDD
...
#define RGB_GREEN_PTD PTDD
#define RGB_GREEN PTDD PTDDD
#define RGB_RED_PIN 1
#define RGB_BLUE_PIN 5
#define RGB_GREEN_PIN 3
You can now set these independently of where they happen to be located on the hardware:
void rgb_init (void)
{
RGB_RED_PTDD |= (1 << RGB_RED_PIN);
RGB_BLUE_PTDD |= (1 << RGB_BLUE_PIN);
RGB_GREEN_PTDD |= (1 << RGB_GREEN_PIN);
}
void rgb_yellow (void)
{
RGB_RED_PTD |= (1 << RGB_RED_PIN);
RGB_BLUE_PTD &= ~(1 << RGB_BLUE_PIN);
RGB_GREEN_PTD |= (1 << RGB_GREEN_PIN);
}
And so on. Examples were for HCS08 but the same can of course be used universally on any MCU with direct port I/O.
It sounds like an approach such as the following is along the lines of where you would like to go with a solution.
I have not tested this as I do not have the hardware however this should provide an alternative to look at.
This assumes that you want to turn on particular pins or turn off particular pins but there will not be a case where you will want to turn on some pins and turn off other pins for a particular device in a single operation. If that should be the case I would consider making the type of RegPinNo be an unsigned short to include an op code for each register/pin number combination.
This also assumes that timing of operations is not a critical constraint and that the hardware has sufficient horsepower such that small loops are not much of a burden on throughput and hogging CPU time needed for other things. So this code may need changes to improve optimization if that is a consideration.
I assume that you want some kind of a easily readable way of expressing a command that will turn on and off a series of bits scattered across several areas of memory.
The first thing is to come up with a representation of what such a command would look like and it seems to me that borrowing from a char array to represent a string would suffice.
typedef byte RegPinNo; // upper nibble indicates register number 0 - 7, lower nibble indicates pin number 0 - 7
const byte REGPINNOEOS = 0xff; // the end of string for a RegPinNo array.
And these would be used to define an array of register/pin numbers as in the following.
RegPinNo myLed[] = { 0x01, 0x12, REGPINNOEOS }; // LED is addressed through Register 0, Pin 0 and Register 1, Pin 1 (zero based)
So at this point we have a way to describe that a particular device, an LED in this case, is addressed through a series of register/pin number items.
Next lets create a small library of functions that will use this representation to actually modify the specific pins in specific registers by traversing this array of register/pin numbers and performing an operation on it such as setting the bit in the register or clearing the bit in the register.
typedef unsigned char byte;
typedef union {
byte Byte;
struct {
byte PTAD0 : 1;
byte PTAD1 : 1;
byte PTAD2 : 1;
byte PTAD3 : 1;
byte PTAD4 : 1;
byte PTAD5 : 1;
byte PTAD6 : 1;
byte PTAD7 : 1;
} Bits;
} PTADSTR;
// Define a pointer to the beginning of the register area. This area is composed of
// 8 different registers each of which is one byte in size.
// We will address these registers as Register 0, Register 1, ... Register 7 which just happens
// to be how C does its zero based indexing.
// The bits representing pins on the PCB we will address as Pin 0, Pin 1, ... Pin 7.
extern volatile PTADSTR (* const _PTAD) = 0x00000000;
void SetRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte |= pins[bPinNo];
}
}
void ClearRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte &= ~pins[bPinNo];
}
}
void ToggleRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte ^= pins[bPinNo];
}
}
You would use the above something like the following. Not sure what a time delay function would look like in your environment so I am using a function Sleep() which takes an argument as to the number of milliseconds to delay or sleep.
void LightLed (int nMilliSeconds)
{
RegPinNo myLed[] = { 0x01, 0x12, REGPINNOEOS }; // LED is addressed through Register 0, Pin 0 and Register 1, Pin 1 (zero based)
SetRegPins(myLed); // turn on the LED
Sleep(nMilliSeconds); // delay for a time with the LED lit
ClearRegPins(myLed); // turn the LED back off
}
Edit - A Refinement
A more efficient implementation that would allow multiple pins to be set in a particular register at the same time would be to define the use of RegPinNo as being an unsigned short` with the upper byte being the register number and the lower byte being the pins to manipulate as a bit mask for the byte.
With this approach you would have a SetRegPins() function that would look like the following. A similar change would be needed for the other functions.
void SetRegPins(RegPinNo *x)
{
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 8) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0xFF; // get the pin mask
_PTAD[bRegNo].Byte |= bPinNo;
}
}
And the typedefs would look like:
typedef unsigned short RegPinNo; // upper byte indicates register number 0 - 7, lower byte provides pin mask
const byte REGPINNOEOS = 0xffff; // the end of string for a RegPinNo array.
And these elements would be used like:
void LightLed (int nMilliSeconds)
{
RegPinNo myLed[] = { 0x0002, 0x0103, REGPINNOEOS }; // LED is addressed through Register 0, Pin 1 and Register 1, Pin 0 and Pin 1 (zero based)
SetRegPins(myLed); // turn on the LED
Sleep(nMilliSeconds); // delay for a time with the LED lit
ClearRegPins(myLed); // turn the LED back off
}
Currently I meet one technique issue, which makes me want to improve the previous implementation, the situation is:
I have 5 GPIO pins, I need use these pins as the hardware identifier, for example:
pin1: LOW
pin2: LOW
pin3: LOW
pin4: LOW
pin5: LOW
this means one of my HW variants, so we can have many combinations. In previous design, the developer use if-else to implement this, just like:
if(PIN1 == LOW && ... && ......&& PIN5 ==LOW)
{
HWID = variant1;
}
else if( ... )
{
}
...
else
{
}
but I think this is not good because it will have more than 200 variants, and the code will become to long, and I want changed it to a mask. The idea is I treat this five pins as a five bits register, and because I can predict which variant I need to assign according to GPIOs status(this already defined by hardware team, they provide a variant list, with all these GPIO pins configuration), therefore, the code may look like this:
enum{
variant 0x0 //GPIO config 1
...
variant 0xF3 //GPIO config 243
}
then I can first read these five GPIO pins status, and compare to some mask to see if they are equal or not.
Question
However, for GPIO, it has three status, namely: LOW, HIGH, OPEN. If there is any good calculation method to have a 3-D mask?
You have 5 pins of 3 states each. You can approach representing this in a few ways.
First, imagine using this sort of framework:
#define LOW (0)
#define HIGH (1)
#define OPEN (2)
uint16_t config = PIN_CONFIG(pin1, pin2, pin3, pin4, pin5);
if(config == PIN_CONFIG(LOW, HIGH, OPEN, LOW, LOW))
{
// do something
}
switch(config) {
case PIN_CONFIG(LOW, HIGH, OPEN, LOW, HIGH):
// do something;
break;
}
uint16_t config_max = PIN_CONFIG(OPEN, OPEN, OPEN, OPEN, OPEN);
uint32_t hardware_ids[config_max + 1] = {0};
// init your hardware ids
hardware_ids[PIN_CONFIG(LOW, HIGH, HIGH, LOW, LOW)] = 0xF315;
hardware_ids[PIN_CONFIG(LOW, LOW, HIGH, LOW, LOW)] = 0xF225;
// look up a HWID
uint32_t hwid = hardware_ids[config];
This code is just the sort of stuff you'd like to do with pin configurations. The only bit left to implement is PIN_CONFIG
Approach 1
The first approach is to keep using it as a bitfield, but instead of 1 bit per pin you use 2 bits to represent each pin state. I think this is the cleanest, even though you're "wasting" half a bit for each pin.
#define PIN_CLAMP(x) ((x) & 0x03)
#define PIN_CONFIG(p1, p2, p3, p4, p5) \\
(PIN_CLAMP(p1) & \\
(PIN_CLAMP(p2) << 2) & \\
(PIN_CLAMP(p3) << 4) & \\
(PIN_CLAMP(p4) << 6) & \\
(PIN_CLAMP(p5) << 8))
This is kind of nice because it leaves room for a "Don't care" or "Invalid" value if you are going to do searches later.
Approach 2
Alternatively, you can use arithmetic to do it, making sure you use the minimum amount of bits necessary. That is, ~1.5 bits to encode 3 values. As expected, this goes from 0 up to 242 for a total of 3^5=243 states.
Without knowing anything else about your situation I believe this is the smallest complete encoding of your pin states.
(Practically, you have to use 8 bits to encode 243 values, so it's higher 1.5 bits per pin)
#define PIN_CLAMP(x) ((x) % 3) /* note this should really assert */
#define PIN_CONFIG(p1, p2, p3, p4, p5) \\
(PIN_CLAMP(p1) & \\
(PIN_CLAMP(p2) * 3) & \\
(PIN_CLAMP(p3) * 9) & \\
(PIN_CLAMP(p4) * 27) & \\
(PIN_CLAMP(p5) * 81))
Approach 1.1
If you don't like preprocessor stuff, you could use functions a bit like this:
enum PinLevel (low = 0, high, open);
void set_pin(uint32_t * config, uint8_t pin_number, enum PinLevel value) {
int shift = pin_number * 2; // 2 bits
int mask = 0x03 << shift; // 2 bits set to on, moved to the right spot
*config &= ~pinmask;
*config |= (((int)value) << shift) & pinmask;
}
enum PinLevel get_pin(uint32_t config, uint8_t pin_number) {
int shift = pin_number * 2; // 2 bits
return (enum PinLevel)((config >> shift) & 0x03);
}
This follows the first (2 bit per value) approach.
Approach 1.2
YET ANOTHER WAY using C's cool bitfield syntax:
struct pins {
uint16_t pin1 : 2;
uint16_t pin2 : 2;
uint16_t pin3 : 2;
uint16_t pin4 : 2;
uint16_t pin5 : 2;
};
typedef union pinconfig_ {
struct pins pins;
uint16_t value;
} pinconfig;
pinconfig input;
input.value = 0; // don't forget to init the members unless static
input.pins.pin1 = HIGH;
input.pins.pin2 = LOW;
printf("%d", input.value);
input.value = 0x0003;
printd("%d", input.pins.pin1);
The union lets you view the bitfield as a number and vice versa.
(note: all code completely untested)
This is my suggestion to solve the problem
#include<stdio.h>
#define LOW 0
#define HIGH 1
#define OPEN 2
#define MAXGPIO 5
int main()
{
int gpio[MAXGPIO] = { LOW, LOW, OPEN, HIGH, OPEN };
int mask = 0;
for (int i = 0; i < MAXGPIO; i++)
mask = mask << 2 | gpio[i];
printf("Masked: %d\n", mask);
printf("Unmasked:\n");
for (int i = 0; i < MAXGPIO; i++)
printf("GPIO %d = %d\n", i + 1, (mask >> (2*(MAXGPIO-1-i))) & 0x03);
return 0;
}
A little explanation about the code.
Masking
I am using 2 bits to save each GPIO value. The combinations are:
00: LOW
01: HIGH
02: OPEN
03 is Invalid
I am iterating the array gpio (where I have the acquired values) and creating a mask in the mask variable shifting left 2 bits and applying an or operation.
Unmasking
To get the initial values I am just making the opposite operation shifting right 2 bits multiplied by the amount of GPIO - 1 and masking with 0x03
I am applying a mask with 0x03 because those are the bit I am interested.
This is the result of the program
$ cc -Wall test.c -o test;./test
Masked: 38
Unmasked:
GPIO 1 = 0
GPIO 2 = 0
GPIO 3 = 2
GPIO 4 = 1
GPIO 5 = 2
Hope this helps
Suppose that an instruction aw is code 010 defined by a 32 bit structure as follows:
bits 31-25 unused (all 0s)
bits 24-22: code
bits 21-19: argument 1
bits 18-16: argument 2
bits 15-0: offset (a 16-bit, 2's complement number with a range of -32768 to 32767)
Given the number 8454151, how can I determine if the code is aw?
I tried to shift the number 22 bits, like 8454151 >> 22, but I keep getting 0. Any ideas on how I can obtain the bit information for the code (to check whether it's aw or something else)?
If you just have to verify if an instruction is of a certain operation, the code needing the least cycles would be as follows:
const uint32_t mask = 7 << 22; // Shift 3 set bits by 22 in order to build
// a mask where bits 22-24 are set.
const uint32_t inst_aw = 2 << 22; // Shift the opcode by 22 to build a comparable value
uint32_t instruction = ...; // Your instruction word
if ((instruction & mask) == inst_aw) {
// Do your thing
}
Anyway if you have to build something like an "instruction decoder" or "interpreter", I'd recommend using a lookup table with instruction names (or function pointers) indexed by the instruction code:
/*! \brief Instruction names lookup table. Make sure it has always 8 entries
in order to avoid access beyond the array limits */
const char *instruction_names[] = {
/* 000 */ "Unknown instruction 000",
/* 001 */ "Unknown instruction 001",
/* 010 */ "AW",
...
/* 111 */ "Unknown instruction 111"
};
uint32_t instruction = ...;
unsigned int opcode = (instruction >> 22) & 0x07; // Retrieving the opcode by shifting right 22
// times and mask out all bit except the last 3
printf("Instruction is: %s", instruction_names[opcode]);
A bit shift should work. Be sure to check the data types. You can also "and" the number with 0x01C000 and then compare.