Search |
 |
|
 |
| Author |
Message |
|
|
Posted: Feb 14, 2012 - 10:00 PM |
|

Joined: Nov 17, 2008
Posts: 20
|
|
Hi,
I'm trying to write macros, which would simplify management of pins.
I'd like to be able to assign a symbolic name to the particular pin of certain port, using syntax like this (stating, that pin 2 of port D is used to control the motor):
Code:
DECL_PIN(MOTOR_ON, D, 2)
Then I'd like to be able to use macros like below:
Code:
DIR_OUT(MOTOR_ON)
to set this pin to output and
Code:
DIR_IN(MOTOR_ON)
to set it to input,
Code:
SET_PIN(MOTOR_ON)
to set it to 1, or
Code:
CLR_PIN(MOTOR_ON)
to set it to 0.
Code:
CHK_PIN(MOTOR_ON)
to check the state of the pin
Currently I use the approach, in which I declare four macros
for each pin:
Code:
#define DDR_POWER_ON DDRD
#define PINNR_POWER_ON 2
#define PORT_POWER_ON PORTD
#define PIN_POWER_ON PIND
And then I can define the above mentioned macros in the following form:
Code:
#define DIR_OUT(NAME) DDR_ ## NAME |= (1 << PINNR_ ## NAME)
#define DIR_IN(NAME) DDR_ ## NAME &= ~(1 << PINNR_ ## NAME)
#define SET_PIN(NAME) PORT_ ## NAME |= (1 << PINNR_ ## NAME)
#define CLR_PIN(NAME) PORT_ ## NAME &= ~(1 << PINNR_ ## NAME)
#define CHK_PIN(NAME) ( PIN_ ## NAME & (1 << PINNR_ ## NAME) ) ? 1 : 0 )
Unfortunately definitions of the DDR_NAME, PORT_NAME, PIN_NAME and PINNR_NAME are difficult to maintain (especially when I have to change a design slightly and to move particular function to another pin/port).
I'd definitely prefere the single macro like
Code:
DECL_PIN(MOTOR_ON, D, 2)
but I don't know how to achieve that.
Unfortunately it is not possible to make something like this:
Code:
#define DECL_PIN_(NAME,PORT) #define PIN_ ## #NAME PIN ## #PORT
#define DECL_PORT(NAME, PORT) #define PORT_ ## NAME PORT ## #PORT
#define DECL_DDR(NAME, PORT) #define DDR_ ## NAME DDR ## #PORT
#define DECL_PINNR(NAME, NR) #define PINNR_ ## NAME #NR
#define DECL_PIN(NAME,PORT,NR) DECL_DDR(#NAME, #PORT, #NR) \
DECL_PORT(#NAME, #PORT) \
DECL_PINNR(#NAME, #NR) \
DECL_PIN_(#NAME, #PORT)
Currently I generate the definitions of the PORT_NAME, DDR_NAME, PINNR_NAME and PIN_NAME in a separate header file with a Python script from a
text file containing definitions like below:
Code:
[...]
MOTOR_ON D 4
RED_LED C 5
[...]
It can also be done with awk, but I'd prefere to have a solution based only on avr-gcc and the preprocesor...
Is it possible to implement it in a simple and reliable way?
PS.
The sample awk script generating the macros from the above list may look like below:
Code:
#!/usr/bin/awk -f
$1 $2 $3 {
print "#define DDR_" $1 " DDR" $2;
print "#define PORT_" $1 " PORT" $2;
print "#define PIN_" $1 " PIN" $2;
print "#define PINNR_" $1 " " $3;
}
|
|
|
| |
|
|
|
|
|
Posted: Feb 14, 2012 - 10:46 PM |
|

Joined: Oct 29, 2006
Posts: 2689
|
|
|
wzab66 wrote:
I'm trying to write macros, which would simplify management of pins.
I'd like to be able to assign a symbolic name to the particular pin of certain port, using syntax like this (stating, that pin 2 of port D is used to control the motor):
Code:
DECL_PIN(MOTOR_ON, D, 2)
For my own work, I've used code like
Code:
#define MOTOR_ON_LET D
#define MOTOR_ON_BIT 2
Quote:
Then I'd like to be able to use macros like below:
Code:
DIR_OUT(MOTOR_ON)
to set this pin to output and
Code:
DIR_IN(MOTOR_ON)
to set it to input,
Code:
SET_PIN(MOTOR_ON)
to set it to 1, or
Code:
CLR_PIN(MOTOR_ON)
to set it to 0.
Code:
CHK_PIN(MOTOR_ON)
to check the state of the pin
I called mine dset, dclr, pset, pclr and pval.
Quote:
Currently I use the approach, in which I declare four macros
for each pin:
Code:
#define DDR_POWER_ON DDRD
#define PINNR_POWER_ON 2
#define PORT_POWER_ON PORTD
#define PIN_POWER_ON PIND
You only need two POWER_ON-specific macros.
The rest can be done with the preprocessor.
The following macros will help:
Code:
#define xpaste(a,b) a ## b
#define paste(a,b) xpaste(a,b)
Use paste.
Quote:
And then I can define the above mentioned macros in the following form:
Code:
#define DIR_OUT(NAME) DDR_ ## NAME |= (1 << PINNR_ ## NAME)
#define DIR_IN(NAME) DDR_ ## NAME &= ~(1 << PINNR_ ## NAME)
#define SET_PIN(NAME) PORT_ ## NAME |= (1 << PINNR_ ## NAME)
#define CLR_PIN(NAME) PORT_ ## NAME &= ~(1 << PINNR_ ## NAME)
#define CHK_PIN(NAME) ( PIN_ ## NAME & (1 << PINNR_ ## NAME) ) ? 1 : 0 )
Unfortunately definitions of the DDR_NAME, PORT_NAME, PIN_NAME and PINNR_NAME are difficult to maintain (especially when I have to change a design slightly and to move particular function to another pin/port).
Quote:
PS.
The sample awk script generating the macros from the above list may look like below:
Code:
#!/usr/bin/awk -f
$1 $2 $3 {
print "#define DDR_" $1 " DDR" $2;
print "#define PORT_" $1 " PORT" $2;
print "#define PIN_" $1 " PIN" $2;
print "#define PINNR_" $1 " " $3;
}
Before I decided to trust the preprocessor, I used python.
Actually, if you work at it, you only need one POWER_ON-specific macro, e.g.
Code:
#define POWER_ON_LETBIT D2
How to use it is left as an exercise for the reader. |
_________________ Michael Hennebry
Iluvatar is the better part of Valar.
|
| |
|
|
|
|
|
Posted: Feb 15, 2012 - 12:10 AM |
|

Joined: Dec 20, 2007
Posts: 946
Location: Portland, Oregon, USA
|
|
| How often do you find yourself needing to set up the data direction register bits for your hardware? If it's every tenth line of your application, then go ahead and make macros for them. I usually find, however, that "setting up" operations happen oh, about exactly ONE TIME in an entire application. So, weighing pros and cons, we wind up comparing the writing and maintaining of dozens of lines of obfuscating macros to allegedly "simplify" (or beautify, or better-ize) a section of code that would take fewer lines to write straightforwardly. If idioms like (1 << SOME_BIT_NAME) are obscure, address that by adding a comment line that explains what you're intending to initialize and why; something along the lines of
Code:
// The solenoid - driver transistor's base is driven by
// pin 4 of PortD, so let's make it an output
//
DDRD |= (1 << 4);
|
|
|
| |
|
|
|
|
|
Posted: Feb 15, 2012 - 08:31 AM |
|

Joined: Nov 17, 2008
Posts: 20
|
|
|
Quote:
How often do you find yourself needing to set up the data direction register bits for your hardware? If it's every tenth line of your application, then go ahead and make macros for them. I usually find, however, that "setting up" operations happen oh, about exactly ONE TIME in an entire application. So, weighing pros and cons, we wind up comparing the writing and maintaining of dozens of lines of obfuscating macros to allegedly "simplify" (or beautify, or better-ize) a section of code that would take fewer lines to write straightforwardly. If idioms like (1 << SOME_BIT_NAME) are obscure, address that by adding a comment line that explains what you're intending to initialize and why; something along the lines of
Code:
// The solenoid - driver transistor's base is driven by
// pin 4 of PortD, so let's make it an output
//
DDRD |= (1 << 4);
I agree, but I often find myself reusing the same code in different hardware (different board layout or different AVR model).
Therefore I prefere to have all information about the usage of pins concentrated in one place, to avoid discrepancy. |
|
|
| |
|
|
|
|
|
Posted: Feb 15, 2012 - 08:35 AM |
|

Joined: Sep 05, 2001
Posts: 2508
|
|
|
|
|
|
|
Posted: Feb 15, 2012 - 04:40 PM |
|

Joined: Nov 17, 2008
Posts: 20
|
|
|
Quote:
There are several ways.
You can use my sbit.h:
http://www.avrfreaks.net/index.php?name ... 728#835728
Or my macros:
http://www.avrfreaks.net/index.php?name ... mp;t=91304
Peter
Thanks a lot. Especially the set of macros provided by gromit64 in the second thread is very interesting, as it provides the same fucntionality as my python/awk based solution but using the preprocessor alone.
Thanks,
Wojtek |
|
|
| |
|
|
|
|
|
Posted: Feb 15, 2012 - 05:39 PM |
|


Joined: Feb 19, 2001
Posts: 26102
Location: Wisconsin USA
|
|
|
Quote:
Especially the set of macros provided by gromit64 in the second thread is very interesting
Yes, indeed.
As bit_set() and bit_clear() have "PORT" in them we can extrapolate that these macros are for AVR port work only and not to work with e.g. TCCR0B/WGM02. Thus for completness it might be useful to add a bit_toggle() that would apply to PINx on all modern AVR models. |
|
|
| |
|
|
|
|
|
Posted: Feb 15, 2012 - 07:03 PM |
|

Joined: Oct 29, 2006
Posts: 2689
|
|
|
Levenkay wrote:
How often do you find yourself needing to set up the data direction register bits for your hardware? If it's every tenth line of your application, then go ahead and make macros for them. I usually find, however, that "setting up" operations happen oh, about exactly ONE TIME in an entire application. So, weighing pros and cons, we wind up comparing the writing and maintaining of dozens of lines of obfuscating macros to allegedly "simplify" (or beautify, or better-ize) a section of code that would take fewer lines to write straightforwardly. If idioms like (1 << SOME_BIT_NAME) are obscure, address that by adding a comment line that explains what you're intending to initialize and why; something along the lines of
Code:
// The solenoid - driver transistor's base is driven by
// pin 4 of PortD, so let's make it an output
//
DDRD |= (1 << 4);
My code would look something like this:
Code:
#include "portbits.h"
// the only two solenoid-specific macros
// If there is only one top-level source file,
// a header file would not be necessary for them.
#define solenoid_LET D
#define solenoid_BIT 4
...
dset(solenoid);
...
pset(solenoid);
...
pclr(solenoid);
...
If a redesign moved the solenoid to B6,
only two lines would need changing
and they would be adjacent.
Coding for maintenance. |
_________________ Michael Hennebry
Iluvatar is the better part of Valar.
|
| |
|
|
|
|
|
Posted: Feb 15, 2012 - 09:13 PM |
|

Joined: May 24, 2004
Posts: 6028
Location: Tampere, Finland
|
|
I have been here too, but why make it more complex than it should be?
Why define some macros that are used to access bits directly, why not define macros or functions that are used to access functionality of the board after initializing it?
For example a solenoid is used so rarely you can have the overhead of a function call, but not all things are like this, so they could be inline functions or macros. |
|
|
| |
|
|
|
|
|
Posted: Feb 19, 2012 - 05:18 PM |
|


Joined: Jul 25, 2002
Posts: 68
Location: Paderborn, Germany
|
|
|
|
|
|
|
|
|
|