Go Down

Topic: Trick for getting PORT / SFR_IO address (Read 204 times) previous topic - next topic

fabriceo

Hi every one;

I ve just put my head on a problem where I was trying to get the adress of an arduino port into an expression and now just sharing with the community the trick I found for this:

Basically all the arduino SFR like PORTB or TIFR0 are declared from the sfr_defs.h.

2 macro are used:
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)

and then each register is defined like this:
#define PORTB _SFR_IO8(0x05)
#define TIFR0 _SFR_IO8(0x15)

by this way, you can read a register directly like:
uint8_t XX = PORTB;

but if you just want to get the adress of PORTB (0x25) and TIFR0 (0x35) you cannot just write
uint8_t ADDR = &TIFR0;
as you get a compiler error:
invalid conversion from 'volatile uint8_t* {aka volatile unsigned char*}' to 'uint8_t {aka unsigned char}'

so the trick is to typecast all of that but with using the void cast in between, here is a macro:

#define GPIO_ADDR(port) reinterpret_cast<uint16_t> ((volatile void *)(&port))
uint8_t AddrTIFR0 = GPIO_ADDR(TIFR0);

and voila

I was needing this trick to be able to pass a SFR as a tempate uint8_t argument and using this approach is working well

hope this will be of interrested to some of us
cheers


fabriceo

#1
Jun 15, 2016, 12:45 pm Last Edit: Jun 15, 2016, 01:11 pm by fabriceo
Well,
I can propose a typical example of using this trick for a class which gives the possibility to declare digitalpins with direct access to ports, while providing a nice way of abstracting it in the source code:

Code: [Select]
#define sfr_addr(sfr) reinterpret_cast<unsigned> ((volatile void *)(&sfr))

template < const uint8_t sfr, const uint8_t bit>
struct sfr_bit {
inline void high() { *(uint8_t volatile *)sfr |= 1<<bit;}
inline void low()  { *(uint8_t volatile *)sfr &= ~(1<<bit);}
inline unsigned read() {
if (*(uint8_t volatile *)sfr & 1<<bit) return 1; else return 0; }
inline  operator unsigned () { return read(); }
inline sfr_bit operator =(const unsigned value) {
if (value==0) low(); else high(); return *this;  }
};

sfr_bit< sfr_addr(PORTB), 6 > myLed;

void setup() {
  uint8_t oldLed = myLed;
  myLed = 1; }


it is possible to declare each IO with the sfr_bit tempate, and then to access each instances either in an expression or using the = assignement operator
Thanks to GCC the resulting code is just as compact as it can be using bit instructions

hope this is usefull and as fun as I wanted it to be

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy