atcan.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2005-2009 proconX Pty Ltd. All rights reserved.
00003  *
00004  * This driver has been closely modeled after the existing Nut/OS SJA1000
00005  * driver and the buffer management and some code snippets have been borrowed
00006  * from sja1000.c.
00007  *
00008  * Portions Copyright (C) 2004 by Ole Reinhardt <ole.reinhardt@kernelconcepts.de>,
00009  * Kernelconcepts http://www.kernelconcepts.de
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  *
00015  * 1. Redistributions of source code must retain the above copyright
00016  *    notice, this list of conditions and the following disclaimer.
00017  * 2. Redistributions in binary form must reproduce the above copyright
00018  *    notice, this list of conditions and the following disclaimer in the
00019  *    documentation and/or other materials provided with the distribution.
00020  * 3. Neither the name of the copyright holders nor the names of
00021  *    contributors may be used to endorse or promote products derived
00022  *    from this software without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00025  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00026  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00027  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00028  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00029  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00030  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00031  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00032  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00033  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00034  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00035  * SUCH DAMAGE.
00036  *
00037  * For additional information see http://www.ethernut.de/
00038  *
00039  */
00040 
00041 /*
00042  * $Log$
00043  * Revision 1.8  2009/02/04 23:40:52  hwmaier
00044  * Added support for a receive buffer size configuration entry ATCAN_RX_BUF_SIZE.
00045  *
00046  * Revision 1.7  2008/08/11 06:59:14  haraldkipp
00047  * BSD types replaced by stdint types (feature request #1282721).
00048  *
00049  * Revision 1.6  2007/11/16 03:17:26  hwmaier
00050  * Updated bit timing values for a sample point of 87.5% and a SJW of 2. Required for maximum bus length as per CiA DS-102.
00051  *
00052  * Revision 1.5  2007/09/08 03:00:52  hwmaier
00053  * Optional time-out for receiving added, more robust handling of error interrupts.
00054  *
00055  * Revision 1.3  2007/05/24 00:55:43  henrik
00056  * no message
00057  *
00058  * Revision 1.2  2007/03/11 08:59:47  henrik
00059  * no message
00060  *
00061  * Revision 1.1  2006/11/17 01:44:00  henrik
00062  * no message
00063  *
00064  * Revision 1.4  2006/03/01 02:15:29  hwmaier
00065  * Error check for NutHeapAlloc added
00066  *
00067  * Revision 1.3  2005/12/04 10:53:59  hwmaier
00068  * no message
00069  *
00070  * Revision 1.2  2005/10/07 22:02:33  hwmaier
00071  * no message
00072  *
00073  * Revision 1.1  2005/10/04 06:00:59  hwmaier
00074  * Added AT90CAN128 CAN driver
00075  *
00076  */
00077 
00082 
00083 #ifdef __GNUC__
00084 
00085 #include <cfg/arch/avr.h>
00086 #include <string.h>
00087 #include <sys/event.h>
00088 #include <sys/heap.h>
00089 #include <sys/atom.h>
00090 #include <dev/irqreg.h>
00091 #include <dev/can_dev.h>
00092 #include <avr/io.h>
00093 #include <dev/atcan.h>
00094 
00095 
00096 /*****************************************************************************
00097  * Definitions
00098  *****************************************************************************/
00099 
00100 #define RX_MOB 8
00101 
00102 #ifndef ATCAN_RX_BUF_SIZE
00103 #  define ATCAN_RX_BUF_SIZE 64
00104 #endif
00105 
00106 
00107 /*****************************************************************************
00108  * CAN baud rate table
00109  *
00110  * Tried to match as closely as possible a sampling point of 87.5 %
00111  * which is recommended by CiA for CANOpen. DeviceNet specifies a
00112  * sampling point > 80%. SQW is 2.
00113  *****************************************************************************/
00114 
00115 //
00116 // 8.00 MHz
00117 //
00118 #if NUT_CPU_FREQ == 8000000
00119 // 100 kbit/s 86.67% 15 quanta (BRP=7 Tprs=8 Tph1=4 Tph2=2 Tsjw=2)
00120 #define CAN_BT1_100K 0x08
00121 #define CAN_BT2_100K 0x0C
00122 #define CAN_BT3_100K 0x37
00123 // 125 kbit/s 87.50% 16 quanta (BRP=5 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00124 #define CAN_BT1_125K 0x0E
00125 #define CAN_BT2_125K 0x04
00126 #define CAN_BT3_125K 0x13
00127 // 250 kbit/s 87.50% 16 quanta (BRP=2 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00128 #define CAN_BT1_250K 0x06
00129 #define CAN_BT2_250K 0x04
00130 #define CAN_BT3_250K 0x13
00131 // 500 kbit/s 83.33% 12 quanta (BRP=1 Tprs=7 Tph1=2 Tph2=2 Tsjw=2)
00132 #define CAN_BT1_500K 0x02
00133 #define CAN_BT2_500K 0x0C
00134 #define CAN_BT3_500K 0x37
00135 // 1000 kbit/s 83.33% 12 quanta (BRP=0 Tprs=7 Tph1=2 Tph2=2 Tsjw=2)
00136 #define CAN_BT1_1M 0x00
00137 #define CAN_BT2_1M 0x04
00138 #define CAN_BT3_1M 0x12
00139 
00140 //
00141 // 12.00 MHz
00142 //
00143 #elif NUT_CPU_FREQ == 12000000
00144 // 10 kbit/s 85.00% 20 quanta (BRP=59 Tprs=8 Tph1=8 Tph2=3 Tsjw=2)
00145 #define CAN_BT1_10K 0x76
00146 #define CAN_BT2_10K 0x2E
00147 #define CAN_BT3_10K 0x2E
00148 // 20 kbit/s 86.67% 15 quanta (BRP=39 Tprs=8 Tph1=4 Tph2=2 Tsjw=2)
00149 #define CAN_BT1_20K 0x4E
00150 #define CAN_BT2_20K 0x2E
00151 #define CAN_BT3_20K 0x16
00152 // 50 kbit/s 87.50% 16 quanta (BRP=14 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00153 #define CAN_BT1_50K 0x1C
00154 #define CAN_BT2_50K 0x2E
00155 #define CAN_BT3_50K 0x18
00156 // 100 kbit/s 86.67% 15 quanta (BRP=7 Tprs=8 Tph1=4 Tph2=2 Tsjw=2)
00157 #define CAN_BT1_100K 0x0E
00158 #define CAN_BT2_100K 0x2E
00159 #define CAN_BT3_100K 0x16
00160 // 125 kbit/s 87.50% 16 quanta (BRP=5 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00161 #define CAN_BT1_125K 0x0A
00162 #define CAN_BT2_125K 0x2E
00163 #define CAN_BT3_125K 0x18
00164 // 250 kbit/s 87.50% 16 quanta (BRP=2 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00165 #define CAN_BT1_250K 0x04
00166 #define CAN_BT2_250K 0x2E
00167 #define CAN_BT3_250K 0x18
00168 // 500 kbit/s 83.33% 12 quanta (BRP=1 Tprs=7 Tph1=2 Tph2=2 Tsjw=2)
00169 #define CAN_BT1_500K 0x02
00170 #define CAN_BT2_500K 0x2C
00171 #define CAN_BT3_500K 0x12
00172 // 800 kbit/s 86.67% 15 quanta (BRP=0 Tprs=8 Tph1=4 Tph2=2 Tsjw=2)
00173 #define CAN_BT1_800K 0x00
00174 #define CAN_BT2_800K 0x2E
00175 #define CAN_BT3_800K 0x16
00176 // 1000 kbit/s 83.33% 12 quanta (BRP=0 Tprs=7 Tph1=2 Tph2=2 Tsjw=2)
00177 #define CAN_BT1_1M 0x00
00178 #define CAN_BT2_1M 0x2C
00179 #define CAN_BT3_1M 0x12
00180 
00181 //
00182 // 16.00 MHz
00183 //
00184 #elif NUT_CPU_FREQ == 16000000
00185 // 10 kbit/s 68.00% 25 quanta (BRP=63 Tprs=8 Tph1=8 Tph2=8 Tsjw=2)
00186 #define CAN_BT1_10K 0x7E
00187 #define CAN_BT2_10K 0x2E
00188 #define CAN_BT3_10K 0x7E
00189 // 20 kbit/s 87.50% 16 quanta (BRP=49 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00190 #define CAN_BT1_20K 0x62
00191 #define CAN_BT2_20K 0x2E
00192 #define CAN_BT3_20K 0x18
00193 // 50 kbit/s 87.50% 16 quanta (BRP=19 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00194 #define CAN_BT1_50K 0x26
00195 #define CAN_BT2_50K 0x2E
00196 #define CAN_BT3_50K 0x18
00197 // 100 kbit/s 87.50% 16 quanta (BRP=9 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00198 #define CAN_BT1_100K 0x12
00199 #define CAN_BT2_100K 0x2E
00200 #define CAN_BT3_100K 0x18
00201 // 125 kbit/s 87.50% 16 quanta (BRP=7 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00202 #define CAN_BT1_125K 0x0E
00203 #define CAN_BT2_125K 0x2E
00204 #define CAN_BT3_125K 0x18
00205 // 250 kbit/s 87.50% 16 quanta (BRP=3 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00206 #define CAN_BT1_250K 0x06
00207 #define CAN_BT2_250K 0x2E
00208 #define CAN_BT3_250K 0x18
00209 // 500 kbit/s 87.50% 16 quanta (BRP=1 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00210 #define CAN_BT1_500K 0x02
00211 #define CAN_BT2_500K 0x2E
00212 #define CAN_BT3_500K 0x18
00213 // 800 kbit/s 85.00% 20 quanta (BRP=0 Tprs=8 Tph1=8 Tph2=3 Tsjw=2)
00214 #define CAN_BT1_800K 0x00
00215 #define CAN_BT2_800K 0x2E
00216 #define CAN_BT3_800K 0x2E
00217 // 1000 kbit/s 87.50% 16 quanta (BRP=0 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
00218 #define CAN_BT1_1M 0x00
00219 #define CAN_BT2_1M 0x2E
00220 #define CAN_BT3_1M 0x18
00221 #else
00222 #  error Frequency not supported or not set to a Fixed MCU clock!
00223 #endif
00224 
00225 
00226 /*****************************************************************************
00227  * Buffer management
00228  *
00229  * Note: Buffer concept borrowed from existing Nut/OS sja1000.c driver
00230  *****************************************************************************/
00231 
00232 struct _CANBuffer {
00233     CANFRAME *dataptr;    // the physical memory address where the buffer is stored
00234     uint8_t size;         // the allocated size of the buffer
00235     uint8_t datalength;   // the length of the data currently in the buffer
00236     uint8_t dataindex;    // the index into the buffer where the data starts
00237 };
00238 
00239 typedef struct _CANBuffer CANBuffer;
00240 
00241 
00242 /*****************************************************************************
00243  * Driver data
00244  *****************************************************************************/
00245 
00246 static CANBuffer canRxBuf;
00247 CANINFO dcb_atcan;
00248 IFCAN ifc_atcan;
00249 NUTDEVICE devAtCan;
00250 
00251 
00252 /*****************************************************************************
00253  * Low level functions
00254  *****************************************************************************/
00255 
00265 int8_t AtCanGetBusState(void)
00266 {
00267    if (CANGSTA & _BV(BOFF))
00268        return CAN_BUS_OFF;
00269    if (CANGSTA & _BV(ERRP))
00270        return CAN_PASSIVE;
00271    return CAN_SUCCESS;
00272 }
00273 
00274 
00280 int8_t AtCanGetFreeMob(void)
00281 {
00282    int8_t mob;
00283    uint8_t ctrlReg;
00284 
00285    for (mob = 0; mob < ATCAN_MAX_MOB; mob++)
00286    {
00287       CANPAGE = mob << 4;
00288       ctrlReg = CANCDMOB & (_BV(CONMOB1) | _BV(CONMOB0));
00289       if (ctrlReg == 0)
00290          return mob;
00291       if (ctrlReg == _BV(CONMOB0) && (bit_is_set(CANSTMOB, TXOK)))
00292       {
00293           // Free MOB
00294           CANCDMOB &= ~(_BV(CONMOB1) | _BV(CONMOB0));
00295           return mob;
00296       }
00297    }
00298    return -1;
00299 }
00300 
00301 
00314 int8_t AtCanEnableMsgObj(uint8_t mob,
00315                          uint32_t id, int8_t idIsExt, int8_t idRemTag,
00316                          uint32_t mask, int8_t maskIsExt, int8_t maskRemTag)
00317 {
00318     if (mob < ATCAN_MAX_MOB)
00319     {
00320         // Select MOb
00321         CANPAGE = mob << 4;
00322         // Abort MOb
00323         CANCDMOB = 0;
00324         // Set identifier and mask
00325         if (idIsExt)
00326         {
00327             CANCDMOB |= _BV(IDE);
00328             CANIDT1 = (((uint8_t *) &(id))[3] << 3) + (((uint8_t *) &(id))[2] >> 5);
00329             CANIDT2 = (((uint8_t *) &(id))[2] << 3) + (((uint8_t *) &(id))[1] >> 5);
00330             CANIDT3 = (((uint8_t *) &(id))[1] << 3) + (((uint8_t *) &(id))[0] >> 5);
00331             CANIDT4 = (((uint8_t *) &(id))[0] << 3);
00332             CANIDM1 = (((uint8_t *) &(mask))[3] << 3) + (((uint8_t *) &(mask))[2] >> 5);
00333             CANIDM2 = (((uint8_t *) &(mask))[2] << 3) + (((uint8_t *) &(mask))[1] >> 5);
00334             CANIDM3 = (((uint8_t *) &(mask))[1] << 3) + (((uint8_t *) &(mask))[0] >> 5);
00335             CANIDM4 = (((uint8_t *) &(mask))[0] << 3);
00336         }
00337         else
00338         {
00339             CANIDT1 = (((uint8_t *) &(id))[1] << 5) + (((uint8_t *) &(id))[0] >> 3);
00340             CANIDT2 = (((uint8_t *) &(id))[0] << 5);
00341             CANIDT3 = 0;
00342             CANIDT4 = 0;
00343             CANIDM1 = (((uint8_t *) &(mask))[1] << 5) + (((uint8_t *) &(mask))[0] >> 3);
00344             CANIDM2 = (((uint8_t *) &(mask))[0] << 5);
00345             CANIDM3 = 0;
00346             CANIDM4 = 0;
00347         }
00348         if (idRemTag)
00349             CANIDT4 |= _BV(RTRTAG);
00350         if (maskIsExt)
00351             CANIDM4 |= _BV(IDEMSK);
00352         if (maskRemTag)
00353             CANIDM4 |= _BV(RTRMSK);
00354         // Enable reception
00355         CANCDMOB |= _BV(CONMOB1);
00356         return CAN_SUCCESS;
00357     }
00358     else
00359         return CAN_ILLEGAL_MOB;
00360 }
00361 
00362 
00382 int8_t AtCanEnableRx(uint8_t noOfMsgObjs,
00383                      uint32_t id, int8_t idIsExt, int8_t idRemTag,
00384                      uint32_t mask, int8_t maskIsExt, int8_t maskRemTag)
00385 {
00386     int8_t i;
00387     int8_t result;
00388 
00389     for (i = 0; i < noOfMsgObjs; i++)
00390     {
00391         result = AtCanEnableMsgObj(i, id, idIsExt, idRemTag, mask, maskIsExt, maskRemTag);
00392         if (result != CAN_SUCCESS)
00393             return result;
00394     }
00395     return CAN_SUCCESS;
00396 }
00397 
00398 
00405 int8_t AtCanSendMsg(CANFRAME *frame)
00406 {
00407     signed char mob, j;
00408 
00409     mob = AtCanGetFreeMob();
00410     if (mob < 0)
00411         return CAN_TXBUF_FULL;
00412     // Select MOB
00413     CANPAGE = mob << 4;
00414     // Abort MOB and set length fields
00415     CANCDMOB = frame->len;
00416     // Check for ID type
00417     if (frame->ext)
00418     {
00419         CANIDT1 = (((uint8_t *) &(frame->id))[3] << 3) + (((uint8_t *) &(frame->id))[2] >> 5);
00420         CANIDT2 = (((uint8_t *) &(frame->id))[2] << 3) + (((uint8_t *) &(frame->id))[1] >> 5);
00421         CANIDT3 = (((uint8_t *) &(frame->id))[1] << 3) + (((uint8_t *) &(frame->id))[0] >> 5);
00422         CANIDT4 = (((uint8_t *) &(frame->id))[0] << 3);
00423         CANCDMOB |= _BV(IDE);
00424     }
00425     else
00426     {
00427         CANIDT1 = (((uint8_t *) &(frame->id))[1] << 5) + (((uint8_t *) &(frame->id))[0] >> 3);
00428         CANIDT2 = (((uint8_t *) &(frame->id))[0] << 5);
00429         CANIDT3 = 0;
00430         CANIDT4 = 0;
00431     }
00432     if (frame->rtr)
00433         CANIDT4 |= _BV(RTRTAG);
00434     for (j = 0; j < 8; j++)
00435         CANMSG = frame->byte[j];
00436     // Enable transmission
00437     CANCDMOB |= _BV(CONMOB0);
00438 
00439     return CAN_SUCCESS;
00440 }
00441 
00442 
00446 static void AtCanInterrupt(void *arg)
00447 {
00448     uint8_t savedCanPage;
00449     CANINFO *ci = (CANINFO *) (((NUTDEVICE *) arg)->dev_dcb);
00450 
00451     savedCanPage = CANPAGE; // Save the current CAN page
00452     ci->can_interrupts++;
00453 
00454     //
00455     // Check for MOb interrupt
00456     //
00457     if ((CANHPMOB & 0xF0) != 0xF0)
00458     {
00459         CANPAGE = CANHPMOB; // Switch page
00460         // RX interrupt ?
00461         if (bit_is_set(CANSTMOB, RXOK))
00462         {
00463             // Space in buffer ?
00464             if (canRxBuf.datalength < canRxBuf.size)
00465             {
00466                 int8_t j;
00467                 CANFRAME * bufPtr = &canRxBuf.dataptr[(canRxBuf.dataindex + canRxBuf.datalength) % canRxBuf.size];
00468 
00469                 // Extended or standard ID?
00470                 bufPtr->ext = bit_is_set(CANCDMOB, IDE);
00471                 if (bufPtr->ext)
00472                 {
00473                     ((uint8_t *) &(bufPtr->id))[3] = CANIDT1 >> 3;
00474                     ((uint8_t *) &(bufPtr->id))[2] = (CANIDT2 >> 3) | (CANIDT1 << 5);
00475                     ((uint8_t *) &(bufPtr->id))[1] = (CANIDT3 >> 3) | (CANIDT2 << 5);
00476                     ((uint8_t *) &(bufPtr->id))[0] = (CANIDT4 >> 3) | (CANIDT3 << 5);
00477                 }
00478                 else
00479                 {
00480                     ((uint8_t *) &(bufPtr->id))[3] = 0;
00481                     ((uint8_t *) &(bufPtr->id))[2] = 0;
00482                     ((uint8_t *) &(bufPtr->id))[1] = CANIDT1 >> 5;
00483                     ((uint8_t *) &(bufPtr->id))[0] = (CANIDT1 << 3) | (CANIDT2 >> 5);
00484                 }
00485                 bufPtr->len = CANCDMOB & (_BV(DLC0) | _BV(DLC1) | _BV(DLC2) | _BV(DLC3));
00486                 bufPtr->rtr = bit_is_set(CANIDT4, RTRTAG);
00487                 for (j = 0; j < 8; j++)
00488                     bufPtr->byte[j] = CANMSG;
00489                 // Increment buffer length
00490                 canRxBuf.datalength++;
00491                 NutEventPostFromIrq(&ci->can_rx_rdy);
00492                 // Stat houskeeping
00493                 ci->can_rx_frames++;
00494             }
00495             else
00496             {
00497                 // Stat houskeeping
00498                 ci->can_overruns++;
00499             }
00500         }
00501         // TX interrupt ?
00502         else if (bit_is_set(CANSTMOB, TXOK))
00503         {
00504             NutEventPostFromIrq(&ci->can_tx_rdy);
00505             ci->can_tx_frames++;
00506         }
00507         // Error interrupts ?
00508         else
00509         {
00510            // Stat houskeeping
00511            ci->can_errors++;
00512         }
00513 
00514         //
00515         // Acknowledge all MOB interrupts and manage MObs
00516         //
00517         CANSTMOB = CANSTMOB & ~(_BV(TXOK) | _BV(RXOK) | _BV(BERR) |
00518                                 _BV(SERR) | _BV(CERR) | _BV(FERR) | _BV(AERR));
00519 
00520         if (bit_is_set(CANCDMOB, CONMOB1))
00521            // Re-enable MOb for reception by re-writing CONMOB1 bit
00522            CANCDMOB |= _BV(CONMOB1);
00523         else
00524            // Re-claim MOb as send buffer
00525            CANCDMOB &= ~(_BV(CONMOB1) | _BV(CONMOB0));
00526 
00527     }
00528     else
00529     {
00530         // Acknowledge general CAN interrupt
00531         CANGIT = _BV(BOFFIT) | _BV(BXOK) | _BV(SERG) | _BV(CERG) | _BV(FERG) | _BV(AERG);
00532         // Stat houskeeping
00533         ci->can_errors++;
00534     }
00535     CANPAGE = savedCanPage; // Restore CAN page register
00536 }
00537 
00538 
00539 /*****************************************************************************
00540  * Function definitions
00541  *****************************************************************************/
00542 
00549 uint8_t AtCanRxAvail(NUTDEVICE * dev)
00550 {
00551     return canRxBuf.datalength;
00552 }
00553 
00554 
00561 uint8_t AtCanTxFree(NUTDEVICE * dev)
00562 {
00563     return (AtCanGetFreeMob() >= 0);
00564 }
00565 
00566 
00576 void AtCanOutput(NUTDEVICE * dev, CANFRAME * frame)
00577 {
00578     CANINFO * ci = (CANINFO *) dev->dev_dcb;
00579 
00580     while (AtCanSendMsg(frame) == CAN_TXBUF_FULL)
00581     {
00582         NutEventWait(&ci->can_tx_rdy, NUT_WAIT_INFINITE);
00583     };
00584 }
00585 
00586 
00598 uint8_t AtCanInput(NUTDEVICE * dev, CANFRAME * frame)
00599 {
00600     CANINFO * ci = (CANINFO *) dev->dev_dcb;
00601 
00602     while (canRxBuf.datalength == 0)
00603     {
00604         uint32_t timeout =  ((IFCAN *) (dev->dev_icb))->can_rtimeout;
00605 
00606         if (NutEventWait(&ci->can_rx_rdy, timeout))
00607             return 1;
00608     }
00609     NutEnterCritical();
00610     // Get the first frame from buffer
00611     *frame = canRxBuf.dataptr[canRxBuf.dataindex];
00612     // Move index down and decrement length
00613     canRxBuf.dataindex++;
00614     if (canRxBuf.dataindex >= canRxBuf.size)
00615         canRxBuf.dataindex %= canRxBuf.size;
00616     canRxBuf.datalength--;
00617     NutExitCritical();
00618 
00619     return 0;
00620 }
00621 
00622 
00629 void AtCanSetAccCode(NUTDEVICE * dev, uint8_t * ac)
00630 {
00631     memcpy(((IFCAN *) (dev->dev_icb))->can_acc_code, ac, 4);
00632     AtCanEnableRx(RX_MOB, 0, 0, 0, 0, 0, 0); //ttt   TODO: Implement it!
00633 }
00634 
00635 
00642 void AtCanSetAccMask(NUTDEVICE * dev, uint8_t * am)
00643 {
00644     memcpy(((IFCAN *) (dev->dev_icb))->can_acc_mask, am, 4);
00645     AtCanEnableRx(RX_MOB, 0, 0, 0, 0, 0, 0); //ttt   TODO: Implement it!
00646 }
00647 
00648 
00656 uint8_t AtCanSetBaudrate(NUTDEVICE * dev, uint32_t baudrate)
00657 {
00658     switch (baudrate)
00659     {
00660 #if NUT_CPU_FREQ != 8000000
00661         case CAN_SPEED_10K:
00662             CANBT1 = CAN_BT1_10K;
00663             CANBT2 = CAN_BT2_10K;
00664             CANBT3 = CAN_BT3_10K;
00665         break;
00666         case CAN_SPEED_20K:
00667             CANBT1 = CAN_BT1_20K;
00668             CANBT2 = CAN_BT2_20K;
00669             CANBT3 = CAN_BT3_20K;
00670         break;
00671         case CAN_SPEED_50K:
00672             CANBT1 = CAN_BT1_50K;
00673             CANBT2 = CAN_BT2_50K;
00674             CANBT3 = CAN_BT3_50K;
00675         break;
00676 #endif
00677         case CAN_SPEED_100K:
00678             CANBT1 = CAN_BT1_100K;
00679             CANBT2 = CAN_BT2_100K;
00680             CANBT3 = CAN_BT3_100K;
00681         break;
00682         case CAN_SPEED_125K:
00683             CANBT1 = CAN_BT1_125K;
00684             CANBT2 = CAN_BT2_125K;
00685             CANBT3 = CAN_BT3_125K;
00686         break;
00687         case CAN_SPEED_250K:
00688             CANBT1 = CAN_BT1_250K;
00689             CANBT2 = CAN_BT2_250K;
00690             CANBT3 = CAN_BT3_250K;
00691         break;
00692         case CAN_SPEED_500K:
00693             CANBT1 = CAN_BT1_500K;
00694             CANBT2 = CAN_BT2_500K;
00695             CANBT3 = CAN_BT3_500K;
00696         break;
00697 #if NUT_CPU_FREQ != 8000000
00698         case CAN_SPEED_800K:
00699             CANBT1 = CAN_BT1_800K;
00700             CANBT2 = CAN_BT2_800K;
00701             CANBT3 = CAN_BT3_800K;
00702         break;
00703 #endif
00704         case CAN_SPEED_1M:
00705             CANBT1 = CAN_BT1_1M;
00706             CANBT2 = CAN_BT2_1M;
00707             CANBT3 = CAN_BT3_1M;
00708         break;
00709         case CAN_SPEED_CUSTOM:
00710             // Do nothing, user sets baud rate directly but don't report an error
00711         break;
00712         default:
00713         return 1;
00714     }
00715     ((IFCAN *) (dev->dev_icb))->can_baudrate = baudrate;
00716     return 0;
00717 }
00718 
00719 
00730 int AtCanInit(NUTDEVICE * dev)
00731 {
00732     int8_t mob, i;
00733 
00734     memset(dev->dev_dcb, 0, sizeof(CANINFO));
00735 
00736     // Init receive buffer
00737     canRxBuf.dataptr = NutHeapAlloc(ATCAN_RX_BUF_SIZE * sizeof(CANFRAME));
00738     if (canRxBuf.dataptr == 0)
00739         return -1;
00740     canRxBuf.size = ATCAN_RX_BUF_SIZE;
00741     canRxBuf.dataindex = 0;
00742     canRxBuf.datalength = 0;
00743 
00744     // Disable AT90CAN128 CAN system
00745     CANGCON &= ~_BV(ENASTB);
00746     loop_until_bit_is_clear(CANGSTA, ENFG);
00747 
00748     // Clear all MObs
00749     for (mob = 0; mob < ATCAN_MAX_MOB; mob++)
00750     {
00751         CANPAGE = mob << 4;
00752         CANSTMOB = 0; // Clear status register
00753         CANCDMOB = 0; // Clear control register
00754         CANHPMOB = 0; // Clear HP flags
00755         // Clear identifier tag
00756         CANIDT1 = 0;
00757         CANIDT2 = 0;
00758         CANIDT3 = 0;
00759         CANIDT4 = 0;
00760         // Clear identifier mask
00761         CANIDM1 = 0;
00762         CANIDM2 = 0;
00763         CANIDM3 = 0;
00764         CANIDM4 = 0;
00765         for (i = 0; i < 8; i++)
00766         {
00767             CANMSG = 0;
00768         }
00769     }
00770     // Set baudrate
00771     AtCanSetBaudrate(dev, ifc_atcan.can_baudrate); // Errors silently ingnored here
00772     // Install IRQ handler
00773     if (NutRegisterIrqHandler(&sig_CAN_TRANSFER, AtCanInterrupt, dev))
00774         return -1;
00775     // Enable all interrupts
00776     CANIE1 = 0x7F;
00777     CANIE2 = 0xFF;
00778     CANGIE = 0xFE; // All interrupts except OVRTIM
00779     // Enable receiving MOBs
00780     AtCanEnableRx(RX_MOB, 0, 0, 0, 0, 0, 0);
00781 
00782     // Enable AT90CAN128 CAN system
00783     CANGCON |= _BV(ENASTB);
00784     loop_until_bit_is_set(CANGSTA, ENFG);
00785 
00786     return 0;
00787 }
00788 
00789 
00796 IFCAN ifc_atcan = {
00797     CAN_IF_2B,                 
00798     CAN_SPEED_125K,            
00799     {0xFF, 0xFF, 0xFF, 0xFF},  
00800     {0x00, 0x00, 0x00, 0x00},  
00801     NUT_WAIT_INFINITE,         
00802     AtCanRxAvail,              
00803     AtCanTxFree,               
00804     AtCanInput,                
00805     AtCanOutput,               
00806     AtCanSetAccCode,           
00807     AtCanSetAccMask,           
00808     AtCanSetBaudrate,          
00809 };
00810 
00811 
00818 NUTDEVICE devAtCan = {
00819     0,                          
00820     {'a', 't', 'c', 'a', 'n', '0', 0, 0, 0}, 
00821     IFTYP_CAN,                  
00822     0,                          
00823     0,                          
00824     &ifc_atcan,                 
00825     &dcb_atcan,                 
00826     AtCanInit,                  
00827     0,                          
00828     0,                          
00829     0,                          
00830     0,                          
00831     0,                          
00832     0,                          
00833     0                           
00834 };
00835 
00836 #else
00837 
00838 static void keep_icc_happy(void)
00839 {
00840 }
00841 
00842 #endif
00843 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/