Go Down

Topic: SOLVED - How to make an array of registers? (Read 69 times) previous topic - next topic

krupski

Oct 02, 2017, 11:17 pm Last Edit: Oct 02, 2017, 11:52 pm by krupski
Hi all,

I want to do something like this:

Code: [Select]

uint16_t registers[] = {
    PCMSK0,
    PCMSK1,
    PCMSK2,
};


So then, for example, to access "PCMSK1", I could do this:

Code: [Select]

registers[1] |= (_BV(PCINT10)|_BV(PCINT9)); // enable pin change int for 9 & 10


I searched lots of places and tried all combinations of indirection I could think of... can't get it to work.

NOTE: This will be for code running on an Arduino MEGA, but NOT written or compiled with the IDE. I'm using GCC and a Makefile, so I can't depend on any stuff in "Arduino.h".  I need the "nitty-gritty" how to do the above.

Thanks!

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Delta_G

Try this.  I know it works for the PORTx and PINx registers.  They need to be volatile as well, don't know if these do or not.  I would guess probably so. 

Code: [Select]

uint16_t* registers[] = {
    &PCMSK0,
    &PCMSK1,
    &PCMSK2,
};


Of course you'll have to dereference the pointers in that line of code, but you know how to do that. 
If at first you don't succeed, up - home - sudo - enter.

krupski

#2
Oct 02, 2017, 11:49 pm Last Edit: Oct 02, 2017, 11:51 pm by krupski
Try this.  I know it works for the PORTx and PINx registers.  They need to be volatile as well, don't know if these do or not.  I would guess probably so.  

Of course you'll have to dereference the pointers in that line of code, but you know how to do that.  
Awesome! It worked! Thanks so much and a Karma++ coming at ya.

BTW, I had to use uint8_t, not uint16_t... here's what I did and it works:

Code: [Select]
// quick blink led test 'cause I have no serial or lcd code yet!

#include <avr/interrupt.h>

int main (void)
{
    volatile uint8_t *registers[] = {
        &PORTA,
        &PORTB,
        &PORTC,
    };

    DDRB |= _BV(7); // set LED pin as an output

    while (1) {

        *registers[1] |= _BV(7); // PORTB, bit 7 is the LED (pin 13)
        __builtin_avr_delay_cycles ((F_CPU / 1e3) * 500); // 500 msec

        *registers[1] &= ~_BV(7); // led off
        __builtin_avr_delay_cycles ((F_CPU / 1e3) * 500); // 500 msec

    }
}


Compiling with -Os, the code just to do this is 298 bytes!  :)  Strangely, compiling with -O3 results in the exact same code... go figure.

Anyway, thanks for the quick reply.  What I'm going to use it for is to make a function that sets up pin change interrupts simply by passing the interrupt number and an index into an array of interrupt types (i.e. low level, both rise and fall, fall only or rise only).

Depending on the PCINT number I want to setup, I need to access different pin change mask registers and interrupt control registers and I didn't want to do clumsy "switch/case" code with the register names in the cases (that's why I have them in an array instead).


Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Delta_G

BTW, I had to use uint8_t, not uint16_t... here's what I did and it works:
I was wondering about that but I didn't want to look up those registers and I didn't want to dispute you if I hadn't. 
If at first you don't succeed, up - home - sudo - enter.

Go Up