PORT Defines in C Preprocessor

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Greetings all...

In the ongoing process of simplifying my code, I am trying to avoid defining al the relevant PIN/PORT/DDR and just pass them to the header file at compile time.

I see in AVR header files that (Using PORT A as an example) [I checked Mega32 and Mega128]PORTA is deined as:

#define PINA    _SFR_IO8(0x19)
#define DDRA    _SFR_IO8(0x1A)
#define PORTA   _SFR_IO8(0x1B)

My question is would it be valid to define just the port in my calling program and have the header file "calculate the rest" so...
main.c has....

#define myPORT  PORTA

and my header.h has the following..

#ifndef myPORT
 #error" You have not specified a port!! "
#endif
#define myDDR myPORT-1
#define myPIN myPORT-2

Is this valid? (will try anyway) is there a more elegant way?

Thanks

T[/b]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But PORTA is not defined as 0x1B (so that 0x1B-1 = 0x1A and so on). It is defined as "_SFR_IO8(0x1B)" and _SFR_IO8 itself is defined elsewhere as a macro.

So no, this idea is not going to work because "_SFR_IO8(0x1B)-1" does not make sense.

#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + 0x20)
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))

So PORTA-1 is

_SFR_IO8(0x1A)-1

which is

_MMIO_BYTE((0x1A) + 0x20)-1

which is

(*(volatile uint8_t *)(0x3A))-1

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The example below does work:

#define DDR(x)	(*(&x - 1))
#define PIN(x)	(*(&x - 2))

#define myPORT  PORTA

DDR(myPORT) = 0xFF;

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tomasch wrote:

#ifndef myPORT
 #error" You have not specified a port!! "
#endif
#define myDDR myPORT-1
#define myPIN myPORT-2


The relationship that you've expressed between the PORTx, PINx and DDRx addresses does not always hold. For example, on the mega128 PORTF is 0x62, DDRF is 0x61 and PINF is 0x00. Interestingly, address 0x60 is "reserved" so I conjectured that PINF might be mirrored at that address. Alas, it is not.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

why not use the concatenation operator

#define myBANK A

#define myPORT PORT ## myBANK
#define myPIN  PIN ## myBANK
#define myDDR  DDR ## myBANK

this will produce
PORTA for myPORT, PINA for myPIN, and DDRA for myDDR.

This should get around any issues where the addresses are not consecutive, by keeping the symbolic name.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:


#define myBANK A

#define myPORT PORT ## myBANK
#define myPIN  PIN ## myBANK
#define myDDR  DDR ## myBANK

I Like this one best of all - will try and see if it works!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

#define myBANK A

#define myPORT PORT ## myBANK
#define myPIN PIN ## myBANK
#define myDDR DDR ## myBANK

That's what I first came up with when I saw this thread - alas, the preprocessor concats each to be "PORTmyBANK", "PINmyBANK" and "DDRmyBANK", rather than the substitution desired. Couldn't get it to work correctly no matter what I tried. Perhaps someone else will have more luck?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You're right... it doesn't evaluate at the top level. It does however evaluate internally... but I can't think of a way to make one macro make 3 new defines.

for instance

#define MKPORT(_BANK) PORT ## _BANK

with the above macro I will get a port called whatever value was passed to _BANK, and not PORT_BANK.
so

#define myPORT MKPORT(A)

will work giving us myPORT => PORTA

unfortunately

#define myBANK A
#define myPORT MKPORT(myBANK)

does not, it will result in myPORT => PORTmyBANK still

I can't think of any way to force the pre-processor to evaluate myBANK before passing it forward.

All that I can come up with is a really ugly hack, that would use conditionals.

// the bank letter must be in
// single quotes, so it evaluates
// to a number for pre-processor
#define myBANK 'C'

#if myBANK == 'A'
#define myPORT PORTA
#define myPIN PORTA
#define myDDR PORTA
#elif myBANK == 'B'
#define myPORT PORTB
#define myPIN PORTB
#define myDDR PORTB
#elif myBANK == 'C'
#define myPORT PORTC
#define myPIN PORTC
#define myDDR PORTC
#elif myBANK == 'D'
#define myPORT PORTD
#define myPIN PORTD
#define myDDR PORTD
#elif myBANK == 'E'
#define myPORT PORTE
#define myPIN PORTE
#define myDDR PORTE
#elif myBANK == 'F'
#define myPORT PORTF
#define myPIN PORTF
#define myDDR PORTF
#elif myBANK == 'G'
#define myPORT PORTG
#define myPIN PORTG
#define myDDR PORTG
// continue the chain of if/else clauses for all possible values
// since AVR ports follow a common naming scheme, this is easy
// but ugly
#else
  #ifdef myBANK
    #error Invalid value for 'myBANK'
  #else
    #error 'myBANK' must be defined
  #endif
#endif

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

Last Edited: Thu. Apr 12, 2007 - 04:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

The trick here is in a double macro definition. In stdint.h is

/* Helping macro */
#ifndef __CONCAT
#define __CONCATenate(left, right) left ## right
#define __CONCAT(left, right) __CONCATenate(left, right)
#endif

Using those macros or similar

#define myBANK A

#define myPORT __CONCAT(PORT, myBANK)
#define myPIN __CONCAT(PIN, myBANK)
#define myDDR __CONCAT(DDR, myBANK)

This way the parameters are substituted before the concatenation even when they are also macro. See cpp manual (Chapter 3: Macros. 3.4 Stringification & 3.5 Concatenation) in http://gcc.gnu.org/onlinedocs/cpp

Best regards.

Carlos.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nice find... I tried something like that earlier but it didn't seem to work. Obviously did something wrong.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yup, Carlos - that did the trick. Essentially, I'm trying to minimize the amount of changes I have to make in the various files to get a project going. As it stands, I'm even (puts on flame retardant suite) thinking of combining the .c and .h files into a single file so I do not have to keep changing my makefile - just #include the .h file in the main code.
Too many "modules"

Tom

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you considered conditional compiling of the modules instead?

I tend to call my makefile with options so that the same makefile can include or exclude certain optional software components. Usually that means including support for various displays, or communication networks, etc.

My advice is to not put code into the header files, but instead use make to selectively compile.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tomasch wrote:
thinking of combining the .c and .h files into a single file so I do not have to keep changing my makefile

Silly question - how on earth are .h and the Makefile connected in ANY way? (except maybe the -I parms to the compilation?)

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
tomasch wrote:
thinking of combining the .c and .h files into a single file so I do not have to keep changing my makefile

Silly question - how on earth are .h and the Makefile connected in ANY way? (except maybe the -I parms to the compilation?)

Cliff

They aren't related. Imagine he wishes to do a compilation which includes LCD support. In his main.c file he could uncomment a line which reads:

// #include "lcd.h"

with the c code in the h file, the lcd code is now included. I've seen it done in some code that was developed in china, not very nice.

This would just save going to the makefile and uncommenting a line which would probably be

# lcd.c \

in the source list. No real saving anyway imo. It's easier (for me) to pass module options to make for the one makefile, or else have more than one makefile with each makefile including the source list relavant to its module options.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nope, still don't get it - as long as there's no data or code definition in a .h then there's not usually much danger in including an lcd.h or whatever from which nothing is actually used. 'course the excpetion to this is if it #defines something that causes a different compilation path to be taken in something like a #ifdef/#else

Course if someone is mad enough to put variable or function definitions into a .h then they kind of deserve all that's coming to them!

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Course if someone is mad enough to put variable or function definitions into a .h then they kind of deserve all that's coming to them!

Notice I said I was putting on my flame retardant suite ;-)

I know it's not "Good form," but.
Let's say I have a main.c that uses the following

 #include "myLCD.h"
#include "myOneWire.h"
#include "mySerial.h"
#include "myDS18B20.h"
etc...

I have to change my makefile so that it reads

SRC = $(TARGET).c MyLCD.c myOneWire.c mySerial.c myDS18B20.c etc...

I need to keep modifying the makefile for every project depending on what #includes I uses.
If I have my defines and code in the .h file - I just include it in my main.c and off I go. I keep one makefile "master" that I copy from project directory to project directory and I don't have "non used" code compiled into my project.

I know it's not "proper" but keeps things in order for me.

T

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The "proper" solution in that case -- if the various .c files are coded such that they're independent of the rest of the project they're being used with -- would be to precompile each of the .c files into .o files, and then use the librarian to gather all the .o files into a .a file (library).

Then, tell the linker to link against that generic .a file as part of every project. The result will be that only the specific modules that are actually referenced by your application source code will actually end up being included as part of the final executable.