Arduino Forum

International => Italiano => Generale => Topic started by: rizz on May 31, 2012, 03:28 pm

Title: Gestione PCINT attraverso PCICR
Post by: rizz on May 31, 2012, 03:28 pm
Ciao a tutti...

Volevo porre una domnda da nubbio...

Io ho scritto un po di codice che volevo condividere con voi ma non so se posso farlo qui sul forum o se devo postarlo in un link apposito.

Grazie..
Title: Re: Gestione PCINT attraverso PCICR
Post by: lestofante on May 31, 2012, 03:31 pm
posta quì se hai problemi, se è corretto allora il posto giusto è il playground, magari con un paio di righe di spiegazione

ps. l'user sul playground è lo stesso che hai sul forum, le 2 cose son collegate
Title: Re: Gestione PCINT attraverso PCICR
Post by: rizz on May 31, 2012, 03:33 pm

posta quì se hai problemi, se è corretto allora il posto giusto è il playground, magari con un paio di righe di spiegazione


Ok ora lo so commentando poi lo condivido.
Title: Re: Gestione PCINT attraverso PCICR
Post by: rizz on May 31, 2012, 03:56 pm
Ecco qui le parti di codice modificate e create...

Come dicevo, mi sono trovato nella neccessiàa di dove gestire gli interrup PCINT abbinati ai pin del micro.

Ho scritto una rutine che potrebbe essere utile e sono qui a condividere con voi la soluzione che ho trovato.

Specifico che il micro che uso è il atmega1284p quindi il pin_arduino.h è modificato ma coerente con il core è la versione 1.0.1

Modifiche a pin_arduino.h
Code: [Select]

//modifice allo standard
#define digitalPinToPCICR(p)    (((p) >= 0 && (p) < NUM_DIGITAL_PINS) ? (&PCICR) : ((uint8_t *)0))
// modificato per avere tutti i PIN
//#define digitalPinToPCICRbit(p) (((p) <= 7) ? 1 : (((p) <= 15) ? 3 : (((p) <= 23) ? 2 : 0)))
#define digitalPinToPCICRbit(p) (((p) < 8) ? (PCIF1)    : (((p) < 16) ? (PCIF3)    : (((p) < 24) ? (PCIF2)    : (PCIF0))))
//modificato per avere tutti i PIN
//#define digitalPinToPCMSK(p)    (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0))))
#define digitalPinToPCMSK(p)    (((p) <= 7) ? (&PCMSK1) : (((p) <= 15) ? (&PCMSK3) : (((p) <= 23) ? (&PCMSK2) : (&PCMSK0))))
// modificato per ottenere la maschera corretta
// #define digitalPinToPCMSKbit(p) ((p) % 8)
#define digitalPinToPCMSKbit(p) digitalPinToBitMask(p)


Poi ho creato il file interrupt.h:
Code: [Select]

#ifndef INTERRUPT_H_
#define INTERRUPT_H_

#include <inttypes.h>
#include "../wiring_private.h"

#ifdef __cplusplus
extern "C"{
#endif

void attachInterruptPcint(const uint8_t pinNumero, void (*userFunc)(void));//, int mode);

void detachInterruptPcint(const uint8_t pinNumero);

#ifdef __cplusplus
} // extern "C"
#endif

#endif /* INTERRUPT_H_ */


e in fine ho scritto questo interrupt.c
Code: [Select]

#include "interrupt.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include "pins_arduino.h"

// definisce i bit massimi per il micro in uso
#define BIT_MAX 8
// trova il numro di gruppo PCINT attraverso lo standard di "pin_arduino.h"
#define PCIF_MAX (NUM_DIGITAL_PINS+1)/8

// questo arrai serve solo per indicizzare il puntatore alle funzioni da richiamare
static volatile voidFuncPtr intFunc[PCIF_MAX][BIT_MAX];

// abilta la il PCINT in base al pin e alla funzione da richiamare
void attachInterruptPcint( const uint8_t pinNumero,void (*userFunc)(void))
{
uint8_t bit_pcicr=digitalPinToPCICRbit(pinNumero);
uint8_t bit_pcmsk=digitalPinToPCMSKbit(pinNumero);
volatile uint8_t *pcicr=digitalPinToPCICR(pinNumero);
volatile uint8_t *pcmsk=digitalPinToPCMSK(pinNumero);

//salva il puntatore alla funzione
intFunc[bit_pcicr][(uint8_t)(log(bit_pcmsk)/log(2))]=userFunc;

//setta i registri PCICR e il relativo PCMSK con il bit ricavato dal pin
uint8_t oldSREG = SREG;
cli();
*pcmsk |= bit_pcmsk;
*pcicr |= _BV(bit_pcicr);
SREG = oldSREG;
}

//elimina la gestione dell'interrupt
void detachInterruptPcint( const uint8_t pinNumero )
{
uint8_t bit_pcicr=digitalPinToPCICRbit(pinNumero);
uint8_t bit_pcmsk=digitalPinToPCMSKbit(pinNumero);
volatile uint8_t *pcicr=digitalPinToPCICR(pinNumero);
volatile uint8_t *pcmsk=digitalPinToPCMSK(pinNumero);

//verifica se è già stato cancellato
if (intFunc[bit_pcicr][(uint8_t)(log(bit_pcmsk)/log(2))])
{
//porta il puntatore alla funzione a NULL
intFunc[bit_pcicr][(uint8_t)(log(bit_pcmsk)/log(2))]=NULL;

//cancella i registri per disabilitare l'interrupt
uint8_t oldSREG = SREG;
cli();
*pcmsk &= ~bit_pcmsk;
//se tutto il PCMSK inerente è a zero disabilita il controllo su PCIRC
if (*pcmsk==0) {
*pcicr &= ~_BV(bit_pcicr);
}
SREG = oldSREG;
}
}

ISR(PCINT0_vect)
{
//cicla per tutti gli 8 bit collegati al relativo PCINT
//se vi è un interrupt in attesa interrompe il cilo per la ripresa successiva
for (uint8_t j=0;(j<BIT_MAX)&& ((PCIFR & _BV(PCIF0))==0);j++)
{
// se è un interrupt con funzione chiama la relativa funzione
if (intFunc[PCIF0][j])
{
intFunc[PCIF0][j]();
}
}
}
ISR(PCINT1_vect)
{
for (uint8_t j=0;(j<BIT_MAX)&& ((PCIFR & _BV(PCIF1))==0);j++)
{
if (intFunc[PCIF1][j])
{
intFunc[PCIF1][j]();
}
}
}
ISR(PCINT2_vect)
{
for (uint8_t j=0;(j<BIT_MAX)&& ((PCIFR & _BV(PCIF2))==0);j++)
{
if (intFunc[PCIF2][j])
{
intFunc[PCIF2][j]();
}
}
}
ISR(PCINT3_vect)
{
for (uint8_t j=0;(j<BIT_MAX)&& ((PCIFR & _BV(PCIF3))==0);j++)
{
if (intFunc[PCIF3][j])
{
intFunc[PCIF3][j]();
}
}
}
ISR(BADISR_vect)
{
// se viene eseguita è un errore di programmazione
}


Spero che tutto ciò possa essere utile a qualcuno per non dover riscrivere tutto e penso che sia una buona idea per eventuali implementazioni nel core successivi.

Ciao.
Title: Re: Gestione PCINT attraverso PCICR
Post by: testato on Jul 04, 2014, 07:01 pm
bravo, mi ci sono imbattuto perche' cercavo info proprio su PCINT.
Comunque c'e' una libreria apposita gia' fatta che fa usare su tutti i pin gli interrupt.

Hai il tuo primo Karma  ;)
Title: Re: Gestione PCINT attraverso PCICR
Post by: leo72 on Jul 06, 2014, 06:20 am
Mi spieghi questo?
Code: [Select]
log(bit_pcmsk)/log(2)
Non l'ho capito, ma sicuramente è per mio difetto (sono le 6 di mattina ed ho dormito solo 4 ore. :smiley-sleep: )
Title: Re: Gestione PCINT attraverso PCICR
Post by: lestofante on Jul 06, 2014, 10:21 am
credo sia per fare il logaritmo in base 2 di bit_pcmsk, quindi per trovare l'esponente, ovvero la posizione del bit ad 1 nel byte

(non esistendo log base 2 ma solo log base E, devi usare il cambio di base dei logaritmi, ovvero dividere log base E per il log base E della base che vuoi otenere http://en.wikipedia.org/wiki/Logarithm#Change_of_base)

edit: IMHO, sapendo che i float e i log sono inefficientissimi per mancanza di FPU, un for che fa bitshift e verifica il risultato è preferbile, in oltre non rischi roblemi derivanti dall'arrotondamento. Inzomma, bella soluzione sulla carta, ma si dimostra difficile da leggere e error-prone.
Title: Re: Gestione PCINT attraverso PCICR
Post by: leo72 on Jul 06, 2014, 10:24 am
Argh.. l'avevo detto che il sonno mi impediva di capire.... non ci avevo proprio pensato  :smiley-sweat: :smiley-sweat: