added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
JojoS
Date:
Sat Sep 10 15:32:04 2016 +0000
Revision:
147:ba84b7dc41a7
Parent:
144:ef7eb2e8f9f7
added prescaler for 16 bit timers (solution as in LPC11xx), default prescaler 31 for max 28 ms period time

Who changed what in which revision?

UserRevisionLine numberNew contents of line
<> 144:ef7eb2e8f9f7 1 /* mbed Microcontroller Library
<> 144:ef7eb2e8f9f7 2 * Copyright (c) 2006-2015 ARM Limited
<> 144:ef7eb2e8f9f7 3 *
<> 144:ef7eb2e8f9f7 4 * Licensed under the Apache License, Version 2.0 (the "License");
<> 144:ef7eb2e8f9f7 5 * you may not use this file except in compliance with the License.
<> 144:ef7eb2e8f9f7 6 * You may obtain a copy of the License at
<> 144:ef7eb2e8f9f7 7 *
<> 144:ef7eb2e8f9f7 8 * http://www.apache.org/licenses/LICENSE-2.0
<> 144:ef7eb2e8f9f7 9 *
<> 144:ef7eb2e8f9f7 10 * Unless required by applicable law or agreed to in writing, software
<> 144:ef7eb2e8f9f7 11 * distributed under the License is distributed on an "AS IS" BASIS,
<> 144:ef7eb2e8f9f7 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<> 144:ef7eb2e8f9f7 13 * See the License for the specific language governing permissions and
<> 144:ef7eb2e8f9f7 14 * limitations under the License.
<> 144:ef7eb2e8f9f7 15 */
<> 144:ef7eb2e8f9f7 16 #include "mbed_assert.h"
<> 144:ef7eb2e8f9f7 17 #include "can_api.h"
<> 144:ef7eb2e8f9f7 18 #include "cmsis.h"
<> 144:ef7eb2e8f9f7 19 #include "pinmap.h"
<> 144:ef7eb2e8f9f7 20
<> 144:ef7eb2e8f9f7 21 #include <math.h>
<> 144:ef7eb2e8f9f7 22 #include <string.h>
<> 144:ef7eb2e8f9f7 23
<> 144:ef7eb2e8f9f7 24 /* Acceptance filter mode in AFMR register */
<> 144:ef7eb2e8f9f7 25 #define ACCF_OFF 0x01
<> 144:ef7eb2e8f9f7 26 #define ACCF_BYPASS 0x02
<> 144:ef7eb2e8f9f7 27 #define ACCF_ON 0x00
<> 144:ef7eb2e8f9f7 28 #define ACCF_FULLCAN 0x04
<> 144:ef7eb2e8f9f7 29
<> 144:ef7eb2e8f9f7 30 /* There are several bit timing calculators on the internet.
<> 144:ef7eb2e8f9f7 31 http://www.port.de/engl/canprod/sv_req_form.html
<> 144:ef7eb2e8f9f7 32 http://www.kvaser.com/can/index.htm
<> 144:ef7eb2e8f9f7 33 */
<> 144:ef7eb2e8f9f7 34
<> 144:ef7eb2e8f9f7 35 static const PinMap PinMap_CAN_RD[] = {
<> 144:ef7eb2e8f9f7 36 {P0_0 , CAN_1, 1},
<> 144:ef7eb2e8f9f7 37 {P0_4 , CAN_2, 2},
<> 144:ef7eb2e8f9f7 38 {P0_21, CAN_1, 3},
<> 144:ef7eb2e8f9f7 39 {P2_7 , CAN_2, 1},
<> 144:ef7eb2e8f9f7 40 {NC , NC , 0}
<> 144:ef7eb2e8f9f7 41 };
<> 144:ef7eb2e8f9f7 42
<> 144:ef7eb2e8f9f7 43 static const PinMap PinMap_CAN_TD[] = {
<> 144:ef7eb2e8f9f7 44 {P0_1 , CAN_1, 1},
<> 144:ef7eb2e8f9f7 45 {P0_5 , CAN_2, 2},
<> 144:ef7eb2e8f9f7 46 {P0_22, CAN_1, 3},
<> 144:ef7eb2e8f9f7 47 {P2_8 , CAN_2, 1},
<> 144:ef7eb2e8f9f7 48 {NC , NC , 0}
<> 144:ef7eb2e8f9f7 49 };
<> 144:ef7eb2e8f9f7 50
<> 144:ef7eb2e8f9f7 51 // Type definition to hold a CAN message
<> 144:ef7eb2e8f9f7 52 struct CANMsg {
<> 144:ef7eb2e8f9f7 53 unsigned int reserved1 : 16;
<> 144:ef7eb2e8f9f7 54 unsigned int dlc : 4; // Bits 16..19: DLC - Data Length Counter
<> 144:ef7eb2e8f9f7 55 unsigned int reserved0 : 10;
<> 144:ef7eb2e8f9f7 56 unsigned int rtr : 1; // Bit 30: Set if this is a RTR message
<> 144:ef7eb2e8f9f7 57 unsigned int type : 1; // Bit 31: Set if this is a 29-bit ID message
<> 144:ef7eb2e8f9f7 58 unsigned int id; // CAN Message ID (11-bit or 29-bit)
<> 144:ef7eb2e8f9f7 59 unsigned char data[8]; // CAN Message Data Bytes 0-7
<> 144:ef7eb2e8f9f7 60 };
<> 144:ef7eb2e8f9f7 61 typedef struct CANMsg CANMsg;
<> 144:ef7eb2e8f9f7 62
<> 144:ef7eb2e8f9f7 63 static uint32_t can_disable(can_t *obj) {
<> 144:ef7eb2e8f9f7 64 uint32_t sm = obj->dev->MOD;
<> 144:ef7eb2e8f9f7 65 obj->dev->MOD |= 1;
<> 144:ef7eb2e8f9f7 66 return sm;
<> 144:ef7eb2e8f9f7 67 }
<> 144:ef7eb2e8f9f7 68
<> 144:ef7eb2e8f9f7 69 static inline void can_enable(can_t *obj) {
<> 144:ef7eb2e8f9f7 70 if (obj->dev->MOD & 1) {
<> 144:ef7eb2e8f9f7 71 obj->dev->MOD &= ~(1);
<> 144:ef7eb2e8f9f7 72 }
<> 144:ef7eb2e8f9f7 73 }
<> 144:ef7eb2e8f9f7 74
<> 144:ef7eb2e8f9f7 75 int can_mode(can_t *obj, CanMode mode) {
<> 144:ef7eb2e8f9f7 76 return 0; // not implemented
<> 144:ef7eb2e8f9f7 77 }
<> 144:ef7eb2e8f9f7 78
<> 144:ef7eb2e8f9f7 79 int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle) {
<> 144:ef7eb2e8f9f7 80 return 0; // not implemented
<> 144:ef7eb2e8f9f7 81 }
<> 144:ef7eb2e8f9f7 82
<> 144:ef7eb2e8f9f7 83 static int can_pclk(can_t *obj) {
<> 144:ef7eb2e8f9f7 84 int value = 0;
<> 144:ef7eb2e8f9f7 85 switch ((int)obj->dev) {
<> 144:ef7eb2e8f9f7 86 case CAN_1: value = (LPC_SC->PCLKSEL0 & (0x3 << 26)) >> 26; break;
<> 144:ef7eb2e8f9f7 87 case CAN_2: value = (LPC_SC->PCLKSEL0 & (0x3 << 28)) >> 28; break;
<> 144:ef7eb2e8f9f7 88 }
<> 144:ef7eb2e8f9f7 89
<> 144:ef7eb2e8f9f7 90 switch (value) {
<> 144:ef7eb2e8f9f7 91 case 1: return 1;
<> 144:ef7eb2e8f9f7 92 case 2: return 2;
<> 144:ef7eb2e8f9f7 93 case 3: return 6;
<> 144:ef7eb2e8f9f7 94 default: return 4;
<> 144:ef7eb2e8f9f7 95 }
<> 144:ef7eb2e8f9f7 96 }
<> 144:ef7eb2e8f9f7 97
<> 144:ef7eb2e8f9f7 98 // This table has the sampling points as close to 75% as possible. The first
<> 144:ef7eb2e8f9f7 99 // value is TSEG1, the second TSEG2.
<> 144:ef7eb2e8f9f7 100 static const int timing_pts[23][2] = {
<> 144:ef7eb2e8f9f7 101 {0x0, 0x0}, // 2, 50%
<> 144:ef7eb2e8f9f7 102 {0x1, 0x0}, // 3, 67%
<> 144:ef7eb2e8f9f7 103 {0x2, 0x0}, // 4, 75%
<> 144:ef7eb2e8f9f7 104 {0x3, 0x0}, // 5, 80%
<> 144:ef7eb2e8f9f7 105 {0x3, 0x1}, // 6, 67%
<> 144:ef7eb2e8f9f7 106 {0x4, 0x1}, // 7, 71%
<> 144:ef7eb2e8f9f7 107 {0x5, 0x1}, // 8, 75%
<> 144:ef7eb2e8f9f7 108 {0x6, 0x1}, // 9, 78%
<> 144:ef7eb2e8f9f7 109 {0x6, 0x2}, // 10, 70%
<> 144:ef7eb2e8f9f7 110 {0x7, 0x2}, // 11, 73%
<> 144:ef7eb2e8f9f7 111 {0x8, 0x2}, // 12, 75%
<> 144:ef7eb2e8f9f7 112 {0x9, 0x2}, // 13, 77%
<> 144:ef7eb2e8f9f7 113 {0x9, 0x3}, // 14, 71%
<> 144:ef7eb2e8f9f7 114 {0xA, 0x3}, // 15, 73%
<> 144:ef7eb2e8f9f7 115 {0xB, 0x3}, // 16, 75%
<> 144:ef7eb2e8f9f7 116 {0xC, 0x3}, // 17, 76%
<> 144:ef7eb2e8f9f7 117 {0xD, 0x3}, // 18, 78%
<> 144:ef7eb2e8f9f7 118 {0xD, 0x4}, // 19, 74%
<> 144:ef7eb2e8f9f7 119 {0xE, 0x4}, // 20, 75%
<> 144:ef7eb2e8f9f7 120 {0xF, 0x4}, // 21, 76%
<> 144:ef7eb2e8f9f7 121 {0xF, 0x5}, // 22, 73%
<> 144:ef7eb2e8f9f7 122 {0xF, 0x6}, // 23, 70%
<> 144:ef7eb2e8f9f7 123 {0xF, 0x7}, // 24, 67%
<> 144:ef7eb2e8f9f7 124 };
<> 144:ef7eb2e8f9f7 125
<> 144:ef7eb2e8f9f7 126 static unsigned int can_speed(unsigned int sclk, unsigned int pclk, unsigned int cclk, unsigned char psjw) {
<> 144:ef7eb2e8f9f7 127 uint32_t btr;
<> 144:ef7eb2e8f9f7 128 uint16_t brp = 0;
<> 144:ef7eb2e8f9f7 129 uint32_t calcbit;
<> 144:ef7eb2e8f9f7 130 uint32_t bitwidth;
<> 144:ef7eb2e8f9f7 131 int hit = 0;
<> 144:ef7eb2e8f9f7 132 int bits;
<> 144:ef7eb2e8f9f7 133
<> 144:ef7eb2e8f9f7 134 bitwidth = sclk / (pclk * cclk);
<> 144:ef7eb2e8f9f7 135
<> 144:ef7eb2e8f9f7 136 brp = bitwidth / 0x18;
<> 144:ef7eb2e8f9f7 137 while ((!hit) && (brp < bitwidth / 4)) {
<> 144:ef7eb2e8f9f7 138 brp++;
<> 144:ef7eb2e8f9f7 139 for (bits = 22; bits > 0; bits--) {
<> 144:ef7eb2e8f9f7 140 calcbit = (bits + 3) * (brp + 1);
<> 144:ef7eb2e8f9f7 141 if (calcbit == bitwidth) {
<> 144:ef7eb2e8f9f7 142 hit = 1;
<> 144:ef7eb2e8f9f7 143 break;
<> 144:ef7eb2e8f9f7 144 }
<> 144:ef7eb2e8f9f7 145 }
<> 144:ef7eb2e8f9f7 146 }
<> 144:ef7eb2e8f9f7 147
<> 144:ef7eb2e8f9f7 148 if (hit) {
<> 144:ef7eb2e8f9f7 149 btr = ((timing_pts[bits][1] << 20) & 0x00700000)
<> 144:ef7eb2e8f9f7 150 | ((timing_pts[bits][0] << 16) & 0x000F0000)
<> 144:ef7eb2e8f9f7 151 | ((psjw << 14) & 0x0000C000)
<> 144:ef7eb2e8f9f7 152 | ((brp << 0) & 0x000003FF);
<> 144:ef7eb2e8f9f7 153 } else {
<> 144:ef7eb2e8f9f7 154 btr = 0xFFFFFFFF;
<> 144:ef7eb2e8f9f7 155 }
<> 144:ef7eb2e8f9f7 156
<> 144:ef7eb2e8f9f7 157 return btr;
<> 144:ef7eb2e8f9f7 158 }
<> 144:ef7eb2e8f9f7 159
<> 144:ef7eb2e8f9f7 160 void can_init(can_t *obj, PinName rd, PinName td) {
<> 144:ef7eb2e8f9f7 161 CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
<> 144:ef7eb2e8f9f7 162 CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
<> 144:ef7eb2e8f9f7 163 obj->dev = (LPC_CAN_TypeDef *)pinmap_merge(can_rd, can_td);
<> 144:ef7eb2e8f9f7 164 MBED_ASSERT((int)obj->dev != NC);
<> 144:ef7eb2e8f9f7 165
<> 144:ef7eb2e8f9f7 166 switch ((int)obj->dev) {
<> 144:ef7eb2e8f9f7 167 case CAN_1: LPC_SC->PCONP |= 1 << PCAN1; break;
<> 144:ef7eb2e8f9f7 168 case CAN_2: LPC_SC->PCONP |= 1 << PCAN2; break;
<> 144:ef7eb2e8f9f7 169 }
<> 144:ef7eb2e8f9f7 170
<> 144:ef7eb2e8f9f7 171 pinmap_pinout(rd, PinMap_CAN_RD);
<> 144:ef7eb2e8f9f7 172 pinmap_pinout(td, PinMap_CAN_TD);
<> 144:ef7eb2e8f9f7 173
<> 144:ef7eb2e8f9f7 174 can_reset(obj);
<> 144:ef7eb2e8f9f7 175 obj->dev->IER = 0; // Disable Interrupts
<> 144:ef7eb2e8f9f7 176 can_frequency(obj, 100000);
<> 144:ef7eb2e8f9f7 177
<> 144:ef7eb2e8f9f7 178 LPC_CANAF->AFMR = ACCF_BYPASS; // Bypass Filter
<> 144:ef7eb2e8f9f7 179 }
<> 144:ef7eb2e8f9f7 180
<> 144:ef7eb2e8f9f7 181 void can_free(can_t *obj) {
<> 144:ef7eb2e8f9f7 182 switch ((int)obj->dev) {
<> 144:ef7eb2e8f9f7 183 case CAN_1: LPC_SC->PCONP &= ~(1 << PCAN1); break;
<> 144:ef7eb2e8f9f7 184 case CAN_2: LPC_SC->PCONP &= ~(1 << PCAN2); break;
<> 144:ef7eb2e8f9f7 185 }
<> 144:ef7eb2e8f9f7 186 }
<> 144:ef7eb2e8f9f7 187
<> 144:ef7eb2e8f9f7 188 int can_frequency(can_t *obj, int f) {
<> 144:ef7eb2e8f9f7 189 int pclk = can_pclk(obj);
<> 144:ef7eb2e8f9f7 190 int btr = can_speed(SystemCoreClock, pclk, (unsigned int)f, 1);
<> 144:ef7eb2e8f9f7 191
<> 144:ef7eb2e8f9f7 192 if (btr > 0) {
<> 144:ef7eb2e8f9f7 193 uint32_t modmask = can_disable(obj);
<> 144:ef7eb2e8f9f7 194 obj->dev->BTR = btr;
<> 144:ef7eb2e8f9f7 195 obj->dev->MOD = modmask;
<> 144:ef7eb2e8f9f7 196 return 1;
<> 144:ef7eb2e8f9f7 197 } else {
<> 144:ef7eb2e8f9f7 198 return 0;
<> 144:ef7eb2e8f9f7 199 }
<> 144:ef7eb2e8f9f7 200 }
<> 144:ef7eb2e8f9f7 201
<> 144:ef7eb2e8f9f7 202 int can_write(can_t *obj, CAN_Message msg, int cc) {
<> 144:ef7eb2e8f9f7 203 unsigned int CANStatus;
<> 144:ef7eb2e8f9f7 204 CANMsg m;
<> 144:ef7eb2e8f9f7 205
<> 144:ef7eb2e8f9f7 206 can_enable(obj);
<> 144:ef7eb2e8f9f7 207
<> 144:ef7eb2e8f9f7 208 m.id = msg.id ;
<> 144:ef7eb2e8f9f7 209 m.dlc = msg.len & 0xF;
<> 144:ef7eb2e8f9f7 210 m.rtr = msg.type;
<> 144:ef7eb2e8f9f7 211 m.type = msg.format;
<> 144:ef7eb2e8f9f7 212 memcpy(m.data, msg.data, msg.len);
<> 144:ef7eb2e8f9f7 213 const unsigned int *buf = (const unsigned int *)&m;
<> 144:ef7eb2e8f9f7 214
<> 144:ef7eb2e8f9f7 215 CANStatus = obj->dev->SR;
<> 144:ef7eb2e8f9f7 216 if (CANStatus & 0x00000004) {
<> 144:ef7eb2e8f9f7 217 obj->dev->TFI1 = buf[0] & 0xC00F0000;
<> 144:ef7eb2e8f9f7 218 obj->dev->TID1 = buf[1];
<> 144:ef7eb2e8f9f7 219 obj->dev->TDA1 = buf[2];
<> 144:ef7eb2e8f9f7 220 obj->dev->TDB1 = buf[3];
<> 144:ef7eb2e8f9f7 221 if (cc) {
<> 144:ef7eb2e8f9f7 222 obj->dev->CMR = 0x30;
<> 144:ef7eb2e8f9f7 223 } else {
<> 144:ef7eb2e8f9f7 224 obj->dev->CMR = 0x21;
<> 144:ef7eb2e8f9f7 225 }
<> 144:ef7eb2e8f9f7 226 return 1;
<> 144:ef7eb2e8f9f7 227
<> 144:ef7eb2e8f9f7 228 } else if (CANStatus & 0x00000400) {
<> 144:ef7eb2e8f9f7 229 obj->dev->TFI2 = buf[0] & 0xC00F0000;
<> 144:ef7eb2e8f9f7 230 obj->dev->TID2 = buf[1];
<> 144:ef7eb2e8f9f7 231 obj->dev->TDA2 = buf[2];
<> 144:ef7eb2e8f9f7 232 obj->dev->TDB2 = buf[3];
<> 144:ef7eb2e8f9f7 233 if (cc) {
<> 144:ef7eb2e8f9f7 234 obj->dev->CMR = 0x50;
<> 144:ef7eb2e8f9f7 235 } else {
<> 144:ef7eb2e8f9f7 236 obj->dev->CMR = 0x41;
<> 144:ef7eb2e8f9f7 237 }
<> 144:ef7eb2e8f9f7 238 return 1;
<> 144:ef7eb2e8f9f7 239
<> 144:ef7eb2e8f9f7 240 } else if (CANStatus & 0x00040000) {
<> 144:ef7eb2e8f9f7 241 obj->dev->TFI3 = buf[0] & 0xC00F0000;
<> 144:ef7eb2e8f9f7 242 obj->dev->TID3 = buf[1];
<> 144:ef7eb2e8f9f7 243 obj->dev->TDA3 = buf[2];
<> 144:ef7eb2e8f9f7 244 obj->dev->TDB3 = buf[3];
<> 144:ef7eb2e8f9f7 245 if (cc) {
<> 144:ef7eb2e8f9f7 246 obj->dev->CMR = 0x90;
<> 144:ef7eb2e8f9f7 247 } else {
<> 144:ef7eb2e8f9f7 248 obj->dev->CMR = 0x81;
<> 144:ef7eb2e8f9f7 249 }
<> 144:ef7eb2e8f9f7 250 return 1;
<> 144:ef7eb2e8f9f7 251 }
<> 144:ef7eb2e8f9f7 252
<> 144:ef7eb2e8f9f7 253 return 0;
<> 144:ef7eb2e8f9f7 254 }
<> 144:ef7eb2e8f9f7 255
<> 144:ef7eb2e8f9f7 256 int can_read(can_t *obj, CAN_Message *msg, int handle) {
<> 144:ef7eb2e8f9f7 257 CANMsg x;
<> 144:ef7eb2e8f9f7 258 unsigned int *i = (unsigned int *)&x;
<> 144:ef7eb2e8f9f7 259
<> 144:ef7eb2e8f9f7 260 can_enable(obj);
<> 144:ef7eb2e8f9f7 261
<> 144:ef7eb2e8f9f7 262 if (obj->dev->GSR & 0x1) {
<> 144:ef7eb2e8f9f7 263 *i++ = obj->dev->RFS; // Frame
<> 144:ef7eb2e8f9f7 264 *i++ = obj->dev->RID; // ID
<> 144:ef7eb2e8f9f7 265 *i++ = obj->dev->RDA; // Data A
<> 144:ef7eb2e8f9f7 266 *i++ = obj->dev->RDB; // Data B
<> 144:ef7eb2e8f9f7 267 obj->dev->CMR = 0x04; // release receive buffer
<> 144:ef7eb2e8f9f7 268
<> 144:ef7eb2e8f9f7 269 msg->id = x.id;
<> 144:ef7eb2e8f9f7 270 msg->len = x.dlc;
<> 144:ef7eb2e8f9f7 271 msg->format = (x.type)? CANExtended : CANStandard;
<> 144:ef7eb2e8f9f7 272 msg->type = (x.rtr)? CANRemote: CANData;
<> 144:ef7eb2e8f9f7 273 memcpy(msg->data,x.data,x.dlc);
<> 144:ef7eb2e8f9f7 274 return 1;
<> 144:ef7eb2e8f9f7 275 }
<> 144:ef7eb2e8f9f7 276
<> 144:ef7eb2e8f9f7 277 return 0;
<> 144:ef7eb2e8f9f7 278 }
<> 144:ef7eb2e8f9f7 279
<> 144:ef7eb2e8f9f7 280 void can_reset(can_t *obj) {
<> 144:ef7eb2e8f9f7 281 can_disable(obj);
<> 144:ef7eb2e8f9f7 282 obj->dev->GSR = 0; // Reset error counter when CAN1MOD is in reset
<> 144:ef7eb2e8f9f7 283 }
<> 144:ef7eb2e8f9f7 284
<> 144:ef7eb2e8f9f7 285 unsigned char can_rderror(can_t *obj) {
<> 144:ef7eb2e8f9f7 286 return (obj->dev->GSR >> 16) & 0xFF;
<> 144:ef7eb2e8f9f7 287 }
<> 144:ef7eb2e8f9f7 288
<> 144:ef7eb2e8f9f7 289 unsigned char can_tderror(can_t *obj) {
<> 144:ef7eb2e8f9f7 290 return (obj->dev->GSR >> 24) & 0xFF;
<> 144:ef7eb2e8f9f7 291 }
<> 144:ef7eb2e8f9f7 292
<> 144:ef7eb2e8f9f7 293 void can_monitor(can_t *obj, int silent) {
<> 144:ef7eb2e8f9f7 294 uint32_t mod_mask = can_disable(obj);
<> 144:ef7eb2e8f9f7 295 if (silent) {
<> 144:ef7eb2e8f9f7 296 obj->dev->MOD |= (1 << 1);
<> 144:ef7eb2e8f9f7 297 } else {
<> 144:ef7eb2e8f9f7 298 obj->dev->MOD &= ~(1 << 1);
<> 144:ef7eb2e8f9f7 299 }
<> 144:ef7eb2e8f9f7 300 if (!(mod_mask & 1)) {
<> 144:ef7eb2e8f9f7 301 can_enable(obj);
<> 144:ef7eb2e8f9f7 302 }
<> 144:ef7eb2e8f9f7 303 }