mirror of https://github.com/ARMmbed/mbed-os.git
Refactor CAN interrupt handling to LPC176X HAL implementation
Add handlers for other CAN interrupt events Changed CAN private entities to protectedpull/20/head
parent
8ef8aac36e
commit
63b2b271d1
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue