Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewelse committed Aug 5, 2013
2 parents 7c8c722 + 48fc1aa commit 2c45596
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 64 deletions.
24 changes: 13 additions & 11 deletions libraries/mbed/api/CAN.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,31 +162,33 @@ class CAN {
* generated.
*
* @param fptr A pointer to a void function, or 0 to set as none
* @param event Which can interrupt to attach the member function to (CAN::IRQ_RX, CAN::IRQ_TX, CAN::IRQ_ERROR, CAN::IRQ_OVERRUN, CAN::IRQ_WAKEUP, CAN::IRQ_PASSIVE, CAN::IRQ_ARB, CAN::IRQ_BUS, CAN::IRQ_READY) - Note that not every event is supported by all hardware
*/
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.
*
* @param tptr pointer to the object to call the member function on
* @param mptr pointer to the member function to be called
* @param event Which can interrupt to attach the member function to (CAN::IRQ_RX, CAN::IRQ_TX, CAN::IRQ_ERROR, CAN::IRQ_OVERRUN, CAN::IRQ_WAKEUP, CAN::IRQ_PASSIVE, CAN::IRQ_ARB, CAN::IRQ_BUS, CAN::IRQ_READY) - Note that not every event is supported by all hardware
*/
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[event].attach(tptr, mptr);
can_irq_set(&_can, event, 1);
}
else {
can_irq_set(&_can, event, 0);
}
}

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
Expand Down
63 changes: 11 additions & 52 deletions libraries/mbed/common/CAN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -57,61 +59,18 @@ 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), can_irq_event event) {
if (fptr) {
_irq[event].attach(fptr);
can_irq_set(&_can, event, 1);
} else {
can_irq_set(&_can, event, 0);
}
}

void CAN::attach(void (*fptr)(void)) {
if (fptr != NULL) {
_rxirq.attach(fptr);
setup_interrupt();
} else {
remove_interrupt();
}
void CAN::_irq_handler(uint32_t id, can_irq_event event) {
CAN *handler = (CAN*)id;
handler->_irq[event].call();
}

} // namespace mbed
Expand Down
19 changes: 19 additions & 0 deletions libraries/mbed/hal/can_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
102 changes: 101 additions & 1 deletion libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/can_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <math.h>
#include <string.h>

#define CAN_NUM 2

/* Acceptance filter mode in AFMR register */
#define ACCF_OFF 0x01
#define ACCF_BYPASS 0x02
Expand Down Expand Up @@ -61,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;
Expand All @@ -73,6 +78,96 @@ static inline void can_enable(can_t *obj) {
}
}

static inline void can_irq(uint32_t icr, uint32_t index) {
uint32_t i;

for(i = 0; i < 8; i++)
{
if((can_irq_ids[index] != 0) && (icr & (1 << i)))
{
switch (i) {
case 0: irq_handler(can_irq_ids[index], IRQ_RX); break;
case 1: irq_handler(can_irq_ids[index], IRQ_TX); break;
case 2: irq_handler(can_irq_ids[index], IRQ_ERROR); break;
case 3: irq_handler(can_irq_ids[index], IRQ_OVERRUN); break;
case 4: irq_handler(can_irq_ids[index], IRQ_WAKEUP); break;
case 5: irq_handler(can_irq_ids[index], IRQ_PASSIVE); break;
case 6: irq_handler(can_irq_ids[index], IRQ_ARB); break;
case 7: irq_handler(can_irq_ids[index], IRQ_BUS); break;
case 8: irq_handler(can_irq_ids[index], IRQ_READY); break;
}
}
}
}

// 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) {
Expand Down Expand Up @@ -166,7 +261,12 @@ void can_init(can_t *obj, PinName rd, PinName td) {

pinmap_pinout(rd, PinMap_CAN_RD);
pinmap_pinout(td, PinMap_CAN_TD);


switch ((int)obj->dev) {
case CAN_1: obj->index = 0; break;
case CAN_2: obj->index = 1; break;
}

can_reset(obj);
obj->dev->IER = 0; // Disable Interrupts
can_frequency(obj, 100000);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct dac_s {

struct can_s {
LPC_CAN_TypeDef *dev;
int index;
};

struct i2c_s {
Expand Down
40 changes: 40 additions & 0 deletions libraries/tests/mbed/can/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "mbed.h"

Ticker ticker;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
CAN can1(p9, p10);
CAN can2(p30, p29);
char counter = 0;

void printmsg(char *title, CANMessage *msg) {
printf("%s [%03X]", title, msg->id);
for(char i = 0; i < msg->len; i++) {
printf(" %02X", msg->data[i]);
}
printf("\n");
}

void send() {
printf("send()\n");
CANMessage msg = CANMessage(1337, &counter, 1);
if(can1.write(msg)) {
printmsg("Tx message:", &msg);
counter++;
}
led1 = !led1;
}

int main() {
printf("main()\n");
ticker.attach(&send, 1);
CANMessage msg;
while(1) {
printf("loop()\n");
if(can1.read(msg)) {
printmsg("Rx message:", &msg);
led2 = !led2;
}
wait(0.2);
}
}
45 changes: 45 additions & 0 deletions libraries/tests/mbed/can_interrupt/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "mbed.h"

Ticker ticker;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
CAN can1(p9, p10);
CAN can2(p30, p29);
char counter = 0;

void printmsg(char *title, CANMessage *msg) {
printf("%s [%03X]", title, msg->id);
for(char i = 0; i < msg->len; i++) {
printf(" %02X", msg->data[i]);
}
printf("\n");
}

void send() {
printf("send()\n");
CANMessage msg = CANMessage(1337, &counter, 1);
if(can1.write(msg)) {
printmsg("Tx message:", &msg);
counter++;
}
led1 = !led1;
}

void read() {
CANMessage msg;
printf("rx()\n");
if(can1.read(msg)) {
printmsg("Rx message:", &msg);
led2 = !led2;
}
}

int main() {
printf("main()\n");
ticker.attach(&send, 1);
can1.attach(&read);
while(1) {
printf("loop()\n");
wait(1);
}
}
Loading

0 comments on commit 2c45596

Please sign in to comment.