mirror of https://github.com/ARMmbed/mbed-os.git
pull/20/head
commit
2c45596673
|
@ -162,31 +162,33 @@ public:
|
|||
* 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
|
|
@ -59,6 +59,7 @@ struct dac_s {
|
|||
|
||||
struct can_s {
|
||||
LPC_CAN_TypeDef *dev;
|
||||
int index;
|
||||
};
|
||||
|
||||
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"),
|
||||
"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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue