| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- /*
- * Copyright (c) 2005-2009 proconX Pty Ltd. All rights reserved.
- *
- * This driver has been closely modeled after the existing Nut/OS SJA1000
- * driver and the buffer management and some code snippets have been borrowed
- * from sja1000.c.
- *
- * Portions Copyright (C) 2004 by Ole Reinhardt <ole.reinhardt@kernelconcepts.de>,
- * Kernelconcepts http://www.kernelconcepts.de
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- *
- */
- /*!
- * \file arch/avr/dev/atcan.c
- * \brief AVR on-chip CAN support.
- *
- * \verbatim
- * $Id: atcan.c 5472 2013-12-06 00:16:28Z olereinhardt $
- * \endverbatim
- */
- /*!
- * \addtogroup xgCanAvr
- */
- /*@{*/
- #ifdef __GNUC__
- #include <cfg/arch/avr.h>
- #include <string.h>
- #include <sys/event.h>
- #include <sys/heap.h>
- #include <sys/atom.h>
- #include <dev/irqreg.h>
- #include <dev/can_dev.h>
- #include <avr/io.h>
- #include <dev/atcan.h>
- /*****************************************************************************
- * Definitions
- *****************************************************************************/
- #define RX_MOB 8
- #ifndef ATCAN_RX_BUF_SIZE
- # define ATCAN_RX_BUF_SIZE 64
- #endif
- /*****************************************************************************
- * CAN baud rate table
- *
- * Tried to match as closely as possible a sampling point of 87.5 %
- * which is recommended by CiA for CANOpen. DeviceNet specifies a
- * sampling point > 80%. SQW is 2.
- *****************************************************************************/
- #if defined(NUT_CPU_FREQ)
- //
- // 8.00 MHz
- //
- #if NUT_CPU_FREQ == 8000000
- // 100 kbit/s 86.67% 15 quanta (BRP=7 Tprs=8 Tph1=4 Tph2=2 Tsjw=2)
- #define CAN_BT1_100K 0x08
- #define CAN_BT2_100K 0x0C
- #define CAN_BT3_100K 0x37
- // 125 kbit/s 87.50% 16 quanta (BRP=5 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_125K 0x0E
- #define CAN_BT2_125K 0x04
- #define CAN_BT3_125K 0x13
- // 250 kbit/s 87.50% 16 quanta (BRP=2 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_250K 0x06
- #define CAN_BT2_250K 0x04
- #define CAN_BT3_250K 0x13
- // 500 kbit/s 83.33% 12 quanta (BRP=1 Tprs=7 Tph1=2 Tph2=2 Tsjw=2)
- #define CAN_BT1_500K 0x02
- #define CAN_BT2_500K 0x0C
- #define CAN_BT3_500K 0x37
- // 1000 kbit/s 83.33% 12 quanta (BRP=0 Tprs=7 Tph1=2 Tph2=2 Tsjw=2)
- #define CAN_BT1_1M 0x00
- #define CAN_BT2_1M 0x04
- #define CAN_BT3_1M 0x12
- //
- // 12.00 MHz
- //
- #elif NUT_CPU_FREQ == 12000000
- // 10 kbit/s 85.00% 20 quanta (BRP=59 Tprs=8 Tph1=8 Tph2=3 Tsjw=2)
- #define CAN_BT1_10K 0x76
- #define CAN_BT2_10K 0x2E
- #define CAN_BT3_10K 0x2E
- // 20 kbit/s 86.67% 15 quanta (BRP=39 Tprs=8 Tph1=4 Tph2=2 Tsjw=2)
- #define CAN_BT1_20K 0x4E
- #define CAN_BT2_20K 0x2E
- #define CAN_BT3_20K 0x16
- // 50 kbit/s 87.50% 16 quanta (BRP=14 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_50K 0x1C
- #define CAN_BT2_50K 0x2E
- #define CAN_BT3_50K 0x18
- // 100 kbit/s 86.67% 15 quanta (BRP=7 Tprs=8 Tph1=4 Tph2=2 Tsjw=2)
- #define CAN_BT1_100K 0x0E
- #define CAN_BT2_100K 0x2E
- #define CAN_BT3_100K 0x16
- // 125 kbit/s 87.50% 16 quanta (BRP=5 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_125K 0x0A
- #define CAN_BT2_125K 0x2E
- #define CAN_BT3_125K 0x18
- // 250 kbit/s 87.50% 16 quanta (BRP=2 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_250K 0x04
- #define CAN_BT2_250K 0x2E
- #define CAN_BT3_250K 0x18
- // 500 kbit/s 83.33% 12 quanta (BRP=1 Tprs=7 Tph1=2 Tph2=2 Tsjw=2)
- #define CAN_BT1_500K 0x02
- #define CAN_BT2_500K 0x2C
- #define CAN_BT3_500K 0x12
- // 800 kbit/s 86.67% 15 quanta (BRP=0 Tprs=8 Tph1=4 Tph2=2 Tsjw=2)
- #define CAN_BT1_800K 0x00
- #define CAN_BT2_800K 0x2E
- #define CAN_BT3_800K 0x16
- // 1000 kbit/s 83.33% 12 quanta (BRP=0 Tprs=7 Tph1=2 Tph2=2 Tsjw=2)
- #define CAN_BT1_1M 0x00
- #define CAN_BT2_1M 0x2C
- #define CAN_BT3_1M 0x12
- //
- // 16.00 MHz
- //
- #elif NUT_CPU_FREQ == 16000000
- // 10 kbit/s 68.00% 25 quanta (BRP=63 Tprs=8 Tph1=8 Tph2=8 Tsjw=2)
- #define CAN_BT1_10K 0x7E
- #define CAN_BT2_10K 0x2E
- #define CAN_BT3_10K 0x7E
- // 20 kbit/s 87.50% 16 quanta (BRP=49 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_20K 0x62
- #define CAN_BT2_20K 0x2E
- #define CAN_BT3_20K 0x18
- // 50 kbit/s 87.50% 16 quanta (BRP=19 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_50K 0x26
- #define CAN_BT2_50K 0x2E
- #define CAN_BT3_50K 0x18
- // 100 kbit/s 87.50% 16 quanta (BRP=9 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_100K 0x12
- #define CAN_BT2_100K 0x2E
- #define CAN_BT3_100K 0x18
- // 125 kbit/s 87.50% 16 quanta (BRP=7 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_125K 0x0E
- #define CAN_BT2_125K 0x2E
- #define CAN_BT3_125K 0x18
- // 250 kbit/s 87.50% 16 quanta (BRP=3 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_250K 0x06
- #define CAN_BT2_250K 0x2E
- #define CAN_BT3_250K 0x18
- // 500 kbit/s 87.50% 16 quanta (BRP=1 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_500K 0x02
- #define CAN_BT2_500K 0x2E
- #define CAN_BT3_500K 0x18
- // 800 kbit/s 85.00% 20 quanta (BRP=0 Tprs=8 Tph1=8 Tph2=3 Tsjw=2)
- #define CAN_BT1_800K 0x00
- #define CAN_BT2_800K 0x2E
- #define CAN_BT3_800K 0x2E
- // 1000 kbit/s 87.50% 16 quanta (BRP=0 Tprs=8 Tph1=5 Tph2=2 Tsjw=2)
- #define CAN_BT1_1M 0x00
- #define CAN_BT2_1M 0x2E
- #define CAN_BT3_1M 0x18
- #else
- # error Frequency not supported or not set to a Fixed MCU clock!
- #endif
- #endif
- /*****************************************************************************
- * Buffer management
- *
- * Note: Buffer concept borrowed from existing Nut/OS sja1000.c driver
- *****************************************************************************/
- struct _CANBuffer {
- CANFRAME *dataptr; // the physical memory address where the buffer is stored
- uint8_t size; // the allocated size of the buffer
- uint8_t datalength; // the length of the data currently in the buffer
- uint8_t dataindex; // the index into the buffer where the data starts
- };
- typedef struct _CANBuffer CANBuffer;
- /*****************************************************************************
- * Driver data
- *****************************************************************************/
- static CANBuffer canRxBuf;
- CANINFO dcb_atcan;
- IFCAN ifc_atcan;
- NUTDEVICE devAtCan;
- /*****************************************************************************
- * Low level functions
- *****************************************************************************/
- /**
- * Returns the state of this CAN node.
- * Refer to state diagram in AT90CAN128 dataheet chapter 20.7 "Error
- * Management"
- *
- * @retval CAN_SUCCESS if CAN node is in ACTIVE state
- * @retval CAN_PASSIVE if CAN node is in PASSIVE state
- * @retval CAN_BUS_OFF if CAN node is in BUS OFF state
- */
- int8_t AtCanGetBusState(void)
- {
- if (CANGSTA & _BV(BOFF))
- return CAN_BUS_OFF;
- if (CANGSTA & _BV(ERRP))
- return CAN_PASSIVE;
- return CAN_SUCCESS;
- }
- /**
- * @internal
- * Search for a free message object
- * @return Index of free message object or -1 if none is available
- */
- int8_t AtCanGetFreeMob(void)
- {
- int8_t mob;
- uint8_t ctrlReg;
- for (mob = 0; mob < ATCAN_MAX_MOB; mob++)
- {
- CANPAGE = mob << 4;
- ctrlReg = CANCDMOB & (_BV(CONMOB1) | _BV(CONMOB0));
- if (ctrlReg == 0)
- return mob;
- if (ctrlReg == _BV(CONMOB0) && (bit_is_set(CANSTMOB, TXOK)))
- {
- // Free MOB
- CANCDMOB &= ~(_BV(CONMOB1) | _BV(CONMOB0));
- return mob;
- }
- }
- return -1;
- }
- /**
- * Configure a single message object for receiption.
- *
- * All 15 MOBS can be set up for reception, not only RX_MOB MOBs
- *
- * @param mob Message object index (0-14)
- * @param id Acceptance code
- * @param idIsExt Flag if acceptance code is extended (0 = standard, 1 = extended)
- * @param idRemTag Id's remote tag (0 or 1)
- * @param mask Acceptance mask
- * @param maskIsExt Flag if acceptance mask is extended (0 = standard, 1 = extended)
- * @param maskRemTag Mask's remote tag (0 or 1)
- * @return Result code. See @ref CAN_RESULT
- */
- int8_t AtCanEnableMsgObj(uint8_t mob,
- uint32_t id, int8_t idIsExt, int8_t idRemTag,
- uint32_t mask, int8_t maskIsExt, int8_t maskRemTag)
- {
- if (mob < ATCAN_MAX_MOB)
- {
- // Select MOb
- CANPAGE = mob << 4;
- // Abort MOb
- CANCDMOB = 0;
- // Set identifier and mask
- if (idIsExt)
- {
- CANCDMOB |= _BV(IDE);
- CANIDT1 = (((uint8_t *) &(id))[3] << 3) + (((uint8_t *) &(id))[2] >> 5);
- CANIDT2 = (((uint8_t *) &(id))[2] << 3) + (((uint8_t *) &(id))[1] >> 5);
- CANIDT3 = (((uint8_t *) &(id))[1] << 3) + (((uint8_t *) &(id))[0] >> 5);
- CANIDT4 = (((uint8_t *) &(id))[0] << 3);
- CANIDM1 = (((uint8_t *) &(mask))[3] << 3) + (((uint8_t *) &(mask))[2] >> 5);
- CANIDM2 = (((uint8_t *) &(mask))[2] << 3) + (((uint8_t *) &(mask))[1] >> 5);
- CANIDM3 = (((uint8_t *) &(mask))[1] << 3) + (((uint8_t *) &(mask))[0] >> 5);
- CANIDM4 = (((uint8_t *) &(mask))[0] << 3);
- }
- else
- {
- CANIDT1 = (((uint8_t *) &(id))[1] << 5) + (((uint8_t *) &(id))[0] >> 3);
- CANIDT2 = (((uint8_t *) &(id))[0] << 5);
- CANIDT3 = 0;
- CANIDT4 = 0;
- CANIDM1 = (((uint8_t *) &(mask))[1] << 5) + (((uint8_t *) &(mask))[0] >> 3);
- CANIDM2 = (((uint8_t *) &(mask))[0] << 5);
- CANIDM3 = 0;
- CANIDM4 = 0;
- }
- if (idRemTag)
- CANIDT4 |= _BV(RTRTAG);
- if (maskIsExt)
- CANIDM4 |= _BV(IDEMSK);
- if (maskRemTag)
- CANIDM4 |= _BV(RTRMSK);
- // Enable reception
- CANCDMOB |= _BV(CONMOB1);
- return CAN_SUCCESS;
- }
- else
- return CAN_ILLEGAL_MOB;
- }
- /**
- * Configure message objects for receiption.
- *
- * @param noOfMsgObjs Number of message objects used for receiption (1-14).
- * Message objects not configured for receiption are used for
- * transmission.
- * The same acceptance filter and mask is applied to the
- * message objects.
- * If it is required to set-up more complex
- * filtering mechanisms use canEnableMsgObj() instead, which
- * allows setting filters on a per message object basis.
- * @param id Acceptance code
- * @param idIsExt Flag if acceptance code is extended (0 = standard, 1 = extended)
- * @param idRemTag Id's remote tag (0 or 1)
- * @param mask Acceptance mask
- * @param maskIsExt Flag if acceptance mask is extended (0 = standard, 1 = extended)
- * @param maskRemTag Mask's remote tag (0 or 1)
- * @return Result code. See @ref CAN_RESULT
- */
- int8_t AtCanEnableRx(uint8_t noOfMsgObjs,
- uint32_t id, int8_t idIsExt, int8_t idRemTag,
- uint32_t mask, int8_t maskIsExt, int8_t maskRemTag)
- {
- int8_t i;
- int8_t result;
- for (i = 0; i < noOfMsgObjs; i++)
- {
- result = AtCanEnableMsgObj(i, id, idIsExt, idRemTag, mask, maskIsExt, maskRemTag);
- if (result != CAN_SUCCESS)
- return result;
- }
- return CAN_SUCCESS;
- }
- /**
- * Send a CAN message
- *
- * @param frame Container for CAN message to be sent
- * @return Result code. See @ref CAN_RESULT
- */
- int8_t AtCanSendMsg(CANFRAME *frame)
- {
- signed char mob, j;
- mob = AtCanGetFreeMob();
- if (mob < 0)
- return CAN_TXBUF_FULL;
- // Select MOB
- CANPAGE = mob << 4;
- // Abort MOB and set length fields
- CANCDMOB = frame->len;
- // Check for ID type
- if (frame->ext)
- {
- CANIDT1 = (((uint8_t *) &(frame->id))[3] << 3) + (((uint8_t *) &(frame->id))[2] >> 5);
- CANIDT2 = (((uint8_t *) &(frame->id))[2] << 3) + (((uint8_t *) &(frame->id))[1] >> 5);
- CANIDT3 = (((uint8_t *) &(frame->id))[1] << 3) + (((uint8_t *) &(frame->id))[0] >> 5);
- CANIDT4 = (((uint8_t *) &(frame->id))[0] << 3);
- CANCDMOB |= _BV(IDE);
- }
- else
- {
- CANIDT1 = (((uint8_t *) &(frame->id))[1] << 5) + (((uint8_t *) &(frame->id))[0] >> 3);
- CANIDT2 = (((uint8_t *) &(frame->id))[0] << 5);
- CANIDT3 = 0;
- CANIDT4 = 0;
- }
- if (frame->rtr)
- CANIDT4 |= _BV(RTRTAG);
- for (j = 0; j < 8; j++)
- CANMSG = frame->byte[j];
- // Enable transmission
- CANCDMOB |= _BV(CONMOB0);
- return CAN_SUCCESS;
- }
- /*!
- * AtCan interrupt service routine
- */
- static void AtCanInterrupt(void *arg)
- {
- uint8_t savedCanPage;
- CANINFO *ci = (CANINFO *) (((NUTDEVICE *) arg)->dev_dcb);
- savedCanPage = CANPAGE; // Save the current CAN page
- ci->can_interrupts++;
- //
- // Check for MOb interrupt
- //
- if ((CANHPMOB & 0xF0) != 0xF0)
- {
- CANPAGE = CANHPMOB; // Switch page
- // RX interrupt ?
- if (bit_is_set(CANSTMOB, RXOK))
- {
- // Space in buffer ?
- if (canRxBuf.datalength < canRxBuf.size)
- {
- int8_t j;
- CANFRAME * bufPtr = &canRxBuf.dataptr[(canRxBuf.dataindex + canRxBuf.datalength) % canRxBuf.size];
- // Extended or standard ID?
- bufPtr->ext = bit_is_set(CANCDMOB, IDE);
- if (bufPtr->ext)
- {
- ((uint8_t *) &(bufPtr->id))[3] = CANIDT1 >> 3;
- ((uint8_t *) &(bufPtr->id))[2] = (CANIDT2 >> 3) | (CANIDT1 << 5);
- ((uint8_t *) &(bufPtr->id))[1] = (CANIDT3 >> 3) | (CANIDT2 << 5);
- ((uint8_t *) &(bufPtr->id))[0] = (CANIDT4 >> 3) | (CANIDT3 << 5);
- }
- else
- {
- ((uint8_t *) &(bufPtr->id))[3] = 0;
- ((uint8_t *) &(bufPtr->id))[2] = 0;
- ((uint8_t *) &(bufPtr->id))[1] = CANIDT1 >> 5;
- ((uint8_t *) &(bufPtr->id))[0] = (CANIDT1 << 3) | (CANIDT2 >> 5);
- }
- bufPtr->len = CANCDMOB & (_BV(DLC0) | _BV(DLC1) | _BV(DLC2) | _BV(DLC3));
- bufPtr->rtr = bit_is_set(CANIDT4, RTRTAG);
- for (j = 0; j < 8; j++)
- bufPtr->byte[j] = CANMSG;
- // Increment buffer length
- canRxBuf.datalength++;
- NutEventPostFromIrq(&ci->can_rx_rdy);
- // Stat houskeeping
- ci->can_rx_frames++;
- }
- else
- {
- // Stat houskeeping
- ci->can_overruns++;
- }
- }
- // TX interrupt ?
- else if (bit_is_set(CANSTMOB, TXOK))
- {
- NutEventPostFromIrq(&ci->can_tx_rdy);
- ci->can_tx_frames++;
- }
- // Error interrupts ?
- else
- {
- // Stat houskeeping
- ci->can_errors++;
- }
- //
- // Acknowledge all MOB interrupts and manage MObs
- //
- CANSTMOB = CANSTMOB & ~(_BV(TXOK) | _BV(RXOK) | _BV(BERR) |
- _BV(SERR) | _BV(CERR) | _BV(FERR) | _BV(AERR));
- if (bit_is_set(CANCDMOB, CONMOB1))
- // Re-enable MOb for reception by re-writing CONMOB1 bit
- CANCDMOB |= _BV(CONMOB1);
- else
- // Re-claim MOb as send buffer
- CANCDMOB &= ~(_BV(CONMOB1) | _BV(CONMOB0));
- }
- else
- {
- // Acknowledge general CAN interrupt
- CANGIT = _BV(BOFFIT) | _BV(BXOK) | _BV(SERG) | _BV(CERG) | _BV(FERG) | _BV(AERG);
- // Stat houskeeping
- ci->can_errors++;
- }
- CANPAGE = savedCanPage; // Restore CAN page register
- }
- /*****************************************************************************
- * Function definitions
- *****************************************************************************/
- /*!
- * Checks if data is available in input buffer
- *
- * \param dev Pointer to the device structure
- * \return Number of frames available
- */
- uint8_t AtCanRxAvail(NUTDEVICE * dev)
- {
- return canRxBuf.datalength;
- }
- /*!
- * Checks if there's still space in output buffer
- *
- * \param dev Pointer to the device structure
- * \return 1 if space is available
- */
- uint8_t AtCanTxFree(NUTDEVICE * dev)
- {
- return (AtCanGetFreeMob() >= 0);
- }
- /*!
- * Write a frame from to output buffer
- *
- * This function writes a frame to the output buffer. If the output buffer
- * is full the function will block until frames are send.
- *
- * \param dev Pointer to the device structure
- * \param frame Pointer to the receive frame
- */
- void AtCanOutput(NUTDEVICE * dev, CANFRAME * frame)
- {
- CANINFO * ci = (CANINFO *) dev->dev_dcb;
- while (AtCanSendMsg(frame) == CAN_TXBUF_FULL)
- {
- NutEventWait(&ci->can_tx_rdy, NUT_WAIT_INFINITE);
- };
- }
- /*!
- * Reads a frame from input buffer
- *
- * This function reads a frame from the input buffer. If the input buffer
- * is empty the function will block unitl new frames are received,
- * or the timeout is reached.
- *
- * \param dev Pointer to the device structure
- * \param frame Pointer to the receive frame
- * \return 1 if timeout, 0 otherwise
- */
- uint8_t AtCanInput(NUTDEVICE * dev, CANFRAME * frame)
- {
- CANINFO * ci = (CANINFO *) dev->dev_dcb;
- while (canRxBuf.datalength == 0)
- {
- uint32_t timeout = ((IFCAN *) (dev->dev_icb))->can_rtimeout;
- if (NutEventWait(&ci->can_rx_rdy, timeout))
- return 1;
- }
- NutEnterCritical();
- // Get the first frame from buffer
- *frame = canRxBuf.dataptr[canRxBuf.dataindex];
- // Move index down and decrement length
- canRxBuf.dataindex++;
- if (canRxBuf.dataindex >= canRxBuf.size)
- canRxBuf.dataindex %= canRxBuf.size;
- canRxBuf.datalength--;
- NutExitCritical();
- return 0;
- }
- /*!
- * Sets the acceptance code
- *
- * \param dev Pointer to the device structure
- * \param ac 4 byte char array with the acceptance code
- */
- void AtCanSetAccCode(NUTDEVICE * dev, uint8_t * ac)
- {
- memcpy(((IFCAN *) (dev->dev_icb))->can_acc_code, ac, 4);
- AtCanEnableRx(RX_MOB, 0, 0, 0, 0, 0, 0); //ttt TODO: Implement it!
- }
- /*!
- * Sets the acceptance mask
- *
- * \param dev Pointer to the device structure
- * \param am 4 byte char array with the acceptance mask
- */
- void AtCanSetAccMask(NUTDEVICE * dev, uint8_t * am)
- {
- memcpy(((IFCAN *) (dev->dev_icb))->can_acc_mask, am, 4);
- AtCanEnableRx(RX_MOB, 0, 0, 0, 0, 0, 0); //ttt TODO: Implement it!
- }
- /*!
- * Sets the CAN baud rate
- *
- * \param dev Pointer to the device structure
- * \param baudrate Baud rate (One of the defined baud rates. See AtCan.h)
- * \return 0 for success
- */
- uint8_t AtCanSetBaudrate(NUTDEVICE * dev, uint32_t baudrate)
- {
- #if !defined(NUT_CPU_FREQ)
- return -1;
- #else
- switch (baudrate)
- {
- #if NUT_CPU_FREQ != 8000000
- case CAN_SPEED_10K:
- CANBT1 = CAN_BT1_10K;
- CANBT2 = CAN_BT2_10K;
- CANBT3 = CAN_BT3_10K;
- break;
- case CAN_SPEED_20K:
- CANBT1 = CAN_BT1_20K;
- CANBT2 = CAN_BT2_20K;
- CANBT3 = CAN_BT3_20K;
- break;
- case CAN_SPEED_50K:
- CANBT1 = CAN_BT1_50K;
- CANBT2 = CAN_BT2_50K;
- CANBT3 = CAN_BT3_50K;
- break;
- #endif
- case CAN_SPEED_100K:
- CANBT1 = CAN_BT1_100K;
- CANBT2 = CAN_BT2_100K;
- CANBT3 = CAN_BT3_100K;
- break;
- case CAN_SPEED_125K:
- CANBT1 = CAN_BT1_125K;
- CANBT2 = CAN_BT2_125K;
- CANBT3 = CAN_BT3_125K;
- break;
- case CAN_SPEED_250K:
- CANBT1 = CAN_BT1_250K;
- CANBT2 = CAN_BT2_250K;
- CANBT3 = CAN_BT3_250K;
- break;
- case CAN_SPEED_500K:
- CANBT1 = CAN_BT1_500K;
- CANBT2 = CAN_BT2_500K;
- CANBT3 = CAN_BT3_500K;
- break;
- #if NUT_CPU_FREQ != 8000000
- case CAN_SPEED_800K:
- CANBT1 = CAN_BT1_800K;
- CANBT2 = CAN_BT2_800K;
- CANBT3 = CAN_BT3_800K;
- break;
- #endif
- case CAN_SPEED_1M:
- CANBT1 = CAN_BT1_1M;
- CANBT2 = CAN_BT2_1M;
- CANBT3 = CAN_BT3_1M;
- break;
- case CAN_SPEED_CUSTOM:
- // Do nothing, user sets baud rate directly but don't report an error
- break;
- default:
- return 1;
- }
- ((IFCAN *) (dev->dev_icb))->can_baudrate = baudrate;
- return 0;
- #endif
- }
- /*!
- * Initialize CAN interface.
- *
- * Applications typically do not use this function, but
- * call NutRegisterDevice().
- *
- * \param dev Identifies the device to initialize. The
- * structure must be properly set.
- * \return 0 for successful initialisation or -1 in case init failed
- */
- int AtCanInit(NUTDEVICE * dev)
- {
- int8_t mob, i;
- #if !defined( NUT_CPU_FREQ)
- return -1;
- #endif
- memset(dev->dev_dcb, 0, sizeof(CANINFO));
- // Init receive buffer
- canRxBuf.dataptr = NutHeapAlloc(ATCAN_RX_BUF_SIZE * sizeof(CANFRAME));
- if (canRxBuf.dataptr == 0)
- return -1;
- canRxBuf.size = ATCAN_RX_BUF_SIZE;
- canRxBuf.dataindex = 0;
- canRxBuf.datalength = 0;
- // Disable AT90CAN128 CAN system
- CANGCON &= ~_BV(ENASTB);
- loop_until_bit_is_clear(CANGSTA, ENFG);
- // Clear all MObs
- for (mob = 0; mob < ATCAN_MAX_MOB; mob++)
- {
- CANPAGE = mob << 4;
- CANSTMOB = 0; // Clear status register
- CANCDMOB = 0; // Clear control register
- CANHPMOB = 0; // Clear HP flags
- // Clear identifier tag
- CANIDT1 = 0;
- CANIDT2 = 0;
- CANIDT3 = 0;
- CANIDT4 = 0;
- // Clear identifier mask
- CANIDM1 = 0;
- CANIDM2 = 0;
- CANIDM3 = 0;
- CANIDM4 = 0;
- for (i = 0; i < 8; i++)
- {
- CANMSG = 0;
- }
- }
- // Set baudrate
- AtCanSetBaudrate(dev, ifc_atcan.can_baudrate); // Errors silently ingnored here
- // Install IRQ handler
- if (NutRegisterIrqHandler(&sig_CAN_TRANSFER, AtCanInterrupt, dev))
- return -1;
- // Enable all interrupts
- CANIE1 = 0x7F;
- CANIE2 = 0xFF;
- CANGIE = 0xFE; // All interrupts except OVRTIM
- // Enable receiving MOBs
- AtCanEnableRx(RX_MOB, 0, 0, 0, 0, 0, 0);
- // Enable AT90CAN128 CAN system
- CANGCON |= _BV(ENASTB);
- loop_until_bit_is_set(CANGSTA, ENFG);
- return 0;
- }
- /*!
- * Interface information structure.
- *
- * This structure stores some interface parameters like bit rate,
- * acceptance mask, acceptance code and callback handlers.
- */
- IFCAN ifc_atcan = {
- CAN_IF_2B, /*!< \brief Interface type. */
- CAN_SPEED_125K, /*!< \brief Baudrate of device. */
- {0xFF, 0xFF, 0xFF, 0xFF}, /*!< \brief Acceptance mask */
- {0x00, 0x00, 0x00, 0x00}, /*!< \brief Acceptance code */
- NUT_WAIT_INFINITE, /*!< \brief Receive time-out */
- AtCanRxAvail, /*!< \brief Data in RxBuffer available? */
- AtCanTxFree, /*!< \brief TxBuffer free? */
- AtCanInput, /*!< \brief CAN Input routine */
- AtCanOutput, /*!< \brief CAN Output routine */
- AtCanSetAccCode, /*!< \brief Set acceptance code */
- AtCanSetAccMask, /*!< \brief Set acceptance mask */
- AtCanSetBaudrate, /*!< \brief Set baudrate */
- };
- /*!
- * Device information structure.
- *
- * Applications must pass this structure to NutRegisterDevice()
- * to bind this CAN device driver to the Nut/OS kernel.
- */
- NUTDEVICE devAtCan = {
- 0, /*!< Pointer to next device. */
- {'a', 't', 'c', 'a', 'n', '0', 0, 0, 0}, /*!< Unique device name. */
- IFTYP_CAN, /*!< Type of device. */
- 0, /*!< Base address. */
- 0, /*!< First interrupt number. */
- &ifc_atcan, /*!< Interface control block. */
- &dcb_atcan, /*!< Driver control block. */
- AtCanInit, /*!< Driver initialization routine. */
- 0, /*!< Driver specific control function. */
- 0, /*!< Read from device. */
- 0, /*!< Write to device. */
- 0, /*!< Write from program space data to device. */
- 0, /*!< Open a device or file. */
- 0, /*!< Close a device or file. */
- 0, /*!< Request file size. */
- 0, /*!< Select function, optional, not yet implemented */
- };
- #else
- static void keep_icc_happy(void)
- {
- }
- #endif
- /*@}*/
|