mirror of https://github.com/ARMmbed/mbed-os.git
pull/20/head
commit
2c45596673
|
@ -162,31 +162,33 @@ public:
|
||||||
* generated.
|
* generated.
|
||||||
*
|
*
|
||||||
* @param fptr A pointer to a void function, or 0 to set as none
|
* @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
|
/** Attach a member function to call whenever a CAN frame received interrupt
|
||||||
* is generated.
|
* is generated.
|
||||||
*
|
*
|
||||||
* @param tptr pointer to the object to call the member function on
|
* @param tptr pointer to the object to call the member function on
|
||||||
* @param mptr pointer to the member function to be called
|
* @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>
|
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)) {
|
if((mptr != NULL) && (tptr != NULL)) {
|
||||||
_rxirq.attach(tptr, mptr);
|
_irq[event].attach(tptr, mptr);
|
||||||
setup_interrupt();
|
can_irq_set(&_can, event, 1);
|
||||||
} else {
|
}
|
||||||
remove_interrupt();
|
else {
|
||||||
|
can_irq_set(&_can, event, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
static void _irq_handler(uint32_t id, can_irq_event event);
|
||||||
can_t _can;
|
|
||||||
FunctionPointer _rxirq;
|
|
||||||
|
|
||||||
void setup_interrupt(void);
|
protected:
|
||||||
void remove_interrupt(void);
|
can_t _can;
|
||||||
|
FunctionPointer _irq[9];
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mbed
|
} // namespace mbed
|
||||||
|
|
|
@ -23,10 +23,12 @@ namespace mbed {
|
||||||
|
|
||||||
CAN::CAN(PinName rd, PinName td) {
|
CAN::CAN(PinName rd, PinName td) {
|
||||||
can_init(&_can, rd, td);
|
can_init(&_can, rd, td);
|
||||||
|
can_irq_init(&_can, (&CAN::_irq_handler), (uint32_t)this);
|
||||||
}
|
}
|
||||||
|
|
||||||
CAN::~CAN() {
|
CAN::~CAN() {
|
||||||
can_free(&_can);
|
can_free(&_can);
|
||||||
|
can_irq_free(&_can);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CAN::frequency(int f) {
|
int CAN::frequency(int f) {
|
||||||
|
@ -57,63 +59,20 @@ void CAN::monitor(bool silent) {
|
||||||
can_monitor(&_can, (silent) ? 1 : 0);
|
can_monitor(&_can, (silent) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FunctionPointer* can_obj[2] = { NULL };
|
void CAN::attach(void (*fptr)(void), can_irq_event event) {
|
||||||
|
if (fptr) {
|
||||||
// Have to check that the CAN block is active before reading the Interrupt
|
_irq[event].attach(fptr);
|
||||||
// Control Register, or the mbed hangs
|
can_irq_set(&_can, event, 1);
|
||||||
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();
|
|
||||||
} else {
|
} 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
|
} // namespace mbed
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,11 +28,30 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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;
|
typedef struct can_s can_t;
|
||||||
|
|
||||||
void can_init (can_t *obj, PinName rd, PinName td);
|
void can_init (can_t *obj, PinName rd, PinName td);
|
||||||
void can_free (can_t *obj);
|
void can_free (can_t *obj);
|
||||||
int can_frequency(can_t *obj, int hz);
|
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_write (can_t *obj, CAN_Message, int cc);
|
||||||
int can_read (can_t *obj, CAN_Message *msg);
|
int can_read (can_t *obj, CAN_Message *msg);
|
||||||
void can_reset (can_t *obj);
|
void can_reset (can_t *obj);
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#define CAN_NUM 2
|
||||||
|
|
||||||
/* Acceptance filter mode in AFMR register */
|
/* Acceptance filter mode in AFMR register */
|
||||||
#define ACCF_OFF 0x01
|
#define ACCF_OFF 0x01
|
||||||
#define ACCF_BYPASS 0x02
|
#define ACCF_BYPASS 0x02
|
||||||
|
@ -61,6 +63,9 @@ struct CANMsg {
|
||||||
};
|
};
|
||||||
typedef struct CANMsg 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) {
|
static uint32_t can_disable(can_t *obj) {
|
||||||
uint32_t sm = obj->dev->MOD;
|
uint32_t sm = obj->dev->MOD;
|
||||||
obj->dev->MOD |= 1;
|
obj->dev->MOD |= 1;
|
||||||
|
@ -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) {
|
static int can_pclk(can_t *obj) {
|
||||||
int value = 0;
|
int value = 0;
|
||||||
switch ((int)obj->dev) {
|
switch ((int)obj->dev) {
|
||||||
|
@ -167,6 +262,11 @@ void can_init(can_t *obj, PinName rd, PinName td) {
|
||||||
pinmap_pinout(rd, PinMap_CAN_RD);
|
pinmap_pinout(rd, PinMap_CAN_RD);
|
||||||
pinmap_pinout(td, PinMap_CAN_TD);
|
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);
|
can_reset(obj);
|
||||||
obj->dev->IER = 0; // Disable Interrupts
|
obj->dev->IER = 0; // Disable Interrupts
|
||||||
can_frequency(obj, 100000);
|
can_frequency(obj, 100000);
|
||||||
|
|
|
@ -59,6 +59,7 @@ struct dac_s {
|
||||||
|
|
||||||
struct can_s {
|
struct can_s {
|
||||||
LPC_CAN_TypeDef *dev;
|
LPC_CAN_TypeDef *dev;
|
||||||
|
int index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
struct i2c_s {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -369,6 +369,18 @@ TESTS = [
|
||||||
"source_dir": join(TEST_DIR, "mbed", "interrupt_chaining", "ticker"),
|
"source_dir": join(TEST_DIR, "mbed", "interrupt_chaining", "ticker"),
|
||||||
"dependencies": [MBED_LIBRARIES, TEST_MBED_LIB],
|
"dependencies": [MBED_LIBRARIES, TEST_MBED_LIB],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "MBED_30", "description": "CAN network test",
|
||||||
|
"source_dir": join(TEST_DIR, "mbed", "can"),
|
||||||
|
"dependencies": [MBED_LIBRARIES],
|
||||||
|
"mcu": ["LPC1768"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "MBED_31", "description": "CAN network test using interrupts",
|
||||||
|
"source_dir": join(TEST_DIR, "mbed", "can_interrupt"),
|
||||||
|
"dependencies": [MBED_LIBRARIES],
|
||||||
|
"mcu": ["LPC1768"]
|
||||||
|
},
|
||||||
|
|
||||||
# CMSIS RTOS tests
|
# CMSIS RTOS tests
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue