mbed library sources
Dependents: frdm_kl05z_gpio_test
Fork of mbed-src by
Diff: targets/hal/TARGET_NXP/TARGET_LPC408X/can_api.c
- Revision:
- 17:151ab7482c89
- Parent:
- 16:7da2369b400c
- Child:
- 22:dbd009839d5e
diff -r 7da2369b400c -r 151ab7482c89 targets/hal/TARGET_NXP/TARGET_LPC408X/can_api.c --- a/targets/hal/TARGET_NXP/TARGET_LPC408X/can_api.c Wed Aug 07 16:33:54 2013 +0000 +++ b/targets/hal/TARGET_NXP/TARGET_LPC408X/can_api.c Thu Aug 08 15:42:46 2013 +0100 @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include <math.h> -#include <string.h> +#include "can_api.h" -#include "can_api.h" #include "cmsis.h" #include "pinmap.h" #include "error.h" -#if DEVICE_CAN +#include <math.h> +#include <string.h> + +#define CAN_NUM 2 /* Acceptance filter mode in AFMR register */ #define ACCF_OFF 0x01 @@ -62,6 +63,9 @@ }; 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; @@ -74,6 +78,101 @@ } } +int can_mode(can_t *obj, CanMode mode) +{ + return 0; // not implemented +} + +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, CanIrqType type, uint32_t enable) { + uint32_t ier; + + switch (type) { + 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); + } +} + // This table has the sampling points as close to 75% as possible. The first // value is TSEG1, the second TSEG2. static const int timing_pts[23][2] = { @@ -134,6 +233,7 @@ } return btr; + } void can_init(can_t *obj, PinName rd, PinName td) { @@ -143,19 +243,24 @@ if ((int)obj->dev == NC) { error("CAN pin mapping failed"); } - + switch ((int)obj->dev) { case CAN_1: LPC_SC->PCONP |= 1 << 13; break; case CAN_2: LPC_SC->PCONP |= 1 << 14; break; } - + 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); - + LPC_CANAF->AFMR = ACCF_BYPASS; // Bypass Filter } @@ -168,8 +273,9 @@ int can_frequency(can_t *obj, int f) { int pclk = PeripheralClock; + int btr = can_speed(SystemCoreClock, pclk, (unsigned int)f, 1); - + if (btr > 0) { uint32_t modmask = can_disable(obj); obj->dev->BTR = btr; @@ -183,16 +289,16 @@ int can_write(can_t *obj, CAN_Message msg, int cc) { unsigned int CANStatus; CANMsg m; - + can_enable(obj); - + m.id = msg.id ; m.dlc = msg.len & 0xF; m.rtr = msg.type; m.type = msg.format; memcpy(m.data, msg.data, msg.len); const unsigned int *buf = (const unsigned int *)&m; - + CANStatus = obj->dev->SR; if (CANStatus & 0x00000004) { obj->dev->TFI1 = buf[0] & 0xC00F0000; @@ -205,7 +311,7 @@ obj->dev->CMR = 0x21; } return 1; - + } else if (CANStatus & 0x00000400) { obj->dev->TFI2 = buf[0] & 0xC00F0000; obj->dev->TID2 = buf[1]; @@ -217,7 +323,7 @@ obj->dev->CMR = 0x41; } return 1; - + } else if (CANStatus & 0x00040000) { obj->dev->TFI3 = buf[0] & 0xC00F0000; obj->dev->TID3 = buf[1]; @@ -230,23 +336,23 @@ } return 1; } - + return 0; } int can_read(can_t *obj, CAN_Message *msg) { CANMsg x; unsigned int *i = (unsigned int *)&x; - + can_enable(obj); - + if (obj->dev->GSR & 0x1) { *i++ = obj->dev->RFS; // Frame *i++ = obj->dev->RID; // ID *i++ = obj->dev->RDA; // Data A *i++ = obj->dev->RDB; // Data B obj->dev->CMR = 0x04; // release receive buffer - + msg->id = x.id; msg->len = x.dlc; msg->format = (x.type)? CANExtended : CANStandard; @@ -254,7 +360,7 @@ memcpy(msg->data,x.data,x.dlc); return 1; } - + return 0; } @@ -282,5 +388,3 @@ can_enable(obj); } } - -#endif