Skip to content

Commit 63b2b27

Browse files
committed
Refactor CAN interrupt handling to LPC176X HAL implementation
Add handlers for other CAN interrupt events Changed CAN private entities to protected
1 parent 8ef8aac commit 63b2b27

File tree

4 files changed

+129
-63
lines changed

4 files changed

+129
-63
lines changed

libraries/mbed/api/CAN.h

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ class CAN {
163163
*
164164
* @param fptr A pointer to a void function, or 0 to set as none
165165
*/
166-
void attach(void (*fptr)(void));
166+
void attach(void (*fptr)(void), can_irq_event event=IRQ_RX);
167167

168168
/** Attach a member function to call whenever a CAN frame received interrupt
169169
* is generated.
@@ -172,21 +172,18 @@ class CAN {
172172
* @param mptr pointer to the member function to be called
173173
*/
174174
template<typename T>
175-
void attach(T* tptr, void (T::*mptr)(void)) {
175+
void attach(T* tptr, void (T::*mptr)(void), can_irq_event event=IRQ_RX) {
176176
if((mptr != NULL) && (tptr != NULL)) {
177-
_rxirq.attach(tptr, mptr);
178-
setup_interrupt();
179-
} else {
180-
remove_interrupt();
177+
_irq[type].attach(tptr, mptr);
178+
can_irq_set(&_can, event, 1);
181179
}
182180
}
183181

184-
private:
185-
can_t _can;
186-
FunctionPointer _rxirq;
182+
static void _irq_handler(uint32_t id, can_irq_event event);
187183

188-
void setup_interrupt(void);
189-
void remove_interrupt(void);
184+
protected:
185+
can_t _can;
186+
FunctionPointer _irq[9];
190187
};
191188

192189
} // namespace mbed

libraries/mbed/common/CAN.cpp

Lines changed: 11 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ namespace mbed {
2323

2424
CAN::CAN(PinName rd, PinName td) {
2525
can_init(&_can, rd, td);
26+
can_irq_init(&_can, (&CAN::_irq_handler), (uint32_t)this);
2627
}
2728

2829
CAN::~CAN() {
2930
can_free(&_can);
31+
can_irq_free(&_can);
3032
}
3133

3234
int CAN::frequency(int f) {
@@ -57,61 +59,18 @@ void CAN::monitor(bool silent) {
5759
can_monitor(&_can, (silent) ? 1 : 0);
5860
}
5961

60-
static FunctionPointer* can_obj[2] = { NULL };
61-
62-
// Have to check that the CAN block is active before reading the Interrupt
63-
// Control Register, or the mbed hangs
64-
void can_irq(void) {
65-
uint32_t icr;
66-
67-
if(LPC_SC->PCONP & (1 << 13)) {
68-
icr = LPC_CAN1->ICR;
69-
70-
if(icr && (can_obj[0] != NULL)) {
71-
can_obj[0]->call();
72-
}
73-
}
74-
75-
if(LPC_SC->PCONP & (1 << 14)) {
76-
icr = LPC_CAN2->ICR;
77-
if(icr && (can_obj[1] != NULL)) {
78-
can_obj[1]->call();
79-
}
80-
}
81-
82-
}
83-
84-
void CAN::setup_interrupt(void) {
85-
switch ((int)_can.dev) {
86-
case CAN_1: can_obj[0] = &_rxirq; break;
87-
case CAN_2: can_obj[1] = &_rxirq; break;
88-
}
89-
_can.dev->MOD |= 1;
90-
_can.dev->IER |= 1;
91-
_can.dev->MOD &= ~1;
92-
NVIC_SetVector(CAN_IRQn, (uint32_t) &can_irq);
93-
NVIC_EnableIRQ(CAN_IRQn);
94-
}
95-
96-
void CAN::remove_interrupt(void) {
97-
switch ((int)_can.dev) {
98-
case CAN_1: can_obj[0] = NULL; break;
99-
case CAN_2: can_obj[1] = NULL; break;
100-
}
101-
102-
_can.dev->IER &= ~(1);
103-
if ((can_obj[0] == NULL) && (can_obj[1] == NULL)) {
104-
NVIC_DisableIRQ(CAN_IRQn);
62+
void CAN::attach(void (*fptr)(void), can_irq_event event) {
63+
if (fptr) {
64+
_irq[event].attach(fptr);
65+
can_irq_set(&_can, event, 1);
66+
} else {
67+
can_irq_set(&_can, event, 0);
10568
}
10669
}
10770

108-
void CAN::attach(void (*fptr)(void)) {
109-
if (fptr != NULL) {
110-
_rxirq.attach(fptr);
111-
setup_interrupt();
112-
} else {
113-
remove_interrupt();
114-
}
71+
void CAN::_irq_handler(uint32_t id, can_irq_event event) {
72+
CAN *handler = (CAN*)id;
73+
handler->_irq[event].call();
11574
}
11675

11776
} // namespace mbed

libraries/mbed/hal/can_api.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,30 @@
2828
extern "C" {
2929
#endif
3030

31+
typedef enum {
32+
IRQ_RX,
33+
IRQ_TX,
34+
IRQ_ERROR,
35+
IRQ_OVERRUN,
36+
IRQ_WAKEUP,
37+
IRQ_PASSIVE,
38+
IRQ_ARB,
39+
IRQ_BUS,
40+
IRQ_READY
41+
} can_irq_event;
42+
43+
typedef void (*can_irq_handler)(uint32_t id, can_irq_event event);
44+
3145
typedef struct can_s can_t;
3246

3347
void can_init (can_t *obj, PinName rd, PinName td);
3448
void can_free (can_t *obj);
3549
int can_frequency(can_t *obj, int hz);
50+
51+
void can_irq_init (can_t *obj, can_irq_handler handler, uint32_t id);
52+
void can_irq_free (can_t *obj);
53+
void can_irq_set (can_t *obj, can_irq_event irq, uint32_t enable);
54+
3655
int can_write (can_t *obj, CAN_Message, int cc);
3756
int can_read (can_t *obj, CAN_Message *msg);
3857
void can_reset (can_t *obj);

libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/can_api.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ struct CANMsg {
6363
};
6464
typedef struct CANMsg CANMsg;
6565

66+
static uint32_t can_irq_ids[CAN_NUM] = {0};
67+
static can_irq_handler irq_handler;
68+
6669
static uint32_t can_disable(can_t *obj) {
6770
uint32_t sm = obj->dev->MOD;
6871
obj->dev->MOD |= 1;
@@ -75,6 +78,94 @@ static inline void can_enable(can_t *obj) {
7578
}
7679
}
7780

81+
static inline void can_irq(uint32_t icr, uint32_t index) {
82+
#warning TODO(@jorisa) Check that events not happen at same time
83+
can_irq_event event;
84+
switch (icr) {
85+
case (1 << 0): event = IRQ_RX; break;
86+
case (1 << 1): event = IRQ_TX; break;
87+
case (1 << 2): event = IRQ_ERROR; break;
88+
case (1 << 3): event = IRQ_OVERRUN; break;
89+
case (1 << 4): event = IRQ_WAKEUP; break;
90+
case (1 << 5): event = IRQ_PASSIVE; break;
91+
case (1 << 6): event = IRQ_ARB; break;
92+
case (1 << 7): event = IRQ_BUS; break;
93+
case (1 << 8): event = IRQ_READY; break;
94+
default: return;
95+
}
96+
97+
if (can_irq_ids[index] != 0)
98+
irq_handler(can_irq_ids[index], event);
99+
}
100+
101+
// Have to check that the CAN block is active before reading the Interrupt
102+
// Control Register, or the mbed hangs
103+
void can_irq_n() {
104+
uint32_t icr;
105+
106+
if(LPC_SC->PCONP & (1 << 13)) {
107+
icr = LPC_CAN1->ICR & 0x1FF;
108+
can_irq(icr, 0);
109+
}
110+
111+
if(LPC_SC->PCONP & (1 << 14)) {
112+
icr = LPC_CAN2->ICR & 0x1FF;
113+
can_irq(icr, 1);
114+
}
115+
}
116+
117+
// Register CAN object's irq handler
118+
void can_irq_init(can_t *obj, can_irq_handler handler, uint32_t id) {
119+
irq_handler = handler;
120+
can_irq_ids[obj->index] = id;
121+
}
122+
123+
// Unregister CAN object's irq handler
124+
void can_irq_free(can_t *obj) {
125+
obj->dev->IER &= ~(1);
126+
can_irq_ids[obj->index] = 0;
127+
128+
if ((can_irq_ids[0] == 0) && (can_irq_ids[1] == 0)) {
129+
NVIC_DisableIRQ(CAN_IRQn);
130+
}
131+
}
132+
133+
// Clear or set a irq
134+
void can_irq_set(can_t *obj, can_irq_event event, uint32_t enable) {
135+
uint32_t ier;
136+
137+
switch (event) {
138+
case IRQ_RX: ier = (1 << 0); break;
139+
case IRQ_TX: ier = (1 << 1); break;
140+
case IRQ_ERROR: ier = (1 << 2); break;
141+
case IRQ_OVERRUN: ier = (1 << 3); break;
142+
case IRQ_WAKEUP: ier = (1 << 4); break;
143+
case IRQ_PASSIVE: ier = (1 << 5); break;
144+
case IRQ_ARB: ier = (1 << 6); break;
145+
case IRQ_BUS: ier = (1 << 7); break;
146+
case IRQ_READY: ier = (1 << 8); break;
147+
default: return;
148+
}
149+
150+
obj->dev->MOD |= 1;
151+
if(enable == 0) {
152+
obj->dev->IER &= ~ier;
153+
}
154+
else {
155+
obj->dev->IER |= ier;
156+
}
157+
obj->dev->MOD &= ~(1);
158+
159+
// Enable NVIC if at least 1 interrupt is active
160+
if(LPC_CAN1->IER | LPC_CAN2->IER != 0) {
161+
NVIC_SetVector(CAN_IRQn, (uint32_t) &can_irq_n);
162+
NVIC_EnableIRQ(CAN_IRQn);
163+
}
164+
else {
165+
NVIC_DisableIRQ(CAN_IRQn);
166+
}
167+
}
168+
78169
static int can_pclk(can_t *obj) {
79170
int value = 0;
80171
switch ((int)obj->dev) {

0 commit comments

Comments
 (0)