Go Down

Topic: Gestione PCINT attraverso PCICR (Read 1 time) previous topic - next topic

rizz

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..

lestofante

#1
May 31, 2012, 03:31 pm Last Edit: May 31, 2012, 03:36 pm by lesto Reason: 1
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
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

rizz


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.

rizz

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.

testato

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  ;)
- [Guida] IDE - http://goo.gl/ln6glr
- [Lib] ST7032i LCD I2C - http://goo.gl/GNojT6
- [Lib] PCF8574+HD44780 LCD I2C - http://goo.gl/r7CstH

leo72

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: )

lestofante

#6
Jul 06, 2014, 10:21 am Last Edit: Jul 06, 2014, 10:24 am by lesto Reason: 1
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.
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

leo72

Argh.. l'avevo detto che il sonno mi impediva di capire.... non ci avevo proprio pensato  :smiley-sweat: :smiley-sweat:

Go Up