mbed library sources
Dependents: frdm_kl05z_gpio_test
Fork of mbed-src by
targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/TARGET_LPC11CXX/can_api.c@225:2af4c5d0160c, 2014-06-11 (annotated)
- Committer:
- mbed_official
- Date:
- Wed Jun 11 09:30:07 2014 +0100
- Revision:
- 225:2af4c5d0160c
- Parent:
- 203:0f54f988aa69
- Child:
- 250:a49055e7a707
Synchronized with git revision ff65c63a80830b0c36f91f13488d79bafef442e6
Full URL: https://github.com/mbedmicro/mbed/commit/ff65c63a80830b0c36f91f13488d79bafef442e6/
Add support for remote CAN frames on LPC11CXX
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mbed_official | 41:e8b66477f5bf | 1 | /* mbed Microcontroller Library |
mbed_official | 41:e8b66477f5bf | 2 | * Copyright (c) 2006-2013 ARM Limited |
mbed_official | 41:e8b66477f5bf | 3 | * |
mbed_official | 41:e8b66477f5bf | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
mbed_official | 41:e8b66477f5bf | 5 | * you may not use this file except in compliance with the License. |
mbed_official | 41:e8b66477f5bf | 6 | * You may obtain a copy of the License at |
mbed_official | 41:e8b66477f5bf | 7 | * |
mbed_official | 41:e8b66477f5bf | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
mbed_official | 41:e8b66477f5bf | 9 | * |
mbed_official | 41:e8b66477f5bf | 10 | * Unless required by applicable law or agreed to in writing, software |
mbed_official | 41:e8b66477f5bf | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
mbed_official | 41:e8b66477f5bf | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
mbed_official | 41:e8b66477f5bf | 13 | * See the License for the specific language governing permissions and |
mbed_official | 41:e8b66477f5bf | 14 | * limitations under the License. |
mbed_official | 41:e8b66477f5bf | 15 | */ |
mbed_official | 41:e8b66477f5bf | 16 | #include "can_api.h" |
mbed_official | 41:e8b66477f5bf | 17 | |
mbed_official | 41:e8b66477f5bf | 18 | #include "cmsis.h" |
mbed_official | 41:e8b66477f5bf | 19 | #include "error.h" |
mbed_official | 41:e8b66477f5bf | 20 | |
mbed_official | 41:e8b66477f5bf | 21 | #include <math.h> |
mbed_official | 41:e8b66477f5bf | 22 | #include <string.h> |
mbed_official | 41:e8b66477f5bf | 23 | |
mbed_official | 41:e8b66477f5bf | 24 | /* Handy defines */ |
mbed_official | 41:e8b66477f5bf | 25 | #define MSG_OBJ_MAX 32 |
mbed_official | 41:e8b66477f5bf | 26 | #define DLC_MAX 8 |
mbed_official | 41:e8b66477f5bf | 27 | |
mbed_official | 41:e8b66477f5bf | 28 | #define ID_STD_MASK 0x07FF |
mbed_official | 41:e8b66477f5bf | 29 | #define ID_EXT_MASK 0x1FFFFFFF |
mbed_official | 41:e8b66477f5bf | 30 | #define DLC_MASK 0x0F |
mbed_official | 41:e8b66477f5bf | 31 | |
mbed_official | 41:e8b66477f5bf | 32 | static uint32_t can_irq_id = 0; |
mbed_official | 41:e8b66477f5bf | 33 | static can_irq_handler irq_handler; |
mbed_official | 41:e8b66477f5bf | 34 | |
mbed_official | 41:e8b66477f5bf | 35 | static uint32_t can_disable(can_t *obj) { |
mbed_official | 41:e8b66477f5bf | 36 | uint32_t sm = LPC_CAN->CNTL; |
mbed_official | 41:e8b66477f5bf | 37 | LPC_CAN->CNTL |= CANCNTL_INIT; |
mbed_official | 41:e8b66477f5bf | 38 | return sm; |
mbed_official | 41:e8b66477f5bf | 39 | } |
mbed_official | 41:e8b66477f5bf | 40 | |
mbed_official | 41:e8b66477f5bf | 41 | static inline void can_enable(can_t *obj) { |
mbed_official | 41:e8b66477f5bf | 42 | if (LPC_CAN->CNTL & CANCNTL_INIT) { |
mbed_official | 41:e8b66477f5bf | 43 | LPC_CAN->CNTL &= ~CANCNTL_INIT; |
mbed_official | 41:e8b66477f5bf | 44 | } |
mbed_official | 41:e8b66477f5bf | 45 | } |
mbed_official | 41:e8b66477f5bf | 46 | |
mbed_official | 41:e8b66477f5bf | 47 | int can_mode(can_t *obj, CanMode mode) { |
mbed_official | 41:e8b66477f5bf | 48 | return 0; // not implemented |
mbed_official | 41:e8b66477f5bf | 49 | } |
mbed_official | 41:e8b66477f5bf | 50 | |
mbed_official | 41:e8b66477f5bf | 51 | int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle) { |
mbed_official | 41:e8b66477f5bf | 52 | uint16_t i; |
mbed_official | 41:e8b66477f5bf | 53 | |
mbed_official | 41:e8b66477f5bf | 54 | // Find first free message object |
mbed_official | 41:e8b66477f5bf | 55 | if(handle == 0) { |
mbed_official | 41:e8b66477f5bf | 56 | uint32_t msgval = LPC_CAN->MSGV1 | (LPC_CAN->MSGV2 << 16); |
mbed_official | 41:e8b66477f5bf | 57 | // Find first free messagebox |
mbed_official | 41:e8b66477f5bf | 58 | for(i = 0; i < 32; i++) { |
mbed_official | 41:e8b66477f5bf | 59 | if((msgval & (1 << i)) == 0) { |
mbed_official | 41:e8b66477f5bf | 60 | handle = i+1; |
mbed_official | 41:e8b66477f5bf | 61 | break; |
mbed_official | 41:e8b66477f5bf | 62 | } |
mbed_official | 41:e8b66477f5bf | 63 | } |
mbed_official | 41:e8b66477f5bf | 64 | } |
mbed_official | 41:e8b66477f5bf | 65 | |
mbed_official | 41:e8b66477f5bf | 66 | if(handle > 0 && handle < 32) { |
mbed_official | 41:e8b66477f5bf | 67 | if(format == CANExtended) { |
mbed_official | 41:e8b66477f5bf | 68 | // Mark message valid, Direction = TX, Extended Frame, Set Identifier and mask everything |
mbed_official | 41:e8b66477f5bf | 69 | LPC_CAN->IF1_ARB1 = BFN_PREP(id, CANIFn_ARB1_ID); |
mbed_official | 41:e8b66477f5bf | 70 | LPC_CAN->IF1_ARB2 = CANIFn_ARB2_MSGVAL | CANIFn_ARB2_XTD | BFN_PREP(id >> 16, CANIFn_ARB2_ID); |
mbed_official | 41:e8b66477f5bf | 71 | LPC_CAN->IF1_MSK1 = BFN_PREP(mask, CANIFn_MSK1_MSK); |
mbed_official | 225:2af4c5d0160c | 72 | LPC_CAN->IF1_MSK2 = CANIFn_MSK2_MXTD /* | CANIFn_MSK2_MDIR */ | BFN_PREP(mask >> 16, CANIFn_MSK2_MSK); |
mbed_official | 41:e8b66477f5bf | 73 | } |
mbed_official | 41:e8b66477f5bf | 74 | else { |
mbed_official | 41:e8b66477f5bf | 75 | // Mark message valid, Direction = TX, Set Identifier and mask everything |
mbed_official | 41:e8b66477f5bf | 76 | LPC_CAN->IF1_ARB2 = CANIFn_ARB2_MSGVAL | BFN_PREP(id << 2, CANIFn_ARB2_ID); |
mbed_official | 225:2af4c5d0160c | 77 | LPC_CAN->IF1_MSK2 = /* CANIFn_MSK2_MDIR | */ BFN_PREP(mask << 2, CANIFn_MSK2_MSK); |
mbed_official | 41:e8b66477f5bf | 78 | } |
mbed_official | 41:e8b66477f5bf | 79 | |
mbed_official | 41:e8b66477f5bf | 80 | // Use mask, single message object and set DLC |
mbed_official | 41:e8b66477f5bf | 81 | LPC_CAN->IF1_MCTRL = CANIFn_MCTRL_UMASK | CANIFn_MCTRL_EOB | CANIFn_MCTRL_RXIE | BFN_PREP(DLC_MAX, CANIFn_MCTRL_DLC); |
mbed_official | 41:e8b66477f5bf | 82 | |
mbed_official | 41:e8b66477f5bf | 83 | // Transfer all fields to message object |
mbed_official | 41:e8b66477f5bf | 84 | LPC_CAN->IF1_CMDMSK = CANIFn_CMDMSK_WR | CANIFn_CMDMSK_MASK | CANIFn_CMDMSK_ARB | CANIFn_CMDMSK_CTRL; |
mbed_official | 41:e8b66477f5bf | 85 | |
mbed_official | 41:e8b66477f5bf | 86 | // Start Transfer to given message number |
mbed_official | 41:e8b66477f5bf | 87 | LPC_CAN->IF1_CMDREQ = BFN_PREP(handle, CANIFn_CMDREQ_MN); |
mbed_official | 41:e8b66477f5bf | 88 | |
mbed_official | 41:e8b66477f5bf | 89 | // Wait until transfer to message ram complete - TODO: maybe not block?? |
mbed_official | 203:0f54f988aa69 | 90 | while( LPC_CAN->IF1_CMDREQ & CANIFn_CMDREQ_BUSY ); |
mbed_official | 41:e8b66477f5bf | 91 | } |
mbed_official | 41:e8b66477f5bf | 92 | |
mbed_official | 41:e8b66477f5bf | 93 | return handle; |
mbed_official | 41:e8b66477f5bf | 94 | } |
mbed_official | 41:e8b66477f5bf | 95 | |
mbed_official | 41:e8b66477f5bf | 96 | static inline void can_irq() { |
mbed_official | 41:e8b66477f5bf | 97 | irq_handler(can_irq_id, IRQ_RX); |
mbed_official | 41:e8b66477f5bf | 98 | } |
mbed_official | 41:e8b66477f5bf | 99 | |
mbed_official | 41:e8b66477f5bf | 100 | // Register CAN object's irq handler |
mbed_official | 41:e8b66477f5bf | 101 | void can_irq_init(can_t *obj, can_irq_handler handler, uint32_t id) { |
mbed_official | 41:e8b66477f5bf | 102 | irq_handler = handler; |
mbed_official | 203:0f54f988aa69 | 103 | can_irq_id = id; |
mbed_official | 41:e8b66477f5bf | 104 | } |
mbed_official | 41:e8b66477f5bf | 105 | |
mbed_official | 41:e8b66477f5bf | 106 | // Unregister CAN object's irq handler |
mbed_official | 41:e8b66477f5bf | 107 | void can_irq_free(can_t *obj) { |
mbed_official | 41:e8b66477f5bf | 108 | LPC_CAN->CNTL &= ~CANCNTL_IE; // Disable Interrupts :) |
mbed_official | 41:e8b66477f5bf | 109 | |
mbed_official | 41:e8b66477f5bf | 110 | can_irq_id = 0; |
mbed_official | 41:e8b66477f5bf | 111 | NVIC_DisableIRQ(CAN_IRQn); |
mbed_official | 41:e8b66477f5bf | 112 | } |
mbed_official | 41:e8b66477f5bf | 113 | |
mbed_official | 41:e8b66477f5bf | 114 | // Clear or set a irq |
mbed_official | 41:e8b66477f5bf | 115 | void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable) { |
mbed_official | 41:e8b66477f5bf | 116 | // Put CAN in Reset Mode and enable interrupt |
mbed_official | 41:e8b66477f5bf | 117 | can_disable(obj); |
mbed_official | 41:e8b66477f5bf | 118 | if(enable == 0) { |
mbed_official | 41:e8b66477f5bf | 119 | LPC_CAN->CNTL &= ~(CANCNTL_IE | CANCNTL_SIE); |
mbed_official | 41:e8b66477f5bf | 120 | } |
mbed_official | 41:e8b66477f5bf | 121 | else { |
mbed_official | 41:e8b66477f5bf | 122 | LPC_CAN->CNTL |= CANCNTL_IE | CANCNTL_SIE; |
mbed_official | 41:e8b66477f5bf | 123 | } |
mbed_official | 41:e8b66477f5bf | 124 | // Take it out of reset... |
mbed_official | 41:e8b66477f5bf | 125 | can_enable(obj); |
mbed_official | 41:e8b66477f5bf | 126 | |
mbed_official | 41:e8b66477f5bf | 127 | // Enable NVIC if at least 1 interrupt is active |
mbed_official | 41:e8b66477f5bf | 128 | NVIC_SetVector(CAN_IRQn, (uint32_t) &can_irq); |
mbed_official | 41:e8b66477f5bf | 129 | NVIC_EnableIRQ(CAN_IRQn); |
mbed_official | 41:e8b66477f5bf | 130 | } |
mbed_official | 41:e8b66477f5bf | 131 | |
mbed_official | 41:e8b66477f5bf | 132 | // This table has the sampling points as close to 75% as possible. The first |
mbed_official | 41:e8b66477f5bf | 133 | // value is TSEG1, the second TSEG2. |
mbed_official | 41:e8b66477f5bf | 134 | static const int timing_pts[23][2] = { |
mbed_official | 41:e8b66477f5bf | 135 | {0x0, 0x0}, // 2, 50% |
mbed_official | 41:e8b66477f5bf | 136 | {0x1, 0x0}, // 3, 67% |
mbed_official | 41:e8b66477f5bf | 137 | {0x2, 0x0}, // 4, 75% |
mbed_official | 41:e8b66477f5bf | 138 | {0x3, 0x0}, // 5, 80% |
mbed_official | 41:e8b66477f5bf | 139 | {0x3, 0x1}, // 6, 67% |
mbed_official | 41:e8b66477f5bf | 140 | {0x4, 0x1}, // 7, 71% |
mbed_official | 41:e8b66477f5bf | 141 | {0x5, 0x1}, // 8, 75% |
mbed_official | 41:e8b66477f5bf | 142 | {0x6, 0x1}, // 9, 78% |
mbed_official | 41:e8b66477f5bf | 143 | {0x6, 0x2}, // 10, 70% |
mbed_official | 41:e8b66477f5bf | 144 | {0x7, 0x2}, // 11, 73% |
mbed_official | 41:e8b66477f5bf | 145 | {0x8, 0x2}, // 12, 75% |
mbed_official | 41:e8b66477f5bf | 146 | {0x9, 0x2}, // 13, 77% |
mbed_official | 41:e8b66477f5bf | 147 | {0x9, 0x3}, // 14, 71% |
mbed_official | 41:e8b66477f5bf | 148 | {0xA, 0x3}, // 15, 73% |
mbed_official | 41:e8b66477f5bf | 149 | {0xB, 0x3}, // 16, 75% |
mbed_official | 41:e8b66477f5bf | 150 | {0xC, 0x3}, // 17, 76% |
mbed_official | 41:e8b66477f5bf | 151 | {0xD, 0x3}, // 18, 78% |
mbed_official | 41:e8b66477f5bf | 152 | {0xD, 0x4}, // 19, 74% |
mbed_official | 41:e8b66477f5bf | 153 | {0xE, 0x4}, // 20, 75% |
mbed_official | 41:e8b66477f5bf | 154 | {0xF, 0x4}, // 21, 76% |
mbed_official | 41:e8b66477f5bf | 155 | {0xF, 0x5}, // 22, 73% |
mbed_official | 41:e8b66477f5bf | 156 | {0xF, 0x6}, // 23, 70% |
mbed_official | 41:e8b66477f5bf | 157 | {0xF, 0x7}, // 24, 67% |
mbed_official | 41:e8b66477f5bf | 158 | }; |
mbed_official | 41:e8b66477f5bf | 159 | |
mbed_official | 41:e8b66477f5bf | 160 | static unsigned int can_speed(unsigned int sclk, unsigned int cclk, unsigned char psjw) { |
mbed_official | 41:e8b66477f5bf | 161 | uint32_t btr; |
mbed_official | 41:e8b66477f5bf | 162 | uint32_t clkdiv = 1; |
mbed_official | 41:e8b66477f5bf | 163 | uint16_t brp = 0; |
mbed_official | 41:e8b66477f5bf | 164 | uint32_t calcbit; |
mbed_official | 41:e8b66477f5bf | 165 | uint32_t bitwidth; |
mbed_official | 41:e8b66477f5bf | 166 | int hit = 0; |
mbed_official | 41:e8b66477f5bf | 167 | int bits = 0; |
mbed_official | 41:e8b66477f5bf | 168 | |
mbed_official | 41:e8b66477f5bf | 169 | bitwidth = sclk / cclk; |
mbed_official | 41:e8b66477f5bf | 170 | |
mbed_official | 41:e8b66477f5bf | 171 | brp = bitwidth / 0x18; |
mbed_official | 41:e8b66477f5bf | 172 | while ((!hit) && (brp < bitwidth / 4)) { |
mbed_official | 41:e8b66477f5bf | 173 | brp++; |
mbed_official | 41:e8b66477f5bf | 174 | for (bits = 22; bits > 0; bits--) { |
mbed_official | 41:e8b66477f5bf | 175 | calcbit = (bits + 3) * (brp + 1); |
mbed_official | 41:e8b66477f5bf | 176 | if (calcbit == bitwidth) { |
mbed_official | 41:e8b66477f5bf | 177 | hit = 1; |
mbed_official | 41:e8b66477f5bf | 178 | break; |
mbed_official | 41:e8b66477f5bf | 179 | } |
mbed_official | 41:e8b66477f5bf | 180 | } |
mbed_official | 41:e8b66477f5bf | 181 | } |
mbed_official | 41:e8b66477f5bf | 182 | |
mbed_official | 41:e8b66477f5bf | 183 | /* This might be funky |
mbed_official | 41:e8b66477f5bf | 184 | while(btr > 63 && clkdiv < 16) { |
mbed_official | 41:e8b66477f5bf | 185 | btr = btr / 2; |
mbed_official | 41:e8b66477f5bf | 186 | clkdiv = clkdiv * 2; |
mbed_official | 41:e8b66477f5bf | 187 | } |
mbed_official | 41:e8b66477f5bf | 188 | */ |
mbed_official | 41:e8b66477f5bf | 189 | clkdiv = clkdiv - 1; |
mbed_official | 41:e8b66477f5bf | 190 | |
mbed_official | 41:e8b66477f5bf | 191 | if (hit) { |
mbed_official | 41:e8b66477f5bf | 192 | btr = BFN_PREP(timing_pts[bits][1], CANBT_TSEG2) |
mbed_official | 41:e8b66477f5bf | 193 | | BFN_PREP(timing_pts[bits][0], CANBT_TSEG1) |
mbed_official | 41:e8b66477f5bf | 194 | | BFN_PREP(psjw, CANBT_SJW) |
mbed_official | 41:e8b66477f5bf | 195 | | BFN_PREP(brp, CANBT_BRP); |
mbed_official | 41:e8b66477f5bf | 196 | btr = btr | (clkdiv << 16); |
mbed_official | 41:e8b66477f5bf | 197 | |
mbed_official | 41:e8b66477f5bf | 198 | } else { |
mbed_official | 41:e8b66477f5bf | 199 | btr = 0; |
mbed_official | 41:e8b66477f5bf | 200 | } |
mbed_official | 41:e8b66477f5bf | 201 | |
mbed_official | 41:e8b66477f5bf | 202 | return btr; |
mbed_official | 41:e8b66477f5bf | 203 | } |
mbed_official | 41:e8b66477f5bf | 204 | |
mbed_official | 41:e8b66477f5bf | 205 | |
mbed_official | 41:e8b66477f5bf | 206 | int can_config_rxmsgobj(can_t *obj) { |
mbed_official | 41:e8b66477f5bf | 207 | uint16_t i = 0; |
mbed_official | 41:e8b66477f5bf | 208 | |
mbed_official | 41:e8b66477f5bf | 209 | // Make sure the interface is available |
mbed_official | 41:e8b66477f5bf | 210 | //while( LPC_CAN->IF1_CMDREQ & CANIFn_CMDREQ_BUSY ); |
mbed_official | 41:e8b66477f5bf | 211 | |
mbed_official | 41:e8b66477f5bf | 212 | // Mark message valid, Direction = RX, Don't care about anything else |
mbed_official | 41:e8b66477f5bf | 213 | LPC_CAN->IF1_ARB1 = 0; |
mbed_official | 41:e8b66477f5bf | 214 | LPC_CAN->IF1_ARB2 = 0; |
mbed_official | 41:e8b66477f5bf | 215 | LPC_CAN->IF1_MCTRL = 0; |
mbed_official | 41:e8b66477f5bf | 216 | |
mbed_official | 41:e8b66477f5bf | 217 | for ( i = 0; i < MSG_OBJ_MAX; i++ ) |
mbed_official | 41:e8b66477f5bf | 218 | { |
mbed_official | 41:e8b66477f5bf | 219 | // Transfer arb and control fields to message object |
mbed_official | 41:e8b66477f5bf | 220 | LPC_CAN->IF1_CMDMSK = CANIFn_CMDMSK_WR | CANIFn_CMDMSK_ARB | CANIFn_CMDMSK_CTRL | CANIFn_CMDMSK_TXRQST; |
mbed_official | 41:e8b66477f5bf | 221 | |
mbed_official | 41:e8b66477f5bf | 222 | // Start Transfer to given message number |
mbed_official | 41:e8b66477f5bf | 223 | LPC_CAN->IF1_CMDREQ = BFN_PREP(i, CANIFn_CMDREQ_MN); |
mbed_official | 41:e8b66477f5bf | 224 | |
mbed_official | 41:e8b66477f5bf | 225 | // Wait until transfer to message ram complete - TODO: maybe not block?? |
mbed_official | 41:e8b66477f5bf | 226 | while( LPC_CAN->IF1_CMDREQ & CANIFn_CMDREQ_BUSY ); |
mbed_official | 41:e8b66477f5bf | 227 | } |
mbed_official | 41:e8b66477f5bf | 228 | |
mbed_official | 41:e8b66477f5bf | 229 | // Accept all messages |
mbed_official | 41:e8b66477f5bf | 230 | can_filter(obj, 0, 0, CANStandard, 1); |
mbed_official | 41:e8b66477f5bf | 231 | |
mbed_official | 41:e8b66477f5bf | 232 | return 1; |
mbed_official | 41:e8b66477f5bf | 233 | } |
mbed_official | 41:e8b66477f5bf | 234 | |
mbed_official | 41:e8b66477f5bf | 235 | |
mbed_official | 41:e8b66477f5bf | 236 | void can_init(can_t *obj, PinName rd, PinName td) { |
mbed_official | 41:e8b66477f5bf | 237 | // Enable power and clock |
mbed_official | 41:e8b66477f5bf | 238 | LPC_SYSCON->PRESETCTRL |= PRESETCTRL_CAN_RST_N; |
mbed_official | 41:e8b66477f5bf | 239 | LPC_SYSCON->SYSAHBCLKCTRL |= SYSAHBCLKCTRL_CAN; |
mbed_official | 41:e8b66477f5bf | 240 | |
mbed_official | 41:e8b66477f5bf | 241 | // Enable Initialization mode |
mbed_official | 41:e8b66477f5bf | 242 | if (!(LPC_CAN->CNTL & CANCNTL_INIT)) { |
mbed_official | 41:e8b66477f5bf | 243 | LPC_CAN->CNTL |= CANCNTL_INIT; |
mbed_official | 41:e8b66477f5bf | 244 | } |
mbed_official | 41:e8b66477f5bf | 245 | |
mbed_official | 41:e8b66477f5bf | 246 | can_frequency(obj, 125000); |
mbed_official | 41:e8b66477f5bf | 247 | |
mbed_official | 41:e8b66477f5bf | 248 | // Resume operation |
mbed_official | 41:e8b66477f5bf | 249 | LPC_CAN->CNTL &= ~CANCNTL_INIT; |
mbed_official | 41:e8b66477f5bf | 250 | while ( LPC_CAN->CNTL & CANCNTL_INIT ); |
mbed_official | 41:e8b66477f5bf | 251 | |
mbed_official | 41:e8b66477f5bf | 252 | // Initialize RX message object |
mbed_official | 41:e8b66477f5bf | 253 | can_config_rxmsgobj(obj); |
mbed_official | 41:e8b66477f5bf | 254 | } |
mbed_official | 41:e8b66477f5bf | 255 | |
mbed_official | 41:e8b66477f5bf | 256 | void can_free(can_t *obj) { |
mbed_official | 41:e8b66477f5bf | 257 | LPC_SYSCON->SYSAHBCLKCTRL &= ~(SYSAHBCLKCTRL_CAN); |
mbed_official | 41:e8b66477f5bf | 258 | LPC_SYSCON->PRESETCTRL &= ~(PRESETCTRL_CAN_RST_N); |
mbed_official | 41:e8b66477f5bf | 259 | } |
mbed_official | 41:e8b66477f5bf | 260 | |
mbed_official | 41:e8b66477f5bf | 261 | int can_frequency(can_t *obj, int f) { |
mbed_official | 41:e8b66477f5bf | 262 | int btr = can_speed(SystemCoreClock, (unsigned int)f, 1); |
mbed_official | 41:e8b66477f5bf | 263 | int clkdiv = (btr >> 16) & 0x0F; |
mbed_official | 41:e8b66477f5bf | 264 | btr = btr & 0xFFFF; |
mbed_official | 41:e8b66477f5bf | 265 | |
mbed_official | 41:e8b66477f5bf | 266 | if (btr > 0) { |
mbed_official | 203:0f54f988aa69 | 267 | uint32_t cntl_init = LPC_CAN->CNTL | CANCNTL_INIT; |
mbed_official | 41:e8b66477f5bf | 268 | // Set the bit clock |
mbed_official | 203:0f54f988aa69 | 269 | LPC_CAN->CNTL |= CANCNTL_CCE | CANCNTL_INIT; |
mbed_official | 41:e8b66477f5bf | 270 | LPC_CAN->CLKDIV = clkdiv; |
mbed_official | 41:e8b66477f5bf | 271 | LPC_CAN->BT = btr; |
mbed_official | 41:e8b66477f5bf | 272 | LPC_CAN->BRPE = 0x0000; |
mbed_official | 203:0f54f988aa69 | 273 | LPC_CAN->CNTL &= ~(CANCNTL_CCE | CANCNTL_INIT); |
mbed_official | 203:0f54f988aa69 | 274 | LPC_CAN->CNTL |= cntl_init; |
mbed_official | 41:e8b66477f5bf | 275 | return 1; |
mbed_official | 41:e8b66477f5bf | 276 | } |
mbed_official | 41:e8b66477f5bf | 277 | return 0; |
mbed_official | 41:e8b66477f5bf | 278 | } |
mbed_official | 41:e8b66477f5bf | 279 | |
mbed_official | 203:0f54f988aa69 | 280 | int can_write(can_t *obj, CAN_Message msg, int cc) { |
mbed_official | 41:e8b66477f5bf | 281 | uint16_t msgnum = 0; |
mbed_official | 41:e8b66477f5bf | 282 | |
mbed_official | 41:e8b66477f5bf | 283 | // Make sure controller is enabled |
mbed_official | 41:e8b66477f5bf | 284 | can_enable(obj); |
mbed_official | 41:e8b66477f5bf | 285 | |
mbed_official | 41:e8b66477f5bf | 286 | // Make sure the interface is available |
mbed_official | 41:e8b66477f5bf | 287 | while( LPC_CAN->IF1_CMDREQ & CANIFn_CMDREQ_BUSY ); |
mbed_official | 41:e8b66477f5bf | 288 | |
mbed_official | 225:2af4c5d0160c | 289 | // Set the direction bit based on the message type |
mbed_official | 225:2af4c5d0160c | 290 | uint32_t direction = 0; |
mbed_official | 225:2af4c5d0160c | 291 | if (msg.type == CANData) { |
mbed_official | 225:2af4c5d0160c | 292 | direction = CANIFn_ARB2_DIR; |
mbed_official | 225:2af4c5d0160c | 293 | } |
mbed_official | 225:2af4c5d0160c | 294 | |
mbed_official | 41:e8b66477f5bf | 295 | if(msg.format == CANExtended) { |
mbed_official | 225:2af4c5d0160c | 296 | // Mark message valid, Extended Frame, Set Identifier and mask everything |
mbed_official | 41:e8b66477f5bf | 297 | LPC_CAN->IF1_ARB1 = BFN_PREP(msg.id, CANIFn_ARB1_ID); |
mbed_official | 225:2af4c5d0160c | 298 | LPC_CAN->IF1_ARB2 = CANIFn_ARB2_MSGVAL | CANIFn_ARB2_XTD | direction | BFN_PREP(msg.id >> 16, CANIFn_ARB2_ID); |
mbed_official | 41:e8b66477f5bf | 299 | LPC_CAN->IF1_MSK1 = BFN_PREP(ID_EXT_MASK, CANIFn_MSK1_MSK); |
mbed_official | 41:e8b66477f5bf | 300 | LPC_CAN->IF1_MSK2 = CANIFn_MSK2_MXTD | CANIFn_MSK2_MDIR | BFN_PREP(ID_EXT_MASK >> 16, CANIFn_MSK2_MSK); |
mbed_official | 41:e8b66477f5bf | 301 | } |
mbed_official | 41:e8b66477f5bf | 302 | else { |
mbed_official | 225:2af4c5d0160c | 303 | // Mark message valid, Set Identifier and mask everything |
mbed_official | 225:2af4c5d0160c | 304 | LPC_CAN->IF1_ARB2 = CANIFn_ARB2_MSGVAL | direction | BFN_PREP(msg.id << 2, CANIFn_ARB2_ID); |
mbed_official | 41:e8b66477f5bf | 305 | LPC_CAN->IF1_MSK2 = CANIFn_MSK2_MDIR | BFN_PREP(ID_STD_MASK << 2, CANIFn_MSK2_MSK); |
mbed_official | 41:e8b66477f5bf | 306 | } |
mbed_official | 41:e8b66477f5bf | 307 | |
mbed_official | 41:e8b66477f5bf | 308 | // Use mask, request transmission, single message object and set DLC |
mbed_official | 41:e8b66477f5bf | 309 | LPC_CAN->IF1_MCTRL = CANIFn_MCTRL_UMASK | CANIFn_MCTRL_TXRQST | CANIFn_MCTRL_EOB | BFN_PREP(msg.len, CANIFn_MCTRL_DLC); |
mbed_official | 41:e8b66477f5bf | 310 | |
mbed_official | 41:e8b66477f5bf | 311 | LPC_CAN->IF1_DA1 = BFN_PREP(msg.data[1], CANIFn_DA1_DATA1) | BFN_PREP(msg.data[0], CANIFn_DA1_DATA0); |
mbed_official | 41:e8b66477f5bf | 312 | LPC_CAN->IF1_DA2 = BFN_PREP(msg.data[3], CANIFn_DA2_DATA3) | BFN_PREP(msg.data[2], CANIFn_DA2_DATA2); |
mbed_official | 41:e8b66477f5bf | 313 | LPC_CAN->IF1_DB1 = BFN_PREP(msg.data[5], CANIFn_DB1_DATA5) | BFN_PREP(msg.data[4], CANIFn_DB1_DATA4); |
mbed_official | 41:e8b66477f5bf | 314 | LPC_CAN->IF1_DB2 = BFN_PREP(msg.data[7], CANIFn_DB2_DATA7) | BFN_PREP(msg.data[6], CANIFn_DB2_DATA6); |
mbed_official | 41:e8b66477f5bf | 315 | |
mbed_official | 41:e8b66477f5bf | 316 | // Transfer all fields to message object |
mbed_official | 41:e8b66477f5bf | 317 | LPC_CAN->IF1_CMDMSK = CANIFn_CMDMSK_WR | CANIFn_CMDMSK_MASK | CANIFn_CMDMSK_ARB | CANIFn_CMDMSK_CTRL | CANIFn_CMDMSK_TXRQST | CANIFn_CMDMSK_DATA_A | CANIFn_CMDMSK_DATA_B; |
mbed_official | 41:e8b66477f5bf | 318 | |
mbed_official | 41:e8b66477f5bf | 319 | // Start Transfer to given message number |
mbed_official | 41:e8b66477f5bf | 320 | LPC_CAN->IF1_CMDREQ = BFN_PREP(msgnum, CANIFn_CMDREQ_MN); |
mbed_official | 41:e8b66477f5bf | 321 | |
mbed_official | 41:e8b66477f5bf | 322 | // Wait until transfer to message ram complete - TODO: maybe not block?? |
mbed_official | 41:e8b66477f5bf | 323 | while( LPC_CAN->IF1_CMDREQ & CANIFn_CMDREQ_BUSY); |
mbed_official | 41:e8b66477f5bf | 324 | |
mbed_official | 41:e8b66477f5bf | 325 | // Wait until TXOK is set, then clear it - TODO: maybe not block |
mbed_official | 41:e8b66477f5bf | 326 | //while( !(LPC_CAN->STAT & CANSTAT_TXOK) ); |
mbed_official | 41:e8b66477f5bf | 327 | LPC_CAN->STAT &= ~(CANSTAT_TXOK); |
mbed_official | 41:e8b66477f5bf | 328 | |
mbed_official | 41:e8b66477f5bf | 329 | return 1; |
mbed_official | 41:e8b66477f5bf | 330 | } |
mbed_official | 41:e8b66477f5bf | 331 | |
mbed_official | 41:e8b66477f5bf | 332 | int can_read(can_t *obj, CAN_Message *msg, int handle) { |
mbed_official | 41:e8b66477f5bf | 333 | uint16_t i; |
mbed_official | 41:e8b66477f5bf | 334 | |
mbed_official | 41:e8b66477f5bf | 335 | // Make sure controller is enabled |
mbed_official | 41:e8b66477f5bf | 336 | can_enable(obj); |
mbed_official | 41:e8b66477f5bf | 337 | |
mbed_official | 41:e8b66477f5bf | 338 | // Find first message object with new data |
mbed_official | 41:e8b66477f5bf | 339 | if(handle == 0) { |
mbed_official | 41:e8b66477f5bf | 340 | uint32_t newdata = LPC_CAN->ND1 | (LPC_CAN->ND2 << 16); |
mbed_official | 41:e8b66477f5bf | 341 | // Find first free messagebox |
mbed_official | 41:e8b66477f5bf | 342 | for(i = 0; i < 32; i++) { |
mbed_official | 41:e8b66477f5bf | 343 | if(newdata & (1 << i)) { |
mbed_official | 41:e8b66477f5bf | 344 | handle = i+1; |
mbed_official | 41:e8b66477f5bf | 345 | break; |
mbed_official | 41:e8b66477f5bf | 346 | } |
mbed_official | 41:e8b66477f5bf | 347 | } |
mbed_official | 41:e8b66477f5bf | 348 | } |
mbed_official | 41:e8b66477f5bf | 349 | |
mbed_official | 41:e8b66477f5bf | 350 | if(handle > 0 && handle < 32) { |
mbed_official | 41:e8b66477f5bf | 351 | // Wait until message interface is free |
mbed_official | 41:e8b66477f5bf | 352 | while( LPC_CAN->IF2_CMDREQ & CANIFn_CMDREQ_BUSY ); |
mbed_official | 41:e8b66477f5bf | 353 | |
mbed_official | 41:e8b66477f5bf | 354 | // Transfer all fields to message object |
mbed_official | 41:e8b66477f5bf | 355 | LPC_CAN->IF2_CMDMSK = CANIFn_CMDMSK_RD | CANIFn_CMDMSK_MASK | CANIFn_CMDMSK_ARB | CANIFn_CMDMSK_CTRL | CANIFn_CMDMSK_CLRINTPND | CANIFn_CMDMSK_TXRQST | CANIFn_CMDMSK_DATA_A | CANIFn_CMDMSK_DATA_B; |
mbed_official | 41:e8b66477f5bf | 356 | |
mbed_official | 41:e8b66477f5bf | 357 | // Start Transfer from given message number |
mbed_official | 41:e8b66477f5bf | 358 | LPC_CAN->IF2_CMDREQ = BFN_PREP(handle, CANIFn_CMDREQ_MN); |
mbed_official | 41:e8b66477f5bf | 359 | |
mbed_official | 41:e8b66477f5bf | 360 | // Wait until transfer to message ram complete |
mbed_official | 41:e8b66477f5bf | 361 | while( LPC_CAN->IF2_CMDREQ & CANIFn_CMDREQ_BUSY ); |
mbed_official | 41:e8b66477f5bf | 362 | |
mbed_official | 203:0f54f988aa69 | 363 | if (LPC_CAN->IF2_ARB2 & CANIFn_ARB2_XTD) { |
mbed_official | 203:0f54f988aa69 | 364 | msg->format = CANExtended; |
mbed_official | 41:e8b66477f5bf | 365 | msg->id = (LPC_CAN->IF2_ARB1 & CANIFn_ARB2_ID_MASK) << 16; |
mbed_official | 41:e8b66477f5bf | 366 | msg->id |= (LPC_CAN->IF2_ARB2 & CANIFn_ARB2_ID_MASK); |
mbed_official | 41:e8b66477f5bf | 367 | } |
mbed_official | 41:e8b66477f5bf | 368 | else { |
mbed_official | 203:0f54f988aa69 | 369 | msg->format = CANStandard; |
mbed_official | 41:e8b66477f5bf | 370 | msg->id = (LPC_CAN->IF2_ARB2 & CANIFn_ARB2_ID_MASK) >> 2; |
mbed_official | 41:e8b66477f5bf | 371 | } |
mbed_official | 41:e8b66477f5bf | 372 | |
mbed_official | 225:2af4c5d0160c | 373 | if (LPC_CAN->IF2_ARB2 & CANIFn_ARB2_DIR) { |
mbed_official | 225:2af4c5d0160c | 374 | msg->type = CANRemote; |
mbed_official | 225:2af4c5d0160c | 375 | } |
mbed_official | 225:2af4c5d0160c | 376 | else { |
mbed_official | 225:2af4c5d0160c | 377 | msg->type = CANData; |
mbed_official | 225:2af4c5d0160c | 378 | } |
mbed_official | 225:2af4c5d0160c | 379 | |
mbed_official | 41:e8b66477f5bf | 380 | msg->len = BFN_GET(LPC_CAN->IF2_MCTRL, CANIFn_MCTRL_DLC); // TODO: If > 8, len = 8 |
mbed_official | 41:e8b66477f5bf | 381 | msg->data[0] = BFN_GET(LPC_CAN->IF2_DA1, CANIFn_DA1_DATA0); |
mbed_official | 41:e8b66477f5bf | 382 | msg->data[1] = BFN_GET(LPC_CAN->IF2_DA1, CANIFn_DA1_DATA1); |
mbed_official | 41:e8b66477f5bf | 383 | msg->data[2] = BFN_GET(LPC_CAN->IF2_DA2, CANIFn_DA2_DATA2); |
mbed_official | 41:e8b66477f5bf | 384 | msg->data[3] = BFN_GET(LPC_CAN->IF2_DA2, CANIFn_DA2_DATA3); |
mbed_official | 41:e8b66477f5bf | 385 | msg->data[4] = BFN_GET(LPC_CAN->IF2_DB1, CANIFn_DB1_DATA4); |
mbed_official | 41:e8b66477f5bf | 386 | msg->data[5] = BFN_GET(LPC_CAN->IF2_DB1, CANIFn_DB1_DATA5); |
mbed_official | 41:e8b66477f5bf | 387 | msg->data[6] = BFN_GET(LPC_CAN->IF2_DB2, CANIFn_DB2_DATA6); |
mbed_official | 41:e8b66477f5bf | 388 | msg->data[7] = BFN_GET(LPC_CAN->IF2_DB2, CANIFn_DB2_DATA7); |
mbed_official | 41:e8b66477f5bf | 389 | |
mbed_official | 41:e8b66477f5bf | 390 | LPC_CAN->STAT &= ~(CANSTAT_RXOK); |
mbed_official | 41:e8b66477f5bf | 391 | return 1; |
mbed_official | 41:e8b66477f5bf | 392 | } |
mbed_official | 41:e8b66477f5bf | 393 | |
mbed_official | 41:e8b66477f5bf | 394 | return 0; |
mbed_official | 41:e8b66477f5bf | 395 | } |
mbed_official | 41:e8b66477f5bf | 396 | |
mbed_official | 41:e8b66477f5bf | 397 | void can_reset(can_t *obj) { |
mbed_official | 41:e8b66477f5bf | 398 | LPC_SYSCON->PRESETCTRL &= ~PRESETCTRL_CAN_RST_N; |
mbed_official | 41:e8b66477f5bf | 399 | LPC_CAN->STAT = 0; |
mbed_official | 41:e8b66477f5bf | 400 | |
mbed_official | 41:e8b66477f5bf | 401 | can_config_rxmsgobj(obj); |
mbed_official | 41:e8b66477f5bf | 402 | } |
mbed_official | 41:e8b66477f5bf | 403 | |
mbed_official | 41:e8b66477f5bf | 404 | unsigned char can_rderror(can_t *obj) { |
mbed_official | 41:e8b66477f5bf | 405 | return BFN_GET(LPC_CAN->EC, CANEC_REC); |
mbed_official | 41:e8b66477f5bf | 406 | } |
mbed_official | 41:e8b66477f5bf | 407 | |
mbed_official | 41:e8b66477f5bf | 408 | unsigned char can_tderror(can_t *obj) { |
mbed_official | 41:e8b66477f5bf | 409 | return BFN_GET(LPC_CAN->EC, CANEC_TEC); |
mbed_official | 41:e8b66477f5bf | 410 | } |
mbed_official | 41:e8b66477f5bf | 411 | |
mbed_official | 41:e8b66477f5bf | 412 | void can_monitor(can_t *obj, int silent) { |
mbed_official | 41:e8b66477f5bf | 413 | if (silent) { |
mbed_official | 41:e8b66477f5bf | 414 | LPC_CAN->CNTL |= CANCNTL_TEST; |
mbed_official | 41:e8b66477f5bf | 415 | LPC_CAN->TEST |= CANTEST_SILENT; |
mbed_official | 41:e8b66477f5bf | 416 | } else { |
mbed_official | 41:e8b66477f5bf | 417 | LPC_CAN->CNTL &= ~(CANCNTL_TEST); |
mbed_official | 41:e8b66477f5bf | 418 | LPC_CAN->TEST &= ~CANTEST_SILENT; |
mbed_official | 41:e8b66477f5bf | 419 | } |
mbed_official | 41:e8b66477f5bf | 420 | |
mbed_official | 41:e8b66477f5bf | 421 | if (!(LPC_CAN->CNTL & CANCNTL_INIT)) { |
mbed_official | 41:e8b66477f5bf | 422 | LPC_CAN->CNTL |= CANCNTL_INIT; |
mbed_official | 41:e8b66477f5bf | 423 | } |
mbed_official | 41:e8b66477f5bf | 424 | } |