Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
wzab66
PostPosted: Feb 14, 2012 - 10:00 PM
Rookie


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;
  }
 
 View user's profile Send private message  
Reply with quote Back to top
skeeve
PostPosted: Feb 14, 2012 - 10:46 PM
Raving lunatic


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.
 
 View user's profile Send private message  
Reply with quote Back to top
Levenkay
PostPosted: Feb 15, 2012 - 12:10 AM
Resident


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);
 
 View user's profile Send private message  
Reply with quote Back to top
wzab66
PostPosted: Feb 15, 2012 - 08:31 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
danni
PostPosted: Feb 15, 2012 - 08:35 AM
Raving lunatic


Joined: Sep 05, 2001
Posts: 2508


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
 
 View user's profile Send private message  
Reply with quote Back to top
wzab66
PostPosted: Feb 15, 2012 - 04:40 PM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
theusch
PostPosted: Feb 15, 2012 - 05:39 PM
10k+ Postman


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.
 
 View user's profile Send private message  
Reply with quote Back to top
skeeve
PostPosted: Feb 15, 2012 - 07:03 PM
Raving lunatic


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.
 
 View user's profile Send private message  
Reply with quote Back to top
Jepael
PostPosted: Feb 15, 2012 - 09:13 PM
Raving lunatic


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.
 
 View user's profile Send private message  
Reply with quote Back to top
heinrichs.hj
PostPosted: Feb 19, 2012 - 05:18 PM
Wannabe


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

wzab66,
you could also have a look at my generic approach for GPIOs:
http://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=1036

heinrichs.hj
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits