Refactor CAN interrupt handling to LPC176X HAL implementation

Add handlers for other CAN interrupt events
Changed CAN private entities to protected
pull/20/head
Joris Aerts 2013-07-31 07:23:21 -07:00
parent 8ef8aac36e
commit 63b2b271d1
4 changed files with 130 additions and 64 deletions

View File

@ -163,7 +163,7 @@ public:
*
* @param fptr A pointer to a void function, or 0 to set as none
*/
void attach(void (*fptr)(void));
void attach(void (*fptr)(void), can_irq_event event=IRQ_RX);
/** Attach a member function to call whenever a CAN frame received interrupt
* is generated.
@ -172,21 +172,18 @@ public:
* @param mptr pointer to the member function to be called
*/
template<typename T>
void attach(T* tptr, void (T::*mptr)(void)) {
void attach(T* tptr, void (T::*mptr)(void), can_irq_event event=IRQ_RX) {
if((mptr != NULL) && (tptr != NULL)) {
_rxirq.attach(tptr, mptr);
setup_interrupt();
} else {
remove_interrupt();
_irq[type].attach(tptr, mptr);
can_irq_set(&_can, event, 1);
}
}
private:
can_t _can;
FunctionPointer _rxirq;
static void _irq_handler(uint32_t id, can_irq_event event);
void setup_interrupt(void);
void remove_interrupt(void);
protected:
can_t _can;
FunctionPointer _irq[9];
};
} // namespace mbed

View File

@ -23,10 +23,12 @@ namespace mbed {
CAN::CAN(PinName rd, PinName td) {
can_init(&_can, rd, td);
can_irq_init(&_can, (&CAN::_irq_handler), (uint32_t)this);
}
CAN::~CAN() {
can_free(&_can);
can_irq_free(&_can);
}
int CAN::frequency(int f) {
@ -57,63 +59,20 @@ void CAN::monitor(bool silent) {
can_monitor(&_can, (silent) ? 1 : 0);
}
static FunctionPointer* can_obj[2] = { NULL };
// Have to check that the CAN block is active before reading the Interrupt
// Control Register, or the mbed hangs
void can_irq(void) {
uint32_t icr;
if(LPC_SC->PCONP & (1 << 13)) {
icr = LPC_CAN1->ICR;
if(icr && (can_obj[0] != NULL)) {
can_obj[0]->call();
}
}
if(LPC_SC->PCONP & (1 << 14)) {
icr = LPC_CAN2->ICR;
if(icr && (can_obj[1] != NULL)) {
can_obj[1]->call();
}
}
}
void CAN::setup_interrupt(void) {
switch ((int)_can.dev) {
case CAN_1: can_obj[0] = &_rxirq; break;
case CAN_2: can_obj[1] = &_rxirq; break;
}
_can.dev->MOD |= 1;
_can.dev->IER |= 1;
_can.dev->MOD &= ~1;
NVIC_SetVector(CAN_IRQn, (uint32_t) &can_irq);
NVIC_EnableIRQ(CAN_IRQn);
}
void CAN::remove_interrupt(void) {
switch ((int)_can.dev) {
case CAN_1: can_obj[0] = NULL; break;
case CAN_2: can_obj[1] = NULL; break;
}
_can.dev->IER &= ~(1);
if ((can_obj[0] == NULL) && (can_obj[1] == NULL)) {
NVIC_DisableIRQ(CAN_IRQn);
}
}
void CAN::attach(void (*fptr)(void)) {
if (fptr != NULL) {
_rxirq.attach(fptr);
setup_interrupt();
void CAN::attach(void (*fptr)(void), can_irq_event event) {
if (fptr) {
_irq[event].attach(fptr);
can_irq_set(&_can, event, 1);
} else {
remove_interrupt();
can_irq_set(&_can, event, 0);
}
}
void CAN::_irq_handler(uint32_t id, can_irq_event event) {
CAN *handler = (CAN*)id;
handler->_irq[event].call();
}
} // namespace mbed
#endif

View File

@ -28,11 +28,30 @@
extern "C" {
#endif
typedef enum {
IRQ_RX,
IRQ_TX,
IRQ_ERROR,
IRQ_OVERRUN,
IRQ_WAKEUP,
IRQ_PASSIVE,
IRQ_ARB,
IRQ_BUS,
IRQ_READY
} can_irq_event;
typedef void (*can_irq_handler)(uint32_t id, can_irq_event event);
typedef struct can_s can_t;
void can_init (can_t *obj, PinName rd, PinName td);
void can_free (can_t *obj);
int can_frequency(can_t *obj, int hz);
void can_irq_init (can_t *obj, can_irq_handler handler, uint32_t id);
void can_irq_free (can_t *obj);
void can_irq_set (can_t *obj, can_irq_event irq, uint32_t enable);
int can_write (can_t *obj, CAN_Message, int cc);
int can_read (can_t *obj, CAN_Message *msg);
void can_reset (can_t *obj);

View File

@ -63,6 +63,9 @@ struct CANMsg {
};
typedef struct CANMsg CANMsg;
static uint32_t can_irq_ids[CAN_NUM] = {0};
static can_irq_handler irq_handler;
static uint32_t can_disable(can_t *obj) {
uint32_t sm = obj->dev->MOD;
obj->dev->MOD |= 1;
@ -75,6 +78,94 @@ static inline void can_enable(can_t *obj) {
}
}
static inline void can_irq(uint32_t icr, uint32_t index) {
#warning TODO(@jorisa) Check that events not happen at same time
can_irq_event event;
switch (icr) {
case (1 << 0): event = IRQ_RX; break;
case (1 << 1): event = IRQ_TX; break;
case (1 << 2): event = IRQ_ERROR; break;
case (1 << 3): event = IRQ_OVERRUN; break;
case (1 << 4): event = IRQ_WAKEUP; break;
case (1 << 5): event = IRQ_PASSIVE; break;
case (1 << 6): event = IRQ_ARB; break;
case (1 << 7): event = IRQ_BUS; break;
case (1 << 8): event = IRQ_READY; break;
default: return;
}
if (can_irq_ids[index] != 0)
irq_handler(can_irq_ids[index], event);
}
// Have to check that the CAN block is active before reading the Interrupt
// Control Register, or the mbed hangs
void can_irq_n() {
uint32_t icr;
if(LPC_SC->PCONP & (1 << 13)) {
icr = LPC_CAN1->ICR & 0x1FF;
can_irq(icr, 0);
}
if(LPC_SC->PCONP & (1 << 14)) {
icr = LPC_CAN2->ICR & 0x1FF;
can_irq(icr, 1);
}
}
// Register CAN object's irq handler
void can_irq_init(can_t *obj, can_irq_handler handler, uint32_t id) {
irq_handler = handler;
can_irq_ids[obj->index] = id;
}
// Unregister CAN object's irq handler
void can_irq_free(can_t *obj) {
obj->dev->IER &= ~(1);
can_irq_ids[obj->index] = 0;
if ((can_irq_ids[0] == 0) && (can_irq_ids[1] == 0)) {
NVIC_DisableIRQ(CAN_IRQn);
}
}
// Clear or set a irq
void can_irq_set(can_t *obj, can_irq_event event, uint32_t enable) {
uint32_t ier;
switch (event) {
case IRQ_RX: ier = (1 << 0); break;
case IRQ_TX: ier = (1 << 1); break;
case IRQ_ERROR: ier = (1 << 2); break;
case IRQ_OVERRUN: ier = (1 << 3); break;
case IRQ_WAKEUP: ier = (1 << 4); break;
case IRQ_PASSIVE: ier = (1 << 5); break;
case IRQ_ARB: ier = (1 << 6); break;
case IRQ_BUS: ier = (1 << 7); break;
case IRQ_READY: ier = (1 << 8); break;
default: return;
}
obj->dev->MOD |= 1;
if(enable == 0) {
obj->dev->IER &= ~ier;
}
else {
obj->dev->IER |= ier;
}
obj->dev->MOD &= ~(1);
// Enable NVIC if at least 1 interrupt is active
if(LPC_CAN1->IER | LPC_CAN2->IER != 0) {
NVIC_SetVector(CAN_IRQn, (uint32_t) &can_irq_n);
NVIC_EnableIRQ(CAN_IRQn);
}
else {
NVIC_DisableIRQ(CAN_IRQn);
}
}
static int can_pclk(can_t *obj) {
int value = 0;
switch ((int)obj->dev) {