📄 can.c
字号:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
* ----------------------------------------------------------------------------
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include <board.h>
#include <pio/pio.h>
#include <utility/trace.h>
#include <aic/aic.h>
#include "can.h"
//------------------------------------------------------------------------------
// Local definitions
//------------------------------------------------------------------------------
// CAN state
#define CAN_DISABLED 0
#define CAN_HALTED 1
#define CAN_IDLE 2
#define CAN_SENDING 3
#define CAN_RECEIVING 4
// MOT: Mailbox Object Type
#define CAN_MOT_DISABLE 0 // Mailbox is disabled
#define CAN_MOT_RECEPT 1 // Reception Mailbox
#define CAN_MOT_RECEPT_OW 2 // Reception mailbox with overwrite
#define CAN_MOT_TRANSMIT 3 // Transmit mailbox
#define CAN_MOT_CONSUMER 4 // Consumer mailbox
#define CAN_MOT_PRODUCER 5 // Producer mailbox
//------------------------------------------------------------------------------
// Local variables
//------------------------------------------------------------------------------
#if defined (PINS_CAN_TRANSCEIVER_TXD)
static const Pin pins_can_transceiver_txd[] = {PINS_CAN_TRANSCEIVER_TXD};
#endif
#if defined (PINS_CAN_TRANSCEIVER_RXD)
static const Pin pins_can_transceiver_rxd[] = {PINS_CAN_TRANSCEIVER_RXD};
#endif
static const Pin pin_can_transceiver_rs = PIN_CAN_TRANSCEIVER_RS;
#if defined (PIN_CAN_TRANSCEIVER_RXEN)
static const Pin pin_can_transceiver_rxen = PIN_CAN_TRANSCEIVER_RXEN;
#endif
static CanTransfer *pCAN0Transfer=NULL;
#ifdef AT91C_BASE_CAN1
static CanTransfer *pCAN1Transfer=NULL;
#endif
//------------------------------------------------------------------------------
// Local functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// CAN Error Detection
/// \param status error type
/// \param can_number can nulber
//------------------------------------------------------------------------------
static void CAN_ErrorHandling( unsigned int status, unsigned char can_number)
{
if( (status&AT91C_CAN_ERRA) == AT91C_CAN_ERRA) {
TRACE_ERROR("(CAN) CAN is in active Error Active mode\n\r");
}
else if( (status&AT91C_CAN_ERRP) == AT91C_CAN_ERRP) {
TRACE_ERROR("(CAN) CAN is in Error Passive mode\n\r");
}
else if( (status&AT91C_CAN_BOFF) == AT91C_CAN_BOFF) {
TRACE_ERROR("(CAN) CAN is in Buff Off mode\n\r");
// CAN reset
TRACE_ERROR("(CAN) CAN%d reset\n\r", can_number);
// CAN Controller Disable
if (can_number == 0) {
AT91C_BASE_CAN0->CAN_MR &= ~AT91C_CAN_CANEN;
// CAN Controller Enable
AT91C_BASE_CAN0->CAN_MR |= AT91C_CAN_CANEN;
}
#ifdef AT91C_BASE_CAN1
else if (can_number == 1) {
AT91C_BASE_CAN1->CAN_MR &= ~AT91C_CAN_CANEN;
// CAN Controller Enable
AT91C_BASE_CAN1->CAN_MR |= AT91C_CAN_CANEN;
}
#endif
}
// Error for Frame dataframe
// CRC error
if( (status&AT91C_CAN_CERR) == AT91C_CAN_CERR) {
TRACE_ERROR("(CAN) CRC Error\n\r");
}
// Bit-stuffing error
else if( (status&AT91C_CAN_SERR) == AT91C_CAN_SERR) {
TRACE_ERROR("(CAN) Stuffing Error\n\r");
}
// Bit error
else if( (status&AT91C_CAN_BERR) == AT91C_CAN_BERR) {
TRACE_ERROR("(CAN) Bit Error\n\r");
}
// Form error
else if( (status&AT91C_CAN_FERR) == AT91C_CAN_FERR) {
TRACE_ERROR("(CAN) Form Error\n\r");
}
// Acknowledgment error
else if( (status&AT91C_CAN_AERR) == AT91C_CAN_AERR) {
TRACE_ERROR("(CAN) Acknowledgment Error\n\r");
}
// Error interrupt handler
// Represent the current status of the CAN bus and are not latched.
// See CAN, par. Error Interrupt Handler
// AT91C_CAN_WARN
// AT91C_CAN_ERRA
}
//------------------------------------------------------------------------------
// Generic CAN Interrupt handler
/// \param can_number can nulber
//------------------------------------------------------------------------------
static void CAN_Handler( unsigned char can_number )
{
AT91PS_CAN base_can;
AT91PS_CAN_MB CAN_Mailbox;
unsigned int status;
unsigned int can_msr;
unsigned int* pCan_mcr;
unsigned int message_mode;
unsigned char numMailbox;
unsigned char state0=CAN_DISABLED;
unsigned char state1=CAN_DISABLED;
if( can_number == 0 ) {
base_can = AT91C_BASE_CAN0;
CAN_Mailbox = AT91C_BASE_CAN0_MB0;
state0 = pCAN0Transfer->state;
}
#ifdef AT91C_BASE_CAN1
else {
base_can = AT91C_BASE_CAN1;
CAN_Mailbox = AT91C_BASE_CAN1_MB0;
state1 = pCAN1Transfer->state;
}
#endif
status = (base_can->CAN_SR) & (base_can->CAN_IMR);
base_can->CAN_IDR = status;
TRACE_DEBUG("CAN0 status=0x%X\n\r", status);
if(status & AT91C_CAN_WAKEUP) {
if( can_number == 0 ) {
pCAN0Transfer->test_can = AT91C_TEST_OK;
pCAN0Transfer->state = CAN_IDLE;
}
#ifdef AT91C_BASE_CAN1
else {
pCAN1Transfer->test_can = AT91C_TEST_OK;
pCAN1Transfer->state = CAN_IDLE;
}
#endif
}
// Mailbox event ?
else if ((status&0x0000FFFF) != 0) {
TRACE_DEBUG("Mailbox event\n\r");
// Handle Mailbox interrupts
for (numMailbox = 0; numMailbox < NUM_MAILBOX_MAX; numMailbox++) {
can_msr = *(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x10+(0x20*numMailbox)));
if ((AT91C_CAN_MRDY & can_msr) == AT91C_CAN_MRDY) {
// Mailbox object type
message_mode = ((*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x00+(0x20*numMailbox))))>>24)&0x7;
TRACE_DEBUG("message_mode 0x%X\n\r", message_mode);
TRACE_DEBUG("numMailbox 0x%X\n\r", numMailbox);
if( message_mode == 0 ) {
TRACE_ERROR("Error in MOT\n\r");
}
else if( ( message_mode == CAN_MOT_RECEPT )
|| ( message_mode == CAN_MOT_RECEPT_OW )
|| ( message_mode == CAN_MOT_PRODUCER ) ) {
TRACE_DEBUG("Mailbox is in RECEPTION\n\r");
TRACE_DEBUG("Length 0x%X\n\r", (can_msr>>16)&0xF);
TRACE_DEBUG("CAN_MB_MID 0x%X\n\r", ((*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x08+(0x20*numMailbox)))&AT91C_CAN_MIDvA)>>18));
TRACE_DEBUG("can_number %d\n\r", can_number);
if( can_number == 0 ) {
//CAN_MB_MDLx
pCAN0Transfer->data_low_reg =
(*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x14+(0x20*numMailbox))));
//CAN_MB_MDHx
pCAN0Transfer->data_high_reg =
(*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x18+(0x20*numMailbox))));
pCAN0Transfer->size = (can_msr>>16)&0xF;
pCAN0Transfer->mailbox_number = numMailbox;
state0 = CAN_IDLE;
}
#ifdef AT91C_BASE_CAN1
else {
//CAN_MB_MDLx
pCAN1Transfer->data_low_reg =
(*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x14+(0x20*numMailbox))));
//CAN_MB_MDHx
pCAN1Transfer->data_high_reg =
(*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x18+(0x20*numMailbox))));
pCAN1Transfer->size = (can_msr>>16)&0xF;
pCAN1Transfer->mailbox_number = numMailbox;
state1 = CAN_IDLE;
}
#endif
// Message Data has been received
pCan_mcr = (unsigned int*)((unsigned int)CAN_Mailbox+0x1C+(0x20*numMailbox));
*pCan_mcr = AT91C_CAN_MTCR;
}
else {
TRACE_DEBUG("Mailbox is in TRANSMIT\n\r");
TRACE_DEBUG("Length 0x%X\n\r", (can_msr>>16)&0xF);
TRACE_DEBUG("can_number %d\n\r", can_number);
if( can_number == 0 ) {
state0 = CAN_IDLE;
}
else {
state1 = CAN_IDLE;
}
}
}
}
if( can_number == 0 ) {
pCAN0Transfer->state = state0;
}
#ifdef AT91C_BASE_CAN1
else {
pCAN1Transfer->state = state1;
}
#endif
}
if ((status&0xFFCF0000) != 0) {
CAN_ErrorHandling(status, 0);
}
}
//------------------------------------------------------------------------------
/// CAN 0 Interrupt handler
//------------------------------------------------------------------------------
static void CAN0_Handler(void)
{
CAN_Handler( 0 );
}
//------------------------------------------------------------------------------
/// CAN 1 Interrupt handler
//------------------------------------------------------------------------------
#if defined AT91C_BASE_CAN1
static void CAN1_Handler(void)
{
CAN_Handler( 1 );
}
#endif
//------------------------------------------------------------------------------
// Global functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Configure the corresponding mailbox
/// \param pTransfer can transfer structure
//------------------------------------------------------------------------------
void CAN_InitMailboxRegisters( CanTransfer *pTransfer )
{
AT91PS_CAN base_can;
AT91PS_CAN_MB CAN_Mailbox;
if( pTransfer->can_number == 0 ) {
base_can = AT91C_BASE_CAN0;
CAN_Mailbox = AT91C_BASE_CAN0_MB0;
}
#ifdef AT91C_BASE_CAN1
else {
base_can = AT91C_BASE_CAN1;
CAN_Mailbox = AT91C_BASE_CAN1_MB0;
}
#endif
CAN_Mailbox = (AT91PS_CAN_MB)((unsigned int)CAN_Mailbox+(unsigned int)(0x20*pTransfer->mailbox_number));
pTransfer->mailbox_in_use |= 1<<(pTransfer->mailbox_number);
// MailBox Control Register
CAN_Mailbox->CAN_MB_MCR = 0x0;
// MailBox Mode Register
CAN_Mailbox->CAN_MB_MMR = 0x00;
// CAN Message Acceptance Mask Register
CAN_Mailbox->CAN_MB_MAM = pTransfer->acceptance_mask_reg;
// MailBox ID Register
// Disable the mailbox before writing to CAN_MIDx registers
if( (pTransfer->identifier & AT91C_CAN_MIDE) == AT91C_CAN_MIDE ) {
// Extended
CAN_Mailbox->CAN_MB_MAM |= AT91C_CAN_MIDE;
}
else {
CAN_Mailbox->CAN_MB_MAM &= ~AT91C_CAN_MIDE;
}
CAN_Mailbox->CAN_MB_MID = pTransfer->identifier;
// MailBox Mode Register
CAN_Mailbox->CAN_MB_MMR = pTransfer->mode_reg;
// MailBox Data Low Register
CAN_Mailbox->CAN_MB_MDL = pTransfer->data_low_reg;
// MailBox Data High Register
CAN_Mailbox->CAN_MB_MDH = pTransfer->data_high_reg;
// MailBox Control Register
CAN_Mailbox->CAN_MB_MCR = pTransfer->control_reg;
}
//------------------------------------------------------------------------------
/// Reset the MBx
//------------------------------------------------------------------------------
void CAN_ResetAllMailbox( void )
{
unsigned char i;
#if defined (AT91C_BASE_CAN0_MB0)
CAN_ResetTransfer( pCAN0Transfer );
for( i=0; i<8; i++ ) {
pCAN0Transfer->can_number = 0;
pCAN0Transfer->mailbox_number = i;
pCAN0Transfer->mode_reg = AT91C_CAN_MOT_DIS;
pCAN0Transfer->acceptance_mask_reg = 0;
pCAN0Transfer->identifier = 0;
pCAN0Transfer->data_low_reg = 0x00000000;
pCAN0Transfer->data_high_reg = 0x00000000;
pCAN0Transfer->control_reg = 0x00000000;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -