📄 atcan.c
字号:
/* * Copyright (c) 2005 FOCUS Software Engineering Pty Ltd <www.focus-sw.com> * Copyright (c) 2005 proconX <www.proconx.com> * * 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 EGNITE SOFTWARE GMBH 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 EGNITE * SOFTWARE GMBH 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/ * *//* * $Log: atcan.c,v $ * Revision 1.3 2005/12/04 10:53:59 hwmaier * no message * * Revision 1.2 2005/10/07 22:02:33 hwmaier * no message * * Revision 1.1 2005/10/04 06:00:59 hwmaier * Added AT90CAN128 CAN driver * *//*! * \addtogroup xgCanAvr *//*@{*/#ifdef __GNUC__#include <cfg/os.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 MAX_NO_MOB 15/** * CAN result codes * * @ingroup can */enum CAN_RESULT{ CAN_SUCCESS = 0, ///< Successful operation CAN_TXBUF_FULL = -1, ///< All TX message objects busy CAN_RXBUF_EMPTY = -2, ///< All RX message objects busy CAN_ILLEGAL_MOB = -3, ///< Message object index out of range CAN_INVALID_SPEED = -4, ///< Invalid baud rate parameter};#define RX_MOB 8#ifndef CAN_BUF_SIZE# define CAN_BUF_SIZE 64#endif/***************************************************************************** * CAN baud rate table * * Sampling point is 75%, SJW = 1 *****************************************************************************///// 12.00 MHz//#if NUT_CPU_FREQ == 12000000// 10 kbit/s - brp=59 bits=20 Tprs=8 Tph1=6 Tph2=5 Tsjw=1#define CAN_BT1_10K 0x76#define CAN_BT2_10K 0x0E#define CAN_BT3_10K 0x4B// 20 kbit/s - brp=29 bits=20 Tprs=8 Tph1=6 Tph2=5 Tsjw=1#define CAN_BT1_20K 0x3A#define CAN_BT2_20K 0x0E#define CAN_BT3_20K 0x4B// 50 kbit/s - brp=19 bits=12 Tprs=5 Tph1=3 Tph2=3 Tsjw=1#define CAN_BT1_50K 0x26#define CAN_BT2_50K 0x08#define CAN_BT3_50K 0x25// 100 kbit/s - brp=9 bits=12 Tprs=5 Tph1=3 Tph2=3 Tsjw=1#define CAN_BT1_100K 0x12#define CAN_BT2_100K 0x08#define CAN_BT3_100K 0x25// 125 kbit/s - brp=5 bits=16 Tprs=7 Tph1=4 Tph2=4 Tsjw=1#define CAN_BT1_125K 0x0A#define CAN_BT2_125K 0x0C#define CAN_BT3_125K 0x37// 250 kbit/s - brp=2 bits=16 Tprs=7 Tph1=4 Tph2=4 Tsjw=1#define CAN_BT1_250K 0x04#define CAN_BT2_250K 0x0C#define CAN_BT3_250K 0x37// 500 kbit/s - brp=1 bits=12 Tprs=5 Tph1=3 Tph2=3 Tsjw=1#define CAN_BT1_500K 0x02#define CAN_BT2_500K 0x08#define CAN_BT3_500K 0x25// 800 kbit/s - brp=0 bits=15 Tprs=8 Tph1=3 Tph2=3 Tsjw=1#define CAN_BT1_800K 0x00#define CAN_BT2_800K 0x0E#define CAN_BT3_800K 0x25// 1000 kbit/s - brp=0 bits=12 Tprs=5 Tph1=3 Tph2=3 Tsjw=1#define CAN_BT1_1M 0x00#define CAN_BT2_1M 0x08#define CAN_BT3_1M 0x25//// 16.00 MHz//#elif NUT_CPU_FREQ == 16000000// 10 kbit/s - brp=63 bits=25 Tprs=8 Tph1=10 Tph2=6 Tsjw=1#define CAN_BT1_10K 0x7E#define CAN_BT2_10K 0x0E#define CAN_BT3_10K 0x53// 20 kbit/s - brp=39 bits=20 Tprs=8 Tph1=6 Tph2=5 Tsjw=1#define CAN_BT1_20K 0x4E#define CAN_BT2_20K 0x0E#define CAN_BT3_20K 0x4B// 50 kbit/s - brp=19 bits=16 Tprs=7 Tph1=4 Tph2=4 Tsjw=1#define CAN_BT1_50K 0x26#define CAN_BT2_50K 0x0C#define CAN_BT3_50K 0x37// 100 kbit/s - brp=9 bits=16 Tprs=7 Tph1=4 Tph2=4 Tsjw=1#define CAN_BT1_100K 0x12#define CAN_BT2_100K 0x0C#define CAN_BT3_100K 0x37// 125 kbit/s - brp=7 bits=16 Tprs=7 Tph1=4 Tph2=4 Tsjw=1#define CAN_BT1_125K 0x0E#define CAN_BT2_125K 0x0C#define CAN_BT3_125K 0x37// 250 kbit/s - brp=3 bits=16 Tprs=7 Tph1=4 Tph2=4 Tsjw=1#define CAN_BT1_250K 0x06#define CAN_BT2_250K 0x0C#define CAN_BT3_250K 0x37// 500 kbit/s - brp=1 bits=16 Tprs=7 Tph1=4 Tph2=4 Tsjw=1#define CAN_BT1_500K 0x02#define CAN_BT2_500K 0x0C#define CAN_BT3_500K 0x37// 800 kbit/s - brp=0 bits=20 Tprs=8 Tph1=6 Tph2=5 Tsjw=1#define CAN_BT1_800K 0x00#define CAN_BT2_800K 0x0E#define CAN_BT3_800K 0x4B// 1000 kbit/s - brp=0 bits=16 Tprs=7 Tph1=4 Tph2=4 Tsjw=1#define CAN_BT1_1M 0x00#define CAN_BT2_1M 0x0C#define CAN_BT3_1M 0x37#else# error Frequency not supported or not set to a Fixed MCU clock!#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 *****************************************************************************/CANBuffer canRxBuf;CANINFO dcb_atcan;IFCAN ifc_atcan;NUTDEVICE devAtCan;/***************************************************************************** * Low level functions *****************************************************************************//** * @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 < MAX_NO_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. * * @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 < MAX_NO_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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -