eeprom adding

Fork of SEEED_CAN by Sophie Dexter

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers seeed_can_api.cpp Source File

seeed_can_api.cpp

00001 /* seeed_can_api.cpp
00002  * Copyright (c) 2013 Sophie Dexter
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 
00017 #include "seeed_can_api.h"
00018 
00019 /** Initialise the MCP2515 and set the bit rate
00020  */
00021 uint8_t mcpInit(mcp_can_t *obj, const uint32_t bitRate, const CANMode mode)
00022 {
00023     union {                                                             // Access CANMsg as:
00024         CANMsg x;                                                       // the organised struct
00025         uint8_t y[];                                                    // or contiguous memory array
00026     };
00027     uint8_t maskFilt[8] = { MCP_RXM0SIDH, MCP_RXM1SIDH, MCP_RXF0SIDH, MCP_RXF1SIDH, MCP_RXF2SIDH, MCP_RXF3SIDH, MCP_RXF4SIDH, MCP_RXF5SIDH };
00028     uint8_t canBufCtrl[5] = { MCP_TXB0CTRL, MCP_TXB1CTRL, MCP_TXB2CTRL, MCP_RXB0CTRL, MCP_RXB1CTRL };
00029     uint8_t canBuffer[3] = { MCP_TXB0CTRL+1, MCP_TXB1CTRL+1, MCP_TXB2CTRL+1 };
00030 
00031 #ifdef DEBUG
00032     printf("Reseting MCP2515\r\n");
00033 #endif
00034     mcpReset(obj);
00035     for (uint32_t i = 0; i < 8; i++) {                                  // Clear all CAN id masks and filters
00036         mcpWriteId(obj, maskFilt[i], NULL, NULL);
00037     }
00038     for (uint32_t i = 0; i < 5; i++) {                                  // Clear all CAN buffer control registers
00039         mcpWrite(obj, canBufCtrl[i], NULL);
00040     }
00041     for (uint32_t i = 0; i < sizeof(x); i++) y[i] = NULL;               // Initialise empty CAN message buffer
00042     for (uint32_t i = 0; i < 3; i++) {                                  // Clear all CAN TX buffers
00043         mcpWriteMultiple(obj, canBuffer[i], y, sizeof(x) );             // using empty CAN message (as an array)
00044     }
00045     // enable both receive-buffers, using filters to receive messages with std. and ext. identifiers that meet the filter criteria and enable rollover from RXB0 to RXB1 if RXB0 is full
00046     mcpBitModify(obj, MCP_RXB0CTRL, MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK );
00047     mcpBitModify(obj, MCP_RXB1CTRL, MCP_RXB_RX_MASK, MCP_RXB_RX_STDEXT);
00048 #ifdef DEBUG
00049     printf("Setting bit rate\r\n");
00050 #endif
00051     if (!mcpSetBitRate(obj, bitRate)) {                                 // set baudrate
00052         return 0;
00053     }
00054 //    return mcpSetMode(obj, MODE_NORMAL) ? 1 : 0;                        // set Normal mode and return
00055     return mcpSetMode(obj, mode) ? 1 : 0;                        // set Normal mode and return
00056 }
00057 
00058 /**  set MCP2515 operation mode
00059  *
00060  * Configuration, Normal, Sleep, Listen-only or Loopback
00061  */
00062 uint8_t mcpSetMode(mcp_can_t *obj, const uint8_t newmode)
00063 {
00064     mcpBitModify(obj, MCP_CANCTRL, MODE_MASK, newmode);
00065     for (uint32_t i = 0; i<10; i++) {
00066         if ((mcpRead(obj, MCP_CANSTAT) & MODE_MASK) == newmode) {
00067 #ifdef DEBUG
00068             printf("Successfully entered mode: %02x time: %dms\r\n", newmode, i);
00069             printf("CANCTRL:%02x CANSTAT:%02x TXB0:%02x TXB1:%02x TXB2:%02x\r\n", mcpRead(obj, MCP_CANCTRL),  mcpRead(obj, MCP_CANSTAT), mcpRead(obj, MCP_TXB0CTRL), mcpRead(obj, MCP_TXB1CTRL), mcpRead(obj, MCP_TXB2CTRL));
00070 #endif
00071             return 1;
00072         }
00073         wait_ms(1);
00074     }
00075 #ifdef DEBUG
00076     printf("Failed to enter mode: %02x\r\n", newmode);
00077     printf("CANCTRL:%02x CANSTAT:%02x TXB0:%02x TXB1:%02x TXB2:%02x\r\n", mcpRead(obj, MCP_CANCTRL),  mcpRead(obj, MCP_CANSTAT), mcpRead(obj, MCP_TXB0CTRL), mcpRead(obj, MCP_TXB1CTRL), mcpRead(obj, MCP_TXB2CTRL));
00078 #endif
00079     return 0;
00080 }
00081 
00082 /** set the CAN bus bitrate
00083  *
00084  * Calculate suitable BTR register values.
00085  * The Bit Rate Pre-scaler (BRP) can be in the range of 1-64.
00086  * According to CANopen, Bit Time can be be between 25 and 8 Time Quanta (TQU).
00087  * Bit Time = SyncSeg(1 TQU) + PropSeg(1-8 TQU) + PhaseSeg1(1-8 TQU) + PhaseSeg2(2-8 TQU).
00088  * SyncSeg is always 1TQU, PhaseSeg2 must be at least 2TQU to be longer than the processing time.
00089  * Opinions vary on when to take a sample but a point roughly 2/3 of Bit Time seems OK.
00090  * Synchronisation Jump width can be 1-4 TQU, a value of 1 seems to be normal.
00091  *
00092  * All register values are -1, e.g. PropSeg can range from 1-8 TQU, so values are 0-7 (0-63 for BRP).
00093  *
00094  * This table has the sampling points as close to 2/3 (66.7%) as possible.
00095  * The first value is PropSeg, 2nd PhaseSeg1.
00096  * PhaseSeg2 will be the same as PhaseSeg1 when btlmode bit is initialised to 0.
00097  */
00098 static const uint8_t timing_pts[18][2] = {
00099     {0x0, 0x2},    // 8,  62.5%
00100     {0x1, 0x2},    // 9,  66.7%
00101     {0x2, 0x2},    // 10, 70.0%
00102     {0x1, 0x3},    // 11, 63.6%
00103     {0x2, 0x3},    // 12, 66.7%
00104     {0x3, 0x3},    // 13, 69.2%
00105     {0x2, 0x4},    // 14, 64.3%
00106     {0x3, 0x4},    // 15, 66.7%
00107     {0x4, 0x4},    // 16, 68.75%
00108     {0x3, 0x5},    // 17, 64.7%
00109     {0x4, 0x5},    // 18, 66.7%
00110     {0x5, 0x5},    // 19, 63.2%
00111     {0x4, 0x6},    // 20, 65.0%
00112     {0x5, 0x6},    // 21, 66.7%
00113     {0x6, 0x6},    // 22, 68.2%
00114     {0x5, 0x7},    // 23, 65.2
00115     {0x6, 0x7},    // 24, 66.7%
00116     {0x7, 0x7},    // 25, 68.0%
00117 };
00118 
00119 uint8_t mcpSetBitRate(mcp_can_t *obj, const uint32_t bitRate)
00120 {
00121     union {                                                             // Access CANtiming as:
00122         CANtiming x;                                                    // the organised struct
00123         uint8_t y[];                                                    // or contiguous memory array
00124     };
00125     uint32_t bestBRP = 0;
00126     uint32_t bestTQU = 0;
00127     uint32_t bestCanRate = 0;
00128     uint32_t minBRP = (MCP_CLOCK_FREQ / (2 * MCP_MAX_TIME_QUANTA * bitRate));
00129     uint32_t maxBRP = (MCP_CLOCK_FREQ / (2 * MCP_MIN_TIME_QUANTA * bitRate));
00130 
00131 #ifdef DEBUG
00132     printf("Setting configuration mode\r\n");
00133 #endif
00134     uint8_t initialMode = mcpRead(obj, MCP_CANCTRL) & MODE_MASK;        // Store the current operation mode
00135     if(!mcpSetMode(obj, MODE_CONFIG)) {                             // Go into configuration mode
00136         return 0;
00137     }
00138 
00139     for (uint32_t i = 0; i < sizeof(x); i++) y[i] = NULL;               // Initialise CANtiming (btlmode, sjw and sam all = 0)
00140     if ((bitRate < CAN_MIN_RATE) || (bitRate > CAN_MAX_RATE)) {
00141 #ifdef DEBUG
00142         printf("FAILED!! The requested Bit Rate is too high or too low: %d\r\n", bitRate);
00143 #endif
00144         return 0;                                                       // Cannot set the requested bit rate!
00145     }
00146     minBRP = (minBRP == 0) ? MCP_MIN_PRESCALER : minBRP;
00147     maxBRP = (maxBRP > MCP_MAX_PRESCALER) ? MCP_MAX_PRESCALER : maxBRP;
00148     for (uint32_t BRP = minBRP; BRP < (maxBRP + 1); BRP++) {
00149         uint32_t timeQuanta = (MCP_CLOCK_FREQ / (2 * BRP * bitRate));
00150         if ((timeQuanta >= MCP_MIN_TIME_QUANTA) && (timeQuanta <= MCP_MAX_TIME_QUANTA)) {
00151             for (uint32_t TQU = timeQuanta; TQU <= MCP_MAX_TIME_QUANTA; TQU++) {
00152                 uint32_t thisCanRate = MCP_CLOCK_FREQ / (2 * BRP * TQU);
00153                 if ( abs((int)bitRate - (int)thisCanRate) < abs((int)bitRate - (int)bestCanRate)) {
00154                     bestCanRate = thisCanRate;
00155                     bestBRP= BRP;
00156                     bestTQU= TQU;
00157                 }
00158             }
00159         }
00160     }
00161     x.brp = (bestBRP - 1);
00162     x.prseg = (timing_pts[bestTQU - 8][0]);
00163     x.phseg1 = (timing_pts[bestTQU - 8][1]);
00164     mcpWriteMultiple(obj,  MCP_CNF3, y, sizeof(x) );                    // Copy CANtiming to the MCP2515 (as an array)
00165 #ifdef DEBUG
00166     printf("minBRP %d maxBRP %d\r\n", minBRP, maxBRP);
00167     printf("Bitrate: %d\tactualBitRate: %d\t Error: %1.2f percent.\r\n", bitRate, bestCanRate, (100-(100*(float)bitRate/(float)bestCanRate)));
00168     printf("TimeQuanta: %d\tbitRatePrescaler: %d\tSamplePoint: %2.2f percent\r\n", bestTQU, bestBRP, 100*(float)(3 + x.prseg + x.phseg1)/(float)bestTQU ) ;
00169     printf("Syncseg: 1\tPropSeg: %d\tPhaseSeg1: %d\tPhaseSeg2: %d\r\n", (x.prseg+1), (x.phseg1+1), (x.phseg1+1));
00170     printf("Setting normal mode\r\n");
00171 #endif
00172     return (mcpSetMode(obj, initialMode)) ? 1 : 0;                      // desired bit rate set enter normal mode and return
00173 }
00174 
00175 /** write a CAN id to a mask, filter or transmit buffer
00176  */
00177 void mcpWriteId(mcp_can_t *obj, const uint8_t mcp_addr, const uint8_t ext, const uint32_t id )
00178 {
00179     union {                                                             // Access CANid as:
00180         CANid x;                                                        // the organised struct
00181         uint8_t y[];                                                    // or contiguous memory array
00182     };
00183 
00184     for (uint32_t i = 0; i < sizeof(x); i++) y[i] = NULL;               // Initialise CANid structure
00185     x.ide = ext;                                                        // Extended Identifier Flag
00186     if (x.ide == CANExtended) {
00187         x.sid10_3  = (uint8_t) (id >> 21);                              // SID10..3
00188         x.sid2_0   = (uint8_t) (id >> 18) & 0x07;                       // SID2..0
00189         x.eid17_16 = (uint8_t) (id >> 16) & 0x03;                       // EID17..16
00190         x.eid15_8  = (uint8_t) (id >> 8);                               // EID15..8
00191         x.eid7_0   = (uint8_t) id;                                      // EID7..0
00192     } else {
00193         x.sid10_3  = (uint8_t) (id >> 3);                               // SID10..3
00194         x.sid2_0   = (uint8_t) (id & 0x07);                             // SID2..0
00195     }
00196 #ifdef DEBUG
00197     printf("sizeof CanIdStruct: %d bytes\r\n", sizeof(x));
00198     printf("sid10_3: %x\r\n", x.sid10_3);
00199     printf("eid17_16: %x\r\n", x.eid17_16);
00200     printf("ide: %x\r\n", x.ide);
00201     printf("srtr: %x\r\n", x.srtr);
00202     printf("sid2_0: %x\r\n", x.sid2_0);
00203     printf("eid15_8: %x\r\n", x.eid15_8);
00204     printf("eid7_0: %x\r\n", x.eid7_0);
00205 #endif
00206     mcpWriteMultiple(obj,  mcp_addr, y, sizeof(x) );                     // Copy CANid to the MCP2515 (as an array)
00207 }
00208 
00209 /**  write a CAN message to the MCP2515
00210  */
00211 uint8_t mcpCanWrite(mcp_can_t *obj, CAN_Message msg)
00212 {
00213     union {                                                             // Access CANMsg as:
00214         CANMsg x;                                                       // the organised struct
00215         uint8_t y[];                                                    // or contiguous memory array
00216     };
00217     uint8_t bufferCommand[] = {MCP_WRITE_TX0, MCP_WRITE_TX1, MCP_WRITE_TX2};
00218     uint8_t rtsCommand[] = {MCP_RTS_TX0, MCP_RTS_TX1, MCP_RTS_TX2};
00219     uint8_t status = mcpStatus(obj);
00220     uint32_t num = 0;
00221 // Check if there is a free message buffer
00222     if (!(status & MCP_STAT_TX0REQ)) {                                  // TX Message Buffer 0 free?
00223         num = 0;
00224     } else if (!(status & MCP_STAT_TX1REQ)) {                           // TX Message Buffer 1 free?
00225         num = 1;
00226     } else if (!(status & MCP_STAT_TX2REQ)) {                           // TX Message Buffer 2 free?
00227         num = 2;
00228     } else {
00229         return 0;                                                       // No free transmit buffers in the MCP2515 CAN controller chip
00230     }
00231 // populate CANMsg structure
00232     for (uint32_t i = 0; i < sizeof(x); i++) y[i] = NULL;               // Initialise CANMsg structure
00233     x.id.ide = msg.format;                                              // Extended Identifier Flag
00234     if (x.id.ide == CANExtended) {
00235         x.id.sid10_3  = (uint8_t) (msg.id >> 21);                       // SID10..3
00236         x.id.sid2_0   = (uint8_t) (msg.id >> 18) & 0x07;                // SID2..0
00237         x.id.eid17_16 = (uint8_t) (msg.id >> 16) & 0x03;                // EID17..16
00238         x.id.eid15_8  = (uint8_t) (msg.id >> 8);                        // EID15..8
00239         x.id.eid7_0   = (uint8_t) msg.id;                               // EID7..0
00240     } else {
00241         x.id.sid10_3  = (uint8_t) (msg.id >> 3);                        // SID10..3
00242         x.id.sid2_0   = (uint8_t) (msg.id & 0x07);                      // SID2..0
00243     }
00244     x.dlc = msg.len & 0x0f;                                             // Number of bytes in can message
00245     x.ertr = msg.type;                                                  // Data or remote message
00246     memcpy(x.data,msg.data,x.dlc);                                      // Get the Data bytes
00247 // write CANmsg to the specified TX buffer 'num'
00248     mcpWriteBuffer(obj, bufferCommand[num], y, sizeof(x));              // Write the message ,CANMsg, to the MCP2515's Tx buffer 'num' (as an array)
00249     mcpBufferRTS(obj, rtsCommand[num]);
00250     return 1;                                                           // Indicate that message has been transmitted
00251 }
00252 
00253 /** read a CAN message from the MCP2515
00254  */
00255 uint8_t mcpCanRead(mcp_can_t *obj, CAN_Message *msg)
00256 {
00257     union {                                                             // Access CANMsg as:
00258         CANMsg x;                                                       // the organised struct
00259         uint8_t y[];                                                    // or contiguous memory array
00260     };
00261     uint8_t bufferCommand[] = {MCP_READ_RX0, MCP_READ_RX1};
00262     uint8_t status = mcpReceiveStatus(obj);
00263     bool num = 0;
00264 // Check if there is a message the buffers
00265     if (status & MCP_RXSTAT_RXB0) {                                     // Msg in Buffer 0?
00266         num = 0;
00267     } else if (status & MCP_RXSTAT_RXB1) {                              // Msg in Buffer 1?
00268         num = 1;
00269     } else {
00270         return 0;                                                       // No messages waiting
00271     }
00272     mcpReadBuffer(obj, bufferCommand[0], y, sizeof(x));                 // Read the message into CANMsg (as an array)
00273     mcpBitModify(obj, MCP_CANINTF, (!num ? MCP_RX0IF : MCP_RX1IF), 0);  // Free the message buffer
00274 #ifdef DEBUG
00275     printf("sizeof CanMsgStruct: %d bytes\r\n", sizeof(x));
00276     printf("sizeof CanMsgArray: %d bytes\r\n", sizeof(y));
00277     printf("sid10_3: %x\r\n", x.id.sid10_3);
00278     printf("eid17_16: %x\r\n", x.id.eid17_16);
00279     printf("ide: %x\r\n", x.id.ide);
00280     printf("srtr: %x\r\n", x.id.srtr);
00281     printf("sid2_0: %x\r\n", x.id.sid2_0);
00282     printf("eid15_8: %x\r\n", x.id.eid15_8);
00283     printf("eid7_0: %x\r\n", x.id.eid7_0);
00284     printf("dlc: %x\r\n", x.dlc);
00285     printf("ertr: %x\r\n", x.ertr);
00286     printf("data: ");
00287     for (char i=0; i<8; i++)
00288         printf("%02x,", x.data[i]);
00289     printf("\r\n");
00290 #endif
00291     msg->format = (status & MCP_RXSTAT_IDE) ? CANExtended : CANStandard;// Extended CAN id Flag
00292     if (msg->format == CANExtended) {                                   // Assemble the Extended CAN id
00293         msg->id = (x.id.sid10_3 << 21)  |
00294                   (x.id.sid2_0 << 18)   |
00295                   (x.id.eid17_16 << 16) |
00296                   (x.id.eid15_8 << 8)   |
00297                   (x.id.eid7_0);
00298     } else {                                                            // Assemble the Standard CAN id
00299         msg->id = (x.id.sid10_3 << 3)   |
00300                   (x.id.sid2_0);
00301     }
00302     msg->len    = x.dlc;                                                // Number of bytes in CAN message
00303     msg->type = (status & MCP_RXSTAT_RTR) ? CANRemote : CANData;        // Determine if a Remote or Data message type
00304     memcpy(msg->data,x.data,x.dlc);                                     // Get the Data bytes
00305     return 1;                                                           // Indicate that message has been retrieved
00306 }
00307 
00308 /** initialise an Acceptance Mask
00309  */
00310 uint8_t mcpInitMask(mcp_can_t *obj, uint8_t num, uint32_t ulData, bool ext)
00311 {
00312     uint8_t mask[2] = { MCP_RXM0SIDH, MCP_RXM1SIDH };
00313 
00314     if (num > 1) {
00315 #ifdef DEBUG
00316         printf("Trying to set an invalid Mask number: %d\r\n", num);
00317 #endif
00318         return 0;
00319     }
00320 #ifdef DEBUG
00321     printf("Begin to set Mask!!\r\n");
00322 #endif
00323     uint8_t initialMode = mcpRead(obj, MCP_CANCTRL) & MODE_MASK;        // Store the current operation mode
00324     if(!mcpSetMode(obj, MODE_CONFIG)) {
00325         return 0;
00326     }
00327     mcpWriteId(obj, mask[num], ext, ulData);
00328     if(!mcpSetMode(obj, initialMode)) {
00329         return 0;
00330     }
00331 #ifdef DEBUG
00332     printf("Successfully set Mask number: %d\r\n", num);
00333 #endif
00334     return 1;
00335 }
00336 
00337 /** initialise an Acceptance Filter
00338  */
00339 uint8_t mcpInitFilter(mcp_can_t *obj, uint8_t num, uint32_t ulData, bool ext)
00340 {
00341     uint8_t filter[6] = { MCP_RXF0SIDH, MCP_RXF1SIDH, MCP_RXF2SIDH, MCP_RXF3SIDH, MCP_RXF4SIDH, MCP_RXF5SIDH };
00342 
00343     if (num > 5) {
00344 #ifdef DEBUG
00345         printf("Trying to set an invalid Filter number: %d\r\n", num);
00346 #endif
00347         return 0;
00348     }
00349 #ifdef DEBUG
00350     printf("Begin to set Filter!!\r\n");
00351 #endif
00352     uint8_t initialMode = mcpRead(obj, MCP_CANCTRL) & MODE_MASK;        // Store the current operation mode
00353     if(!mcpSetMode(obj, MODE_CONFIG)) {
00354         return 0;
00355     }
00356     mcpWriteId(obj, filter[num], ext, ulData);
00357     if(!mcpSetMode(obj, initialMode)) {
00358         return 0;
00359     }
00360 #ifdef DEBUG
00361     printf("Successfully set Filter: %d\r\n", num);
00362 #endif
00363     return 1;
00364 }
00365 
00366 /*  Report on the specified errors and warnings
00367  */
00368 uint8_t mcpErrorType(mcp_can_t *obj, const CANFlags type)
00369 {
00370     uint8_t which[] = { MCP_EFLG_ALLMASK,
00371                         MCP_EFLG_ERRORMASK,
00372                         MCP_EFLG_WARNMASK,
00373                         MCP_EFLG_RX1OVR,
00374                         MCP_EFLG_RX0OVR,
00375                         MCP_EFLG_TXBO,
00376                         MCP_EFLG_TXEP,
00377                         MCP_EFLG_RXEP,
00378                         MCP_EFLG_TXWAR,
00379                         MCP_EFLG_RXWAR,
00380                         MCP_EFLG_EWARN
00381                       };
00382 
00383     return (mcpRead(obj, MCP_EFLG) & which[type]) ? 1 : 0;
00384 }
00385 
00386 /*  Return contents of the error and warning flags register
00387  */
00388 uint8_t mcpErrorFlags(mcp_can_t *obj)
00389 {
00390     return (mcpRead(obj, MCP_EFLG));
00391 }
00392 
00393 /*  Number of message reception errors
00394  */
00395 uint8_t mcpReceptionErrorCount(mcp_can_t *obj)
00396 {
00397     return (mcpRead(obj, MCP_REC));
00398 }
00399 
00400 /*  Number of message transmission errors
00401  */
00402 uint8_t mcpTransmissionErrorCount(mcp_can_t *obj)
00403 {
00404     return (mcpRead(obj, MCP_TEC));
00405 }
00406 
00407 /* Select between monitor (silent = 1) and normal (silent = 0) modes
00408  */
00409 void mcpMonitor(mcp_can_t *obj, const bool silent)
00410 {
00411     silent ? mcpSetMode(obj, MODE_LISTENONLY) : mcpSetMode(obj, MODE_NORMAL);
00412 }
00413 
00414 /* Change CAN operation to the specified mode
00415  */
00416 uint8_t mcpMode(mcp_can_t *obj, const CANMode mode)
00417 {
00418     uint8_t which[] = { MODE_NORMAL,
00419                         MODE_SLEEP,
00420                         MODE_LOOPBACK,
00421                         MODE_LISTENONLY,
00422                         MODE_CONFIG,
00423                         MODE_CONFIG
00424                       };
00425 
00426     if (mode == _M_RESET) {
00427         mcpReset(obj);
00428     }
00429     if (mcpSetMode(obj, which[mode])) {
00430         return 1;
00431     }
00432     return 0;
00433 }
00434 
00435 /*  Configure interrupt sources
00436  */
00437 void mcpSetInterrupts(mcp_can_t *obj, const CANIrqs irqSet)
00438 {
00439     uint8_t which[] = { MCP_NO_INTS,
00440                         MCP_ALL_INTS,
00441                         MCP_RX_INTS,
00442                         MCP_TX_INTS,
00443                         MCP_RX0IF,
00444                         MCP_RX1IF,
00445                         MCP_TX0IF,
00446                         MCP_TX1IF,
00447                         MCP_TX2IF,
00448                         MCP_ERRIF,
00449                         MCP_WAKIF,
00450                         MCP_MERRF
00451                       };
00452 
00453     mcpWrite(obj, MCP_CANINTE, which[irqSet]);
00454 }
00455 
00456 /*  Report on the specified interrupt causes
00457  */
00458 uint8_t mcpInterruptType(mcp_can_t *obj, const CANIrqs irqFlag)
00459 {
00460     uint8_t which[] = { MCP_NO_INTS,
00461                         MCP_ALL_INTS,
00462                         MCP_RX_INTS,
00463                         MCP_TX_INTS,
00464                         MCP_RX0IF,
00465                         MCP_RX1IF,
00466                         MCP_TX0IF,
00467                         MCP_TX1IF,
00468                         MCP_TX2IF,
00469                         MCP_ERRIF,
00470                         MCP_WAKIF,
00471                         MCP_MERRF
00472                       };
00473 
00474     return (mcpRead(obj, MCP_EFLG) & which[irqFlag]) ? 1 : 0;
00475 }
00476 
00477 /*  Return contents of the interrupt flags register
00478  */
00479 uint8_t mcpInterruptFlags(mcp_can_t *obj)
00480 {
00481     return (mcpRead(obj, MCP_EFLG));
00482 }