mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

Committer:
mbed_official
Date:
Tue Dec 16 08:15:08 2014 +0000
Revision:
440:8a0b45cd594f
Parent:
227:7bd0639b8911
Synchronized with git revision 67fbbf0b635d0c0d93fbe433306c537c2ad206aa

Full URL: https://github.com/mbedmicro/mbed/commit/67fbbf0b635d0c0d93fbe433306c537c2ad206aa/

Targets: nrf51 - updating app_timer.c from Norid'c SDKv7.1.0

Who changed what in which revision?

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