AVR clean pin aliasing solution - enumerating I/O bits - c

I'm working in C on an Arduino device, where the pins are labeled differently. I'm using PLAIN C though, not the Arduino "language".
Each pin is defined by it's port (eg. PORTB) and pin (bit) in the port (eg. PB0).
I'd like to concisely alias pins, so I could make macros or functions somewhat like what the Arduino uses:
pin_direction(D2, 1); // D2 as output
set_pin(D2, 0); // write zero to D2
pin_direction(D3, 0); // D3 as input
enable_pullup(D3, 1); // enable D3 pullup
Instead (atm) I have to use something ugly like this:
#define D0 0
#define D1 1
#define D2 2
#define D3 3
...
#define D10 2
#define D11 3
#define PORT_D0 PORTD
#define PORT_D1 PORTD
#define PORT_D2 PORTD
#define PORT_D3 PORTD
...
#define PORT_D10 PORTB
#define PORT_D11 PORTB
// the same for PIN_xx and DDR_xx
And then I can use macros to do the work:
#define sbi(port, bit) (port) |= _BV(bit)
#define cbi(port, bit) (port) &= ~ _BV(bit)
sbi(DDR_D2, D2); // D2 to output
cbi(PORT_D2, D2); // D2 to output
sbi(DDR_D3, D3); // D3 as input
sbi(PORT_D3, D3); // D3 pullup enable
Now this works, but it's very messy. Any idea how to - without a monster overhead of something like huge switch - do this better - more like my first example? Somehow enumerate all bits and then resolve the right register on the fly?
I'm using avr-gcc with avr-libc.

You can define macros which expand to multiple tokens, e.g.
#define PIN_D0 PORTD, 0
#define PIN_D1 PORTD, 1
...
#define PIN_D10 PORTB, 2
Then use them in macros such as:
sbi(PIN_D0); // expands to sbi(PORTD, 0)
Some utility macros that may be useful with these macros are:
#define PORT_OF(port, bit) port
#define BIT_OF(port, bit) bit
which can be used in contexts such as:
PORT_OF(PIN_D10) // expands to PORTB
BIT_OF(PIN_D10) // expands to 2

Here's the solution I use.
In my util.h (common to all my AVR projects):
#define DDR_REG(port) DDR ## port
#define PORT_REG(port) PORT ## port
#define PIN_REG(port) PIN ## port
#define SET_BIT(port, bit) do { (port) |= (1 << (bit)); } while(0)
#define CLR_BIT(port, bit) do { (port) &= ~(1 << (bit)); } while(0)
#define BIT_IS_SET(port, bit) ((((uint8_t)(port)) >> ((uint8_t)(bit))) & 0x1)
#define IO_SET_INPUT_AUX(port, bit) CLR_BIT(DDR_REG(port), bit)
#define IO_SET_AS_INPUT(io) IO_SET_INPUT_AUX(io)
#define IO_SET_OUTPUT_AUX(port, bit) SET_BIT(DDR_REG(port), bit)
#define IO_SET_AS_OUTPUT(io) IO_SET_OUTPUT_AUX(io)
#define IO_OUTPUT_0_AUX(port, bit) CLR_BIT(PORT_REG(port), bit)
#define IO_OUTPUT_0(io) IO_OUTPUT_0_AUX(io)
#define IO_OUTPUT_1_AUX(port, bit) SET_BIT(PORT_REG(port), bit)
#define IO_OUTPUT_1(io) IO_OUTPUT_1_AUX(io)
#define IO_GET_INPUT_AUX(port, bit) BIT_IS_SET(PIN_REG(port), bit)
#define IO_GET_INPUT(io) IO_GET_INPUT_AUX(io)
In my pin mappings file:
#define UPBTN_IO B,7
#define DOWNBTN_IO D,0
#define ENTERBTN_IO D,1
(etc)
In code:
IO_SET_AS_INPUT(UPBTN_IO);
This relies on some fun preprocessor bits, like there only being one round of macro expansion on macro parameters.

Related

simple arduino code without using avr headers in avr-libc

I have this simple code
That I am trying to compile for arduino microcontroller and without using avr headers. I just defined all macros in my source program file
but my gcc-avr says
led.c:15:8: error: lvalue required as left operand of assignment
DDRB |= 0B100000; // PORTB5 1010
^
Now I can expect this error on some cpu that io area is not virtual memory space of this process but I am running my code on mocrocontroller that must have execution bit. how to get rid of this message and compile it and able to run on arduino
But the gcc-avr throws error that
#define F_CPU 16000000
#define BLINK_DELAY_MS 5000
#include <util/delay.h>
#define __SFR_OFFSET 0x20
#define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET)
#define DDRB _SFR_IO8(0x04)
#define PORTB _SFR_IO8(0x05)
int main (void)
{
// Arduino digital pin 13 (pin 5 of PORTB) for output
DDRB |= 0B100000; // PORTB5 1010
while(1) {
// turn LED on
PORTB |= 0B100000; // PORTB5
// _delay_ms(BLINK_DELAY_MS);
int x=0;
while(x<25)
{
x++;
}
x=0;
// turn LED off
PORTB &= ~ 0B100000; // PORTB5
//hello
while(x<25)
{
x++;
}
//_delay_ms(BLINK_DELAY_MS);
}
}
The problems are the macros, you are defining the register as an integer, not as an address to an integer.
DDRB expands to 0x04 + 0x20 so you end up with code like (0x04 + 0x20) |= 0B100000;. You should be able to fix this with a cast and then de-reference:
#define _SFR_IO8(io_addr) ( *(volatile uint8_t*) ((io_addr) + __SFR_OFFSET) )
For details see How to access a hardware register from firmware?
Please also note that macros starting with double underscore __ are reserved for the compiler, so we should never use that or we might end up with naming collisions.

How to define a macro of two tokens in Cpp

In my Arduinoc (cpp) code, I have these macros that set/clear bit y of register x:
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
In several places I then use:
CLEAR(PORTB,7)
or
SET(PORTB,7)
I would like to define a macro to be PORTB,7 so it only appear once, in a header file, not all over my code. (I show only one example, but I have several conbinations of PORTx,N in my code).
I tried:
#define CLOCK PORTB,7
#define CLOCK_HIGH SET(CLOCK)
but it then fails to build with:
error: macro "SET" requires 2 arguments, but only 1 given CLOCK_HIGH; delay(DELAY); CLOCK_LOW; delay(DELAY);
Is there a way to achieve that?
You must first expand the macro inside. Ie. do another pass. Your code may look like this:
#define SET(x,y) do{ (x) |= (1u << (y)); }while(0)
#define CLEAR(x,y) do{ (x) &= ~(1u << (y)); }while(0)
#define HIGH(a) SET(a) // another empty pass, just forward
// the `a` is expanded and the second `SET` takes two arguments
// or better, but not fully compliant:
// #define HIGH(...) SET(__VA_ARGS__)
#define CLOCK PORTB, 7
#define CLOCK_HIGH() HIGH(CLOCK)
int main() {
int PORTB;
CLOCK_HIGH();
}
As a good measure research about macro pitfalls and research good practices when writing macros..

Use #define to specify multiple paramaters [duplicate]

I want to be able to define a tuple which represents the arguments needed by other macros.
I think the best way to show what I want is to show an example:
#include <avr/io.h>
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_PIN PB7
#define LED LED_PORT, LED_DDR, LED_PIN
#define OUTPUT(port, ddr, pin) ddr |= 1 << pin
void main(void) {
OUTPUT(LED);
}
I want OUTPUT(LED) to be then expanded into:
LED_DDR |= 1 << LED_PIN
The problem that I get is to do with the order of expansion, and results in the following error:
macro "OUTPUT" requires 3 arguments, but only 1 given
This is for use with an AVR project with custom built hardware where I have defined LED and other components with a respective LED_PORT LED_DDR and LED_PIN.
I then want to define more macros that can take this LED and use the appropriate arguments to map to the most succinct way possible.
Is this possible with the standard C-preprocessor?
You can add a level of indirection to the macro to achieve this:
#define OUTPUT_I(port, ddr, pin) ddr |= 1 << pin
#define OUTPUT(spec) OUTPUT_I(spec)
During rescanning, spec is expanded before OUTPUT_I, so the OUTPUT_I macro sees three parameters.

#define a tuple in C

I want to be able to define a tuple which represents the arguments needed by other macros.
I think the best way to show what I want is to show an example:
#include <avr/io.h>
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_PIN PB7
#define LED LED_PORT, LED_DDR, LED_PIN
#define OUTPUT(port, ddr, pin) ddr |= 1 << pin
void main(void) {
OUTPUT(LED);
}
I want OUTPUT(LED) to be then expanded into:
LED_DDR |= 1 << LED_PIN
The problem that I get is to do with the order of expansion, and results in the following error:
macro "OUTPUT" requires 3 arguments, but only 1 given
This is for use with an AVR project with custom built hardware where I have defined LED and other components with a respective LED_PORT LED_DDR and LED_PIN.
I then want to define more macros that can take this LED and use the appropriate arguments to map to the most succinct way possible.
Is this possible with the standard C-preprocessor?
You can add a level of indirection to the macro to achieve this:
#define OUTPUT_I(port, ddr, pin) ddr |= 1 << pin
#define OUTPUT(spec) OUTPUT_I(spec)
During rescanning, spec is expanded before OUTPUT_I, so the OUTPUT_I macro sees three parameters.

Setting a flag in C as elegantly as in assemby language

Flags handling in C feels cumbersome, compared to assembly.
I am looking for a way to make the C code as readable as assembly.
In Assembly:
#define powerOn flagsByte,0
...
bsf powerOn ; Turn on the power
bcf powerOn ; Turn off the power
btfsc powerOn ; If the power is on...
In C:
flagsByte |= (1 << 0) ; // Turn on the power
flagsByte &= ~(1 << 0) ; // Turn off the power
if (flagsByte & (1 << 0)); // If the power is on...
In C, with a macro:
#define BIT_SET(var,bitNo) (var |= (1<<(bitNo)))
BIT_SET(flagsByte,0) ; // Turn on the power
That works, but it's still not as clean as in assembly.
I'd love to do:
#define powerOn flagsByte,0
BIT_SET(powerOn) ; // Turn on the power
But that doesn't work, because it expands to:
flagsByte,0 |= (1<<())
instead of:
flagsByte |= (1<<(0))
Question:
Is there an elegant way in C to set, clear or test a flag that is defined as follows?
#define powerOn flagsByte,0
Personally, I prefer the bit-field syntax, and without macros since my flags are almost always inside structs anyway. However, if you insist on writing assembler in C, here's how:
/* We need to indirect the macro call so that the pair of arguments get expanded */
#define BITSET_(f,i) do{f|= 1<<(i);}while(0)
#define BITCLR_(f,i) do{f&=~(1<<(i));}while(0)
#define BITCHK_(f,i) ((f)&(1<<(i)))
#define BITSET(fi) BITSET_(fi)
#define BITCLR(fi) BITCLR_(fi)
#define BITCHK(fi) BITCHK_(fi)
/* Define the flag container and bit number as per OP */
#define poweron flags1,0
#define warnuser flags7,4
/* Sample uses */
BITSET(poweron);
BITCLR(warnuser);
/* Since BITCHK expands to a parenthesized expression, I can get away with
* leaving out the parentheses in the if statement. Not saying that's a good
* idea or anything.
*/
if BITCHK(poweron) BITSET(warnuser);
If you have gcc, you can verify this with gcc -E flag_macros.c
Here's a set of macros closely matching your assembly example:
#define powerOn 0
#define someotherfield 1
#define BITMASK(field) (1u << (field))
#define SET(field) do { flagsByte |= BITMASK(field); } while(0)
#define CLR(field) do { flagsByte &= ~BITMASK(field); } while(0)
#define TEST(field) (flagsByte & BITMASK(field))
/* Use examples */
SET(powerOn);
CLEAR(powerOn);
if (TEST(powerOn)) {
// Danger!
}
Here's a variant that allows you to include the variable in the particular field definition. It's a bit tricky as it involves argument prescan
#define powerOn flagsByte,0
#define someotherfield flagsByte,1
#define BITMASK(field) (1u << (field))
#define _SET(var, field) do { var |= BITMASK(field); } while(0)
#define SET(x) _SET(x)
/* Use examples */
SET(powerOn);
You could #define powerOn flagsByte |= (1 << 0); and then just use it like a statement. As in
// do stuff...
powerOn; // Turn power on.
// do stuff...
With GCC you can define so-called bit fields and manipulate them like struct members:
struct flagsByte
{
unsigned int powerOn: 1; /* single bit */
};
flagsByte.powerOn = 0;
flagsByte.powerOn = 1;
Building upon this, it is possibile to define a couple of trivial macros, reminiscent of Assembly:
#define bsf(X) flagsByte.(X) = 1
#define bcf(X) flagsByte.(X) = 0
and simply write
bsf(powerOn); /* set flag */
bcf(powerOn); /* clear flag */
Unfortunately, this is not applicable to every C compiler.
You do this with a second expansion.
~/sandbox/20$ cat >t.c
#define BITSET_INNER(a,b) a |= (1<<b)
#define BITSET(spec) BITSET_INNER(spec)
#define f1 flagword,3
BITSET(f1)
~/sandbox/20$ cc -E t.c
# 1 "t.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "t.c"
flagword |= (1<<3)
Add token pasting and a with a strong gorge you can get some extremely gratifying results out of the C preprocessor.
You could just define some constants, not using the preprocessor but enums for fewer surprises:
enum flags{
powerOn = 1<<0,
powerMask = ~powerOn,
/*...*/
};
And use them like this:
flagsByte |= power;
flagsByte &= ~power;
flagsByte &= powerMask; /* same as previous line */
A good rule of thumb in C (and C++): Do not use the preprocessor if you can avoid it.
Anyway, if you can live with the inherent implementation-definedness of bitfields, use bitfields as Roberto Reale proposes.

Resources