📄 sja1000.c
字号:
/* * 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/ * *//*! * \file dev/sja1000.c * \brief Driver for SJA1000 CAN-Bus controller * * * The SJA1000 controller is connected to the memory bus. It's base * address and interrupt is set by NutRegisterDevice. * * Have a look to our m-can board if you have questions. *//* * $Log: sja1000.c,v $ * Revision 1.2 2005/10/24 18:02:34 haraldkipp * Fixes for ATmega103. * * Revision 1.1 2005/07/26 18:02:40 haraldkipp * Moved from dev. * * Revision 1.8 2005/05/27 14:09:56 olereinhardt * Fixed a bug in irq initialisation * * Revision 1.7 2005/01/24 21:12:04 freckle * renamed NutEventPostFromIRQ into NutEventPostFromIrq * * Revision 1.6 2005/01/21 16:49:45 freckle * Seperated calls to NutEventPostAsync between Threads and IRQs * * Revision 1.5 2004/11/12 16:27:42 olereinhardt * Added critical section around NutEventPostAsync * * Revision 1.4 2004/09/17 14:31:37 olereinhardt * Compile only if __GNUC__ defined * * Revision 1.3 2004/06/08 14:50:25 olereinhardt * Removed receive thread and moved input data handling into irq handler. Much faster now on reception. * * Revision 1.1 2004/06/07 15:11:49 olereinhardt * Initial checkin * *//*! * \addtogroup xgCanSJA1000 *//*@{*//* Not ported. */#ifdef __GNUC__#include <string.h>#include <sys/heap.h>#include <sys/thread.h>#include <sys/event.h>#include <sys/atom.h>#include <sys/timer.h>#include <sys/semaphore.h>#include <sys/nutconfig.h>#include <dev/irqreg.h>#include <dev/can_dev.h>#include <dev/sja1000.h>#ifndef SJA_SIGNAL#define SJA_SIGNAL sig_INTERRUPT7#endif#ifndef SJA_EICR#define SJA_EICR EICRB#endif#ifndef SJA_SIGNAL_BIT#define SJA_SIGNAL_BIT 7#endifCANINFO dcb_sja1000;volatile u_short sja_base = 0x0000;struct _CANBuffer { CANFRAME *dataptr; // the physical memory address where the buffer is stored u_short size; // the allocated size of the buffer u_short datalength; // the length of the data currently in the buffer u_short dataindex; // the index into the buffer where the data starts SEM empty; SEM full;};typedef struct _CANBuffer CANBuffer;#ifndef CAN_BufSize#define CAN_BufSize 64#endifCANBuffer CAN_RX_BUF;CANBuffer CAN_TX_BUF;void CANBufferInit(CANBuffer * buffer,u_short size){ NutSemInit(&buffer->full, 0); NutSemInit(&buffer->empty, CAN_BufSize - 1); // set start pointer of the buffer buffer->dataptr = NutHeapAlloc(size * sizeof(CANFRAME)); buffer->size = size; // initialize index and length buffer->dataindex = 0; buffer->datalength = 0;}// access routinesCANFRAME CANBufferGetMutex(CANBuffer * buffer){ CANFRAME data; NutSemWait(&buffer->full);// NutSemWait(&buffer->mutex); // check to see if there's data in the buffer if (buffer->datalength) { // get the first frame from buffer data = buffer->dataptr[buffer->dataindex]; // move index down and decrement length buffer->dataindex++; if (buffer->dataindex >= buffer->size) { buffer->dataindex %= buffer->size; } buffer->datalength--; }// NutSemPost(&buffer->mutex); NutSemPost(&buffer->empty); // return return data;}void CANBufferPutMutex(CANBuffer * buffer, CANFRAME * data){ NutSemWait(&buffer->empty);// NutSemWait(&buffer->mutex); // make sure the buffer has room if (buffer->datalength < buffer->size) { // save frame at end of buffer buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = *data; // increment the length buffer->datalength++; // return success }// NutSemPost(&buffer->mutex); NutSemPost(&buffer->full);}CANFRAME CANBufferGet(CANBuffer * buffer){ CANFRAME data; // check to see if there's data in the buffer if (buffer->datalength) { // get the first frame from buffer data = buffer->dataptr[buffer->dataindex]; // move index down and decrement length buffer->dataindex++; if (buffer->dataindex >= buffer->size) { buffer->dataindex %= buffer->size; } buffer->datalength--; } // return return data;}void CANBufferPut(CANBuffer * buffer, CANFRAME * data){ // make sure the buffer has room if (buffer->datalength < buffer->size) { // save frame at end of buffer buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = *data; // increment the length buffer->datalength++; // return success }}u_short CANBufferFree(CANBuffer * buffer){ // check to see if the buffer has room // return true if there is room return (buffer->size - buffer->datalength);}/*! * \fn SJARxAvail(NUTDEVICE * dev) * \brief checks if data is available in input buffer * * \param dev Pointer to the device structure */inline u_char SJARxAvail(NUTDEVICE * dev){ return CAN_RX_BUF.datalength;}/*! * \fn SJATxAvail(NUTDEVICE * dev) * \brief checks if there's still space in output buffer * * \param dev Pointer to the device structure */inline u_char SJATxFree(NUTDEVICE * dev){ return CANBufferFree(&CAN_TX_BUF);}/*! * \fn SJAOutput(NUTDEVICE * dev, CANFRAME * frame) * \brief 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 SJAOutput(NUTDEVICE * dev, CANFRAME * frame){ CANINFO *ci; ci = (CANINFO *) dev->dev_dcb; CANBufferPutMutex(&CAN_TX_BUF, frame); NutEventPostAsync(&ci->can_tx_rdy);}/*! * \fn SJAInput(NUTDEVICE * dev, CANFRAME * frame) * \brief 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. * * \param dev Pointer to the device structure * * \param frame Pointer to the receive frame */void SJAInput(NUTDEVICE * dev, CANFRAME * frame){ u_char ready = 0; CANINFO *ci; ci = (CANINFO *) dev->dev_dcb; while (!ready) { if (CAN_RX_BUF.datalength==0) NutEventWait(&ci->can_rx_rdy, NUT_WAIT_INFINITE); NutEnterCritical(); if (CAN_RX_BUF.datalength) { *frame = CANBufferGet(&CAN_RX_BUF); ready = 1; } NutExitCritical(); } SJA1000_IEN |= (RIE_Bit); // enables IRQ since buffer has space}/*! * \fn SJASetAccCode(NUTDEVICE * dev, u_char * ac) * \brief Sets the acceptance code * * * \param dev Pointer to the device structure * * \param ac 4 byte char array with the acceptance code */void SJASetAccCode(NUTDEVICE * dev, u_char * ac){ memcpy(((IFCAN *) (dev->dev_icb))->can_acc_code, ac, 4); while ((SJA1000_MODECTRL & RM_RR_Bit) == 0x00) // enter reset state SJA1000_MODECTRL = (RM_RR_Bit | SJA1000_MODECTRL); SJA1000_AC0 = ac[0]; SJA1000_AC1 = ac[1]; SJA1000_AC2 = ac[2]; SJA1000_AC3 = ac[3]; SJA1000_MODECTRL = (AFM_Bit); //*** Note - if you change SJA1000_MODECTRL, change it in // functions CAN_Init and CAN_SetAccMask also. do { SJA1000_MODECTRL = 0x00; } while ((SJA1000_MODECTRL & RM_RR_Bit) != 0x00); // leave reset state}/*! * \fn SJASetAccMask(NUTDEVICE * dev, u_char * am) * \brief Sets the acceptance mask * * * \param dev Pointer to the device structure * * \param am 4 byte char array with the acceptance mask */void SJASetAccMask(NUTDEVICE * dev, u_char * am){ memcpy(((IFCAN *) (dev->dev_icb))->can_acc_mask, am, 4); while ((SJA1000_MODECTRL & RM_RR_Bit) == 0x00) // enter reset state SJA1000_MODECTRL = (RM_RR_Bit | SJA1000_MODECTRL); SJA1000_AM0 = am[0]; SJA1000_AM1 = am[1]; // mask off lower nibble (SJA manual p44) SJA1000_AM2 = am[2]; SJA1000_AM3 = am[3]; SJA1000_MODECTRL = (AFM_Bit); //*** Note - if you change SJA1000_MODECTRL, change it in // functions CAN_Init and CAN_SetAccCode also. do { SJA1000_MODECTRL = 0x00; } while ((SJA1000_MODECTRL & RM_RR_Bit) != 0x00); // leave reset state}/*! * \fn SJASetBaudrate(NUTDEVICE * dev, u_long baudrate) * \brief Sets the baudrate * * * \param dev Pointer to the device structure * * \param baudrate Baudrate (One of the defined baudrates. See sja1000.h) */u_char SJASetBaudrate(NUTDEVICE * dev, u_long baudrate){ u_char result = 0; ((IFCAN *) (dev->dev_icb))->can_baudrate = baudrate; while ((SJA1000_MODECTRL & RM_RR_Bit) == 0x00) // enter reset state SJA1000_MODECTRL = (RM_RR_Bit | SJA1000_MODECTRL); switch (baudrate) // setting actual bustiming { // all @ 16 Mhz case CAN_SPEED_10K: SJA1000_BT0 = 113; SJA1000_BT1 = 28; break; case CAN_SPEED_20K: SJA1000_BT0 = 88; SJA1000_BT1 = 28; break; case CAN_SPEED_50K:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -