]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC408X/TARGET_LPC4088/can_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC408X / TARGET_LPC4088 / can_api.c
1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2013 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "can_api.h"
17
18 #include "cmsis.h"
19 #include "pinmap.h"
20
21 #include <math.h>
22 #include <string.h>
23
24 #define CAN_NUM    2
25
26 /* Acceptance filter mode in AFMR register */
27 #define ACCF_OFF                0x01
28 #define ACCF_BYPASS             0x02
29 #define ACCF_ON                 0x00
30 #define ACCF_FULLCAN            0x04
31
32 /* There are several bit timing calculators on the internet.
33 http://www.port.de/engl/canprod/sv_req_form.html
34 http://www.kvaser.com/can/index.htm
35 */
36
37 static const PinMap PinMap_CAN_RD[] = {
38     {P0_0 , CAN_1, 1},
39     {P0_4 , CAN_2, 2},
40     {P0_21, CAN_1, 4},
41     {P2_7 , CAN_2, 1},
42     {NC   , NC   , 0}
43 };
44
45 static const PinMap PinMap_CAN_TD[] = {
46     {P0_1 , CAN_1, 1},
47     {P0_5 , CAN_2, 2},
48     {P0_22, CAN_1, 4},
49     {P2_8 , CAN_2, 1},
50     {NC   , NC   , 0}
51 };
52
53 // Type definition to hold a CAN message
54 struct CANMsg {
55     unsigned int  reserved1 : 16;
56     unsigned int  dlc       :  4; // Bits 16..19: DLC - Data Length Counter
57     unsigned int  reserved0 : 10;
58     unsigned int  rtr       :  1; // Bit 30: Set if this is a RTR message
59     unsigned int  type      :  1; // Bit 31: Set if this is a 29-bit ID message
60     unsigned int  id;             // CAN Message ID (11-bit or 29-bit)
61     unsigned char data[8];        // CAN Message Data Bytes 0-7
62 };
63 typedef struct CANMsg CANMsg;
64
65 static uint32_t can_irq_ids[CAN_NUM] = {0};
66 static can_irq_handler irq_handler;
67
68 static uint32_t can_disable(can_t *obj) {
69     uint32_t sm = obj->dev->MOD;
70     obj->dev->MOD |= 1;
71     return sm;
72 }
73
74 static inline void can_enable(can_t *obj) {
75     if (obj->dev->MOD & 1) {
76         obj->dev->MOD &= ~(1);
77     }
78 }
79
80 int can_mode(can_t *obj, CanMode mode)
81 {
82     return 0; // not implemented
83 }
84
85 int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle) {
86     return 0; // not implemented
87 }
88
89 static inline void can_irq(uint32_t icr, uint32_t index) {
90     uint32_t i;
91     
92     for(i = 0; i < 8; i++)
93     {
94         if((can_irq_ids[index] != 0) && (icr & (1 << i)))
95         {
96             switch (i) {
97                 case 0: irq_handler(can_irq_ids[index], IRQ_RX);      break;
98                 case 1: irq_handler(can_irq_ids[index], IRQ_TX);      break;
99                 case 2: irq_handler(can_irq_ids[index], IRQ_ERROR);   break;
100                 case 3: irq_handler(can_irq_ids[index], IRQ_OVERRUN); break;
101                 case 4: irq_handler(can_irq_ids[index], IRQ_WAKEUP);  break;
102                 case 5: irq_handler(can_irq_ids[index], IRQ_PASSIVE); break;
103                 case 6: irq_handler(can_irq_ids[index], IRQ_ARB);     break;
104                 case 7: irq_handler(can_irq_ids[index], IRQ_BUS);     break;
105                 case 8: irq_handler(can_irq_ids[index], IRQ_READY);   break;
106             }
107         }
108     }
109 }
110
111 // Have to check that the CAN block is active before reading the Interrupt
112 // Control Register, or the mbed hangs
113 void can_irq_n() {
114     uint32_t icr;
115
116     if(LPC_SC->PCONP & (1 << 13)) {
117         icr = LPC_CAN1->ICR & 0x1FF;
118         can_irq(icr, 0);
119     }
120
121     if(LPC_SC->PCONP & (1 << 14)) {
122         icr = LPC_CAN2->ICR & 0x1FF;
123         can_irq(icr, 1);
124     }
125 }
126
127 // Register CAN object's irq handler
128 void can_irq_init(can_t *obj, can_irq_handler handler, uint32_t id) {
129     irq_handler = handler;
130     can_irq_ids[obj->index] = id;
131 }
132
133 // Unregister CAN object's irq handler
134 void can_irq_free(can_t *obj) {
135     obj->dev->IER &= ~(1);
136     can_irq_ids[obj->index] = 0;
137
138     if ((can_irq_ids[0] == 0) && (can_irq_ids[1] == 0)) {
139         NVIC_DisableIRQ(CAN_IRQn);
140     }
141 }
142
143 // Clear or set a irq
144 void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable) {
145     uint32_t ier;
146     
147     switch (type) {
148         case IRQ_RX:      ier = (1 << 0); break;
149         case IRQ_TX:      ier = (1 << 1); break;
150         case IRQ_ERROR:   ier = (1 << 2); break;
151         case IRQ_OVERRUN: ier = (1 << 3); break;
152         case IRQ_WAKEUP:  ier = (1 << 4); break;
153         case IRQ_PASSIVE: ier = (1 << 5); break;
154         case IRQ_ARB:     ier = (1 << 6); break;
155         case IRQ_BUS:     ier = (1 << 7); break;
156         case IRQ_READY:   ier = (1 << 8); break;
157         default: return;
158     }
159     
160     obj->dev->MOD |= 1;
161     if(enable == 0) {
162         obj->dev->IER &= ~ier;
163     }
164     else {
165         obj->dev->IER |= ier;
166     }
167     obj->dev->MOD &= ~(1);
168     
169     // Enable NVIC if at least 1 interrupt is active
170     if(((LPC_SC->PCONP & (1 << 13)) && LPC_CAN1->IER) || ((LPC_SC->PCONP & (1 << 14)) && LPC_CAN2->IER)) {
171         NVIC_SetVector(CAN_IRQn, (uint32_t) &can_irq_n);
172         NVIC_EnableIRQ(CAN_IRQn);
173     }
174     else {
175         NVIC_DisableIRQ(CAN_IRQn);
176     }
177 }
178
179 // This table has the sampling points as close to 75% as possible. The first
180 // value is TSEG1, the second TSEG2.
181 static const int timing_pts[23][2] = {
182     {0x0, 0x0},      // 2,  50%
183     {0x1, 0x0},      // 3,  67%
184     {0x2, 0x0},      // 4,  75%
185     {0x3, 0x0},      // 5,  80%
186     {0x3, 0x1},      // 6,  67%
187     {0x4, 0x1},      // 7,  71%
188     {0x5, 0x1},      // 8,  75%
189     {0x6, 0x1},      // 9,  78%
190     {0x6, 0x2},      // 10, 70%
191     {0x7, 0x2},      // 11, 73%
192     {0x8, 0x2},      // 12, 75%
193     {0x9, 0x2},      // 13, 77%
194     {0x9, 0x3},      // 14, 71%
195     {0xA, 0x3},      // 15, 73%
196     {0xB, 0x3},      // 16, 75%
197     {0xC, 0x3},      // 17, 76%
198     {0xD, 0x3},      // 18, 78%
199     {0xD, 0x4},      // 19, 74%
200     {0xE, 0x4},      // 20, 75%
201     {0xF, 0x4},      // 21, 76%
202     {0xF, 0x5},      // 22, 73%
203     {0xF, 0x6},      // 23, 70%
204     {0xF, 0x7},      // 24, 67%
205 };
206
207 static unsigned int can_speed(unsigned int pclk, unsigned int cclk, unsigned char psjw) {
208     uint32_t    btr;
209     uint16_t    brp = 0;
210     uint32_t    calcbit;
211     uint32_t    bitwidth;
212     int         hit = 0;
213     int         bits;
214     
215     bitwidth = (pclk / cclk);
216     
217     brp = bitwidth / 0x18;
218     while ((!hit) && (brp < bitwidth / 4)) {
219         brp++;
220         for (bits = 22; bits > 0; bits--) {
221             calcbit = (bits + 3) * (brp + 1);
222             if (calcbit == bitwidth) {
223                 hit = 1;
224                 break;
225             }
226         }
227     }
228     
229     if (hit) {
230         btr = ((timing_pts[bits][1] << 20) & 0x00700000)
231             | ((timing_pts[bits][0] << 16) & 0x000F0000)
232             | ((psjw                << 14) & 0x0000C000)
233             | ((brp                 <<  0) & 0x000003FF);
234     } else {
235         btr = 0xFFFFFFFF;
236     }
237     
238     return btr;
239
240 }
241
242 void can_init(can_t *obj, PinName rd, PinName td) {
243     CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
244     CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
245     obj->dev = (LPC_CAN_TypeDef *)pinmap_merge(can_rd, can_td);
246     MBED_ASSERT((int)obj->dev != NC);
247
248     switch ((int)obj->dev) {
249         case CAN_1: LPC_SC->PCONP |= 1 << 13; break;
250         case CAN_2: LPC_SC->PCONP |= 1 << 14; break;
251     }
252
253     pinmap_pinout(rd, PinMap_CAN_RD);
254     pinmap_pinout(td, PinMap_CAN_TD);
255     
256     switch ((int)obj->dev) {
257         case CAN_1: obj->index = 0; break;
258         case CAN_2: obj->index = 1; break;
259     }
260     
261     can_reset(obj);
262     obj->dev->IER = 0;             // Disable Interrupts
263     can_frequency(obj, 100000);
264
265     LPC_CANAF->AFMR = ACCF_BYPASS; // Bypass Filter
266 }
267
268 void can_free(can_t *obj) {
269     switch ((int)obj->dev) {
270         case CAN_1: LPC_SC->PCONP &= ~(1 << 13); break;
271         case CAN_2: LPC_SC->PCONP &= ~(1 << 14); break;
272     }
273 }
274
275 int can_frequency(can_t *obj, int f) {
276     int pclk = PeripheralClock;
277     
278     int btr = can_speed(pclk, (unsigned int)f, 1);
279
280     if (btr > 0) {
281         uint32_t modmask = can_disable(obj);
282         obj->dev->BTR = btr;
283         obj->dev->MOD = modmask;
284         return 1;
285     } else {
286         return 0;
287     }
288 }
289
290 int can_write(can_t *obj, CAN_Message msg, int cc) {
291     unsigned int CANStatus;
292     CANMsg m;
293
294     can_enable(obj);
295
296     m.id   = msg.id ;
297     m.dlc  = msg.len & 0xF;
298     m.rtr  = msg.type;
299     m.type = msg.format;
300     memcpy(m.data, msg.data, msg.len);
301     const unsigned int *buf = (const unsigned int *)&m;
302
303     CANStatus = obj->dev->SR;
304     if (CANStatus & 0x00000004) {
305         obj->dev->TFI1 = buf[0] & 0xC00F0000;
306         obj->dev->TID1 = buf[1];
307         obj->dev->TDA1 = buf[2];
308         obj->dev->TDB1 = buf[3];
309         if(cc) {
310             obj->dev->CMR = 0x30;
311         } else {
312             obj->dev->CMR = 0x21;
313         }
314         return 1;
315
316     } else if (CANStatus & 0x00000400) {
317         obj->dev->TFI2 = buf[0] & 0xC00F0000;
318         obj->dev->TID2 = buf[1];
319         obj->dev->TDA2 = buf[2];
320         obj->dev->TDB2 = buf[3];
321         if (cc) {
322             obj->dev->CMR = 0x50;
323         } else {
324             obj->dev->CMR = 0x41;
325         }
326         return 1;
327
328     } else if (CANStatus & 0x00040000) {
329         obj->dev->TFI3 = buf[0] & 0xC00F0000;
330         obj->dev->TID3 = buf[1];
331         obj->dev->TDA3 = buf[2];
332         obj->dev->TDB3 = buf[3];
333         if (cc) {
334             obj->dev->CMR = 0x90;
335         } else {
336             obj->dev->CMR = 0x81;
337         }
338         return 1;
339     }
340
341     return 0;
342 }
343
344 int can_read(can_t *obj, CAN_Message *msg, int handle) {
345     CANMsg x;
346     unsigned int *i = (unsigned int *)&x;
347
348     can_enable(obj);
349
350     if (obj->dev->GSR & 0x1) {
351         *i++ = obj->dev->RFS;  // Frame
352         *i++ = obj->dev->RID;  // ID
353         *i++ = obj->dev->RDA;  // Data A
354         *i++ = obj->dev->RDB;  // Data B
355         obj->dev->CMR = 0x04;  // release receive buffer
356
357         msg->id     = x.id;
358         msg->len    = x.dlc;
359         msg->format = (x.type)? CANExtended : CANStandard;
360         msg->type   = (x.rtr)?  CANRemote:    CANData;
361         memcpy(msg->data,x.data,x.dlc);
362         return 1;
363     }
364
365     return 0;
366 }
367
368 void can_reset(can_t *obj) {
369     can_disable(obj);
370     obj->dev->GSR = 0; // Reset error counter when CAN1MOD is in reset
371 }
372
373 unsigned char can_rderror(can_t *obj) {
374     return (obj->dev->GSR >> 16) & 0xFF;
375 }
376
377 unsigned char can_tderror(can_t *obj) {
378     return (obj->dev->GSR >> 24) & 0xFF;
379 }
380
381 void can_monitor(can_t *obj, int silent) {
382     uint32_t mod_mask = can_disable(obj);
383     if (silent) {
384         obj->dev->MOD |= (1 << 1);
385     } else {
386         obj->dev->MOD &= ~(1 << 1);
387     }
388     if (!(mod_mask & 1)) {
389         can_enable(obj);
390     }
391 }