Go Down

Topic: Trick for getting PORT / SFR_IO address (Read 441 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