⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sja1000.c

📁 三星2440 ARM CAN总线驱动 源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// sja1000.c
//
// Copyright (C) 2002-2004 Ake Hedman, eurosource, akhe@eurosource.se
//
// This software is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// parts from code written by Ake Hedman, CC Systems AB
// parts derived from code written by Arnaud Westenberg 
// arnaud@wanadoo.nl and his can drive and
// Version 0.6.1 T.Motylewski@bfad.de 13.03.2001

#include <iom161.h>
#include <io.h>
#include "uart.h"
#include "sja1000.h"
#include <sig-avr.h>
#include <interrupt.h>
#include <string.h>
#include <stdlib.h>

extern u32 ustime; 

// CAN received buffer
static canmsg_t  can_rx_buffer[ CAN_RX_BUFFER_SIZE ];
static uint16_t can_rx_insert_idx, can_rx_extract_idx;

// CAN transmitt buffer
static canmsg_t  can_tx_buffer[ CAN_TX_BUFFER_SIZE ];
static uint16_t can_tx_insert_idx, can_tx_extract_idx;

// CAN statistics
static canstatistics_t canstat;

//////////////////////////////////////////////////////////////////////
// sja1000_enable_IRQ
//

void sja1000_enableIRQ( void )
{
#define  ENABLE_CAN_IRQ   
  REG( SJAIER ) = ( ( 1 << IER_BEIE ) | 
		    ( 1 << IER_EPIE ) | 
		    ( 1 << IER_DOIE ) | 
		    ( 1 << IER_EIE ) | 
		    ( 1 << IER_TIE ) | 
		    ( 1 << IER_RIE ) );
  
  // Enable INT0
  outp( inp( GIMSK ) | ( 1 << INT0 ) , GIMSK );
}

//////////////////////////////////////////////////////////////////////
// sja1000_disableIRQ
//

void sja1000_disableIRQ( void )
{
  REG( SJAIER ) = 0;
  
  // Disable INT0
  outp( inp( GIMSK ) & ~(1 << INT0) , GIMSK );
}

//////////////////////////////////////////////////////////////////////
// sja1000_enable_Config
//

int sja1000_enableConfig( void )
{
  // Disable CAN interrupts
  sja1000_disableIRQ();

  // Set Reset Mode
  while( !( REG( SJAMOD ) & ( 1 << MOD_RM ) ) ) {
    REG( SJAMOD ) = ( 1 << MOD_RM );
  }
 
  // We are in reset mode
  return TRUE;
}

//////////////////////////////////////////////////////////////////////
// sja1000_disableConfig
//

int sja1000_disableConfig( void )
{
  // Set Reset Mode
  while( ( REG( SJAMOD ) & ( 1 << MOD_RM ) ) ) {
    REG( SJAMOD ) = 0;
  }

  // Enable CAN interrupts
  sja1000_enableIRQ();

  // We are out of reset mode
  return TRUE;
}

//////////////////////////////////////////////////////////////////////
// sja1000_init
//

int sja1000_init( void )
{
  // Buffer initialization
  can_rx_insert_idx = can_rx_extract_idx = 0;
  can_tx_insert_idx = can_tx_extract_idx = 0;

  // Reset statistics
  canstat.cntRxPkt = 0;      // Counter for received packets.
  canstat.cntRxData = 0;     // Counter for received data bytes.
  canstat.cntTxPkt = 0;      // Counter for sent packets.
  canstat.cntTxData = 0;     // Counter for sent data bytes.
  canstat.cntWakeup = 0;     // Counter for chip wakeup's
  canstat.cntWarnings = 0;   // Counter for chip warning states.
  canstat.cntBusOff = 0;     // Counter for chip bus off conditions.
  canstat.cntRxFifoOvr = 0;  // Counter for Rx FIFO overruns.
  canstat.cntTxFifoOvr = 0;  // Counter for transmitter overruns (if NONBLOCK).
  canstat.cntStuffErr = 0;   // Counter for stuff errors.
  canstat.cntFormErr = 0;    // Counter for form erros.
  canstat.cntAckErr = 0;     // Counter for ACK errors.
  canstat.cntBit0Err = 0;    // Counter for Bit 0 errors.
  canstat.cntBit1Err = 0;    // Counter for Bit 1 errors.
  canstat.cntCrcErr = 0;     // Counter for CRC errors.

  // Enable configuration
  if ( !sja1000_enableConfig() ) return FALSE;

  // Set Mode, Clock out, comparator
  // 16 MHz / 2 = 8 MHz 
  REG( SJACDR ) = ( 1 << CDR_PELICAN );
 
  // Set driver output configuration
  // - Normal Mode 
  REG( SJAOCR ) = 0xde; 
  
  // Null mask
  if ( !sja1000_setExtendedMask( 0x00000000, 0xffffffff ) ) return FALSE;

  // Set baudrate
  if ( !sja1000_setBaudrate( INIT_VALUE_BAUDRATE, 
			     INIT_VALUE_CRYSTAL, 
			     0,       // sjw
			     75,      // sample point
			     0 ) ) {  // flags
    return FALSE;
  }

  // Enable CAN interrupts
  sja1000_enableIRQ();

  // Release receive buffer
  // Clear data overrun
  REG( SJACMR ) = ( 1 << CMR_CDO ) | ( 1 << CMR_RRB );

  // Disable CAN configuration
  if ( !sja1000_disableConfig() ) return FALSE;

  return TRUE;
}

//////////////////////////////////////////////////////////////////////
// sja1000_setExtendedMask
//
// Must be in RESET mode
//

int sja1000_setExtendedMask( u32 code, u32 mask )
{
  int i;

  // LSB to +3, MSB to +0
  for ( i = SJA_PeliCAN_AC_LEN; --i>= 0; ) {
    REG( SJAACR0 + i ) = ( code & 0xff ); 
    REG( SJAAMR0 + i ) = ( mask & 0xff );
    code >>= 8;
    mask >>= 8;
  }
  
  return TRUE;
}

//////////////////////////////////////////////////////////////////////
// sja1000_setBaudrate
//
// Must be in RESET mode
//

int sja1000_setBaudrate( u32 rate,
			 u32 clock,
			 u32 sjw,
			 u32 sampl_pt,
			 u32 flags )
{
  int best_error = 0xfff;  // Big error
  int error;
  int best_tseg = 0;
  int best_brp = 0;
  int best_rate = 0;
  int brp = 0;
  int tseg = 0;
  int tseg1 = 0;
  int tseg2 = 0;

  clock /= 2;

  // tseg even = round down
  // tseg odd = round up
  for ( tseg = ( ( 0 + 0 + 2 ) * 2 ); 
	tseg <= ( ( MAX_TSEG2 + MAX_TSEG1 + 2 ) * 2 + 1 );
	tseg++ ) {
    
    brp = clock / ( ( 1 + tseg/2 ) * rate ) + ( tseg % 2 );
    
    if ( brp == 0 || brp > 64 ) continue;
    
    error = rate - clock/( brp * ( 1 + tseg / 2 ) );
    
    if ( error < 0 ) error = -error;
    
    if ( error <= best_error ) {
      best_error = error;
      best_tseg = tseg/2;
      best_brp = brp-1;
      best_rate = clock/( brp * ( 1 + tseg/2 ) );
    }
  }

  if ( best_error && ( rate/best_error < 10 ) ) {
    // This baudrate is not possible with this clock
    return FALSE;
  }

  tseg2 = best_tseg - ( sampl_pt * ( best_tseg + 1 ) ) / 100;

  if ( tseg2 < 0 ) tseg2 = 0;

  if ( tseg2 > MAX_TSEG2 ) tseg2 = MAX_TSEG2;

  tseg1 = best_tseg - tseg2 - 2;

  if ( tseg1 > MAX_TSEG1 ) {
    tseg1 = MAX_TSEG1;
    tseg2 = best_tseg - tseg1 - 2;
  }

  // Set the baudrate
  REG( SJABTR0 ) = ( ( sjw << 6 ) | best_brp ); 
  REG( SJABTR1 ) =
    ( ( ( ( flags & BTR1_SAM ) != 0 ) << 7 ) | ( tseg2 << 4 ) | tseg1 ); 
  
  return TRUE;
}

//////////////////////////////////////////////////////////////////////
// sja1000_readMsg
//

void sja1000_readMsg( void )
{
  int i, len;
  uint16_t reg_datastart;   // Regstart for data part of message
  canmsg_t *pmsg = NULL;
  uint16_t temp;
  
  do { 
    // Put the message in the receive fifo if there is
    // a message and there is room for the message
    temp = ( can_rx_insert_idx + 1 ) % CAN_RX_BUFFER_SIZE;
    
    if ( temp != can_rx_extract_idx ) {

      // add message to queue
      pmsg = (canmsg_t *)( (unsigned char *)can_rx_buffer + 
			   can_rx_insert_idx * 
			   sizeof( canmsg_t ) );

      // timestamp
      pmsg->timestamp = ustime + inp( TCNT0 ); 

      if ( REG( SJAFRM ) & ( 1 << FRM_FF ) ) {
	// Extended
	pmsg->id =
	  ( (u32)( REG( SJAID0 ) ) << 21 ) +
	  ( (u32)( REG( SJAID1 ) ) << 13 ) +
	  ( (u32)( REG( SJAID2 ) ) << 5 ) +
	  ( (u32)( REG( SJAID3 ) ) >> 3 );
	reg_datastart = SJADATE;
      } 
      else {
	// Standard
	pmsg->id =
	  ( (u32)( REG( SJAID0 ) ) << 3 ) +
	  ( (u32)( REG( SJAID1 ) ) >> 5 );
	reg_datastart = SJADATS;
      }
      
      // Set flags for Remote Frame, Extended
      pmsg->flags =
	( ( REG( SJAFRM ) & ( 1 << FRM_RTR ) ) ? ( 1 << MSG_RTR ) : 0) |
	( ( REG( SJAFRM )& ( 1 << FRM_FF ) ) ? ( 1 << MSG_EXT ) : 0);
      
      // Set message LEN
      len = ( REG( SJAFRM ) & FRM_DLC_M );
      
      // Get data
      for ( i=0; i < len; i++ ) {
	pmsg->data[ i ] = REG( reg_datastart + i );
      }

      pmsg->length = len;

      // Update buffer pointer
      can_rx_insert_idx = temp;

      // Print out the message
      //print_CAN_Msg( pmsg );

      // Write statistics
      canstat.cntRxPkt++;       // Another packet received
      canstat.cntRxData += len; // +len bytes received     
    }
    else {
      // The fifo is full - Just update statistics
      canstat.cntRxFifoOvr++;
    }

    REG( SJACMR ) =  ( 1 << CMR_RRB ); // Release Receive Buffer

  } while ( REG( SJASR ) & ( 1 << SR_RBS ) ); // More messages
}

///////////////////////////////////////////////////////////////////////////////
// sja1000_prereadConfig

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -