Tim Barry / mbed_blinky_offset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers can_api.c Source File

can_api.c

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "can_api.h"
00017 
00018 #if DEVICE_CAN
00019 
00020 #include "cmsis.h"
00021 
00022 #include "pinmap.h"
00023 #include "error.h"
00024 
00025 #include <math.h>
00026 #include <string.h>
00027 
00028 /* Acceptance filter mode in AFMR register */
00029 #define ACCF_OFF                0x01
00030 #define ACCF_BYPASS             0x02
00031 #define ACCF_ON                 0x00
00032 #define ACCF_FULLCAN            0x04
00033 
00034 /* There are several bit timing calculators on the internet.
00035 http://www.port.de/engl/canprod/sv_req_form.html
00036 http://www.kvaser.com/can/index.htm
00037 */
00038 
00039 static const PinMap PinMap_CAN_RD[] = {
00040     {P0_0 , CAN_1, 1},
00041     {P0_4 , CAN_2, 2},
00042     {P0_21, CAN_1, 3},
00043     {P2_7 , CAN_2, 1},
00044     {NC   , NC   , 0}
00045 };
00046 
00047 static const PinMap PinMap_CAN_TD[] = {
00048     {P0_1 , CAN_1, 1},
00049     {P0_5 , CAN_2, 2},
00050     {P0_22, CAN_1, 3},
00051     {P2_8 , CAN_2, 1},
00052     {NC   , NC   , 0}
00053 };
00054 
00055 // Type definition to hold a CAN message
00056 struct CANMsg {
00057     unsigned int  reserved1 : 16;
00058     unsigned int  dlc       :  4; // Bits 16..19: DLC - Data Length Counter
00059     unsigned int  reserved0 : 10;
00060     unsigned int  rtr       :  1; // Bit 30: Set if this is a RTR message
00061     unsigned int  type      :  1; // Bit 31: Set if this is a 29-bit ID message
00062     unsigned int  id;             // CAN Message ID (11-bit or 29-bit)
00063     unsigned char data[8];        // CAN Message Data Bytes 0-7
00064 };
00065 typedef struct CANMsg CANMsg;
00066 
00067 static uint32_t can_disable(can_t *obj) {
00068     uint32_t sm = obj->dev->MOD;
00069     obj->dev->MOD |= 1;
00070     return sm;
00071 }
00072 
00073 static inline void can_enable(can_t *obj) {
00074     if (obj->dev->MOD & 1) {
00075         obj->dev->MOD &= ~(1);
00076     }
00077 }
00078 
00079 static int can_pclk(can_t *obj) {
00080     int value = 0;
00081     switch ((int)obj->dev) {
00082         case CAN_1: value = (LPC_SC->PCLKSEL0 & (0x3 << 26)) >> 26; break;
00083         case CAN_2: value = (LPC_SC->PCLKSEL0 & (0x3 << 28)) >> 28; break;
00084     }
00085 
00086     switch (value) {
00087         case 1: return 1;
00088         case 2: return 2;
00089         case 3: return 6;
00090         default: return 4;
00091     }
00092 }
00093 
00094 // This table has the sampling points as close to 75% as possible. The first
00095 // value is TSEG1, the second TSEG2.
00096 static const int timing_pts[23][2] = {
00097     {0x0, 0x0},      // 2,  50%
00098     {0x1, 0x0},      // 3,  67%
00099     {0x2, 0x0},      // 4,  75%
00100     {0x3, 0x0},      // 5,  80%
00101     {0x3, 0x1},      // 6,  67%
00102     {0x4, 0x1},      // 7,  71%
00103     {0x5, 0x1},      // 8,  75%
00104     {0x6, 0x1},      // 9,  78%
00105     {0x6, 0x2},      // 10, 70%
00106     {0x7, 0x2},      // 11, 73%
00107     {0x8, 0x2},      // 12, 75%
00108     {0x9, 0x2},      // 13, 77%
00109     {0x9, 0x3},      // 14, 71%
00110     {0xA, 0x3},      // 15, 73%
00111     {0xB, 0x3},      // 16, 75%
00112     {0xC, 0x3},      // 17, 76%
00113     {0xD, 0x3},      // 18, 78%
00114     {0xD, 0x4},      // 19, 74%
00115     {0xE, 0x4},      // 20, 75%
00116     {0xF, 0x4},      // 21, 76%
00117     {0xF, 0x5},      // 22, 73%
00118     {0xF, 0x6},      // 23, 70%
00119     {0xF, 0x7},      // 24, 67%
00120 };
00121 
00122 static unsigned int can_speed(unsigned int sclk, unsigned int pclk, unsigned int cclk, unsigned char psjw) {
00123     uint32_t    btr;
00124     uint16_t    brp = 0;
00125     uint32_t    calcbit;
00126     uint32_t    bitwidth;
00127     int         hit = 0;
00128     int         bits;
00129 
00130     bitwidth = sclk / (pclk * cclk);
00131 
00132     brp = bitwidth / 0x18;
00133     while ((!hit) && (brp < bitwidth / 4)) {
00134         brp++;
00135         for (bits = 22; bits > 0; bits--) {
00136             calcbit = (bits + 3) * (brp + 1);
00137             if (calcbit == bitwidth) {
00138                 hit = 1;
00139                 break;
00140             }
00141         }
00142     }
00143 
00144     if (hit) {
00145         btr = ((timing_pts[bits][1] << 20) & 0x00700000)
00146             | ((timing_pts[bits][0] << 16) & 0x000F0000)
00147             | ((psjw                << 14) & 0x0000C000)
00148             | ((brp                 <<  0) & 0x000003FF);
00149     } else {
00150         btr = 0xFFFFFFFF;
00151     }
00152 
00153     return btr;
00154 
00155 }
00156 
00157 void can_init(can_t *obj, PinName rd, PinName td) {
00158     CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
00159     CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
00160     obj->dev = (LPC_CAN_TypeDef *)pinmap_merge(can_rd, can_td);
00161     if ((int)obj->dev == NC) {
00162         error("CAN pin mapping failed");
00163     }
00164 
00165     switch ((int)obj->dev) {
00166         case CAN_1: LPC_SC->PCONP |= 1 << 13; break;
00167         case CAN_2: LPC_SC->PCONP |= 1 << 14; break;
00168     }
00169 
00170     pinmap_pinout(rd, PinMap_CAN_RD);
00171     pinmap_pinout(td, PinMap_CAN_TD);
00172 
00173     can_reset(obj);
00174     obj->dev->IER = 0;             // Disable Interrupts
00175     can_frequency(obj, 100000);
00176 
00177     LPC_CANAF->AFMR = ACCF_BYPASS; // Bypass Filter
00178 }
00179 
00180 void can_free(can_t *obj) {
00181     switch ((int)obj->dev) {
00182         case CAN_1: LPC_SC->PCONP &= ~(1 << 13); break;
00183         case CAN_2: LPC_SC->PCONP &= ~(1 << 14); break;
00184     }
00185 }
00186 
00187 int can_frequency(can_t *obj, int f) {
00188     int pclk = can_pclk(obj);
00189     int btr = can_speed(SystemCoreClock , pclk, (unsigned int)f, 1);
00190 
00191     if (btr > 0) {
00192         uint32_t modmask = can_disable(obj);
00193         obj->dev->BTR = btr;
00194         obj->dev->MOD = modmask;
00195         return 1;
00196     } else {
00197         return 0;
00198     }
00199 }
00200 
00201 int can_write(can_t *obj, CAN_Message msg, int cc) {
00202     unsigned int CANStatus;
00203     CANMsg m;
00204 
00205     can_enable(obj);
00206 
00207     m.id   = msg.id ;
00208     m.dlc  = msg.len & 0xF;
00209     m.rtr  = msg.type;
00210     m.type = msg.format;
00211     memcpy(m.data, msg.data, msg.len);
00212     const unsigned int *buf = (const unsigned int *)&m;
00213 
00214     CANStatus = obj->dev->SR;
00215     if (CANStatus & 0x00000004) {
00216         obj->dev->TFI1 = buf[0] & 0xC00F0000;
00217         obj->dev->TID1 = buf[1];
00218         obj->dev->TDA1 = buf[2];
00219         obj->dev->TDB1 = buf[3];
00220         if(cc) {
00221             obj->dev->CMR = 0x30;
00222         } else {
00223             obj->dev->CMR = 0x21;
00224         }
00225         return 1;
00226 
00227     } else if (CANStatus & 0x00000400) {
00228         obj->dev->TFI2 = buf[0] & 0xC00F0000;
00229         obj->dev->TID2 = buf[1];
00230         obj->dev->TDA2 = buf[2];
00231         obj->dev->TDB2 = buf[3];
00232         if (cc) {
00233             obj->dev->CMR = 0x50;
00234         } else {
00235             obj->dev->CMR = 0x41;
00236         }
00237         return 1;
00238 
00239     } else if (CANStatus & 0x00040000) {
00240         obj->dev->TFI3 = buf[0] & 0xC00F0000;
00241         obj->dev->TID3 = buf[1];
00242         obj->dev->TDA3 = buf[2];
00243         obj->dev->TDB3 = buf[3];
00244         if (cc) {
00245             obj->dev->CMR = 0x90;
00246         } else {
00247             obj->dev->CMR = 0x81;
00248         }
00249         return 1;
00250     }
00251 
00252     return 0;
00253 }
00254 
00255 int can_read(can_t *obj, CAN_Message *msg) {
00256     CANMsg x;
00257     unsigned int *i = (unsigned int *)&x;
00258 
00259     can_enable(obj);
00260 
00261     if (obj->dev->GSR & 0x1) {
00262         *i++ = obj->dev->RFS;  // Frame
00263         *i++ = obj->dev->RID;  // ID
00264         *i++ = obj->dev->RDA;  // Data A
00265         *i++ = obj->dev->RDB;  // Data B
00266         obj->dev->CMR = 0x04;  // release receive buffer
00267 
00268         msg->id     = x.id;
00269         msg->len    = x.dlc;
00270         msg->format = (x.type)? CANExtended : CANStandard;
00271         msg->type   = (x.rtr)?  CANRemote:    CANData;
00272         memcpy(msg->data,x.data,x.dlc);
00273         return 1;
00274     }
00275 
00276     return 0;
00277 }
00278 
00279 void can_reset(can_t *obj) {
00280     can_disable(obj);
00281     obj->dev->GSR = 0; // Reset error counter when CAN1MOD is in reset
00282 }
00283 
00284 unsigned char can_rderror(can_t *obj) {
00285     return (obj->dev->GSR >> 16) & 0xFF;
00286 }
00287 
00288 unsigned char can_tderror(can_t *obj) {
00289     return (obj->dev->GSR >> 24) & 0xFF;
00290 }
00291 
00292 void can_monitor(can_t *obj, int silent) {
00293     uint32_t mod_mask = can_disable(obj);
00294     if (silent) {
00295         obj->dev->MOD |= (1 << 1);
00296     } else {
00297         obj->dev->MOD &= ~(1 << 1);
00298     }
00299     if (!(mod_mask & 1)) {
00300         can_enable(obj);
00301     }
00302 }
00303 
00304 #endif
00305