/*
This file is part of CanFestival, a library implementing CanOpen Stack.
Copyright (C): Edouard TISSERANT and Francis DUPIN
AT91 Port: Peter CHRISTEN
See COPYING file for copyrights details.
This library 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.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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
*/
//#define DEBUG_WAR_CONSOLE_ON
//#define DEBUG_ERR_CONSOLE_ON
#include "can_AT91.h"
#include "canfestival.h"
void can_irq_handler(void);
unsigned char canInit(unsigned int bitrate)
/******************************************************************************
Initialize the hardware to receive CAN messages and start the timer for the
CANopen stack.
INPUT
OUTPUT
******************************************************************************/
{
unsigned char i;
AT91S_CAN_MB *mb_ptr = AT91C_BASE_CAN_MB0;
// Enable CAN PIOs
AT91F_CAN_CfgPIO();
// Enable CAN Clock
AT91F_CAN_CfgPMC();
// Enable CAN Transceiver
AT91F_PIOA_CfgPMC();
// Init CAN Interrupt Source Level
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, // CAN base address
AT91C_ID_CAN, // CAN ID
AT91C_AIC_PRIOR_HIGHEST, // Max priority
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, // Level sensitive
can_irq_handler); // C Handler
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_CAN);
if (bitrate <= 500)
{
// CANopen 10..500 kbit with 16 tq, sample point is at 14 tq
// all values are added to 1 by hardware
// Resynchronisation jump width (SJW) = 1 tq
// Propagation Time Segment (PRS) = 5 tq
// Phase Segment 1 (PHS1) = 8 tq
// Phase Segment 2 (PHS2) = 2 tq
// Total = 16 tq
AT91F_CAN_CfgBaudrateReg(AT91C_BASE_CAN,
(AT91C_MASTER_CLOCK/16/1000/bitrate - 1) << 16 | 0x0471);
}
else
return 0;
// Enable CAN and Wait for WakeUp Interrupt
// AT91F_CAN_EnableIt(AT91C_BASE_CAN, AT91C_CAN_WAKEUP);
AT91F_CAN_CfgModeReg(AT91C_BASE_CAN, AT91C_CAN_CANEN);
// Reset all mailsboxes (MBs), filters are zero (accept all) by clear all MB
// Set the lower MBs as rx buffer
for (i = 0; i < NB_RX_MB; i++, mb_ptr++)
// Configure receive MBs as receive buffer, last as receive overwrite
AT91F_InitMailboxRegisters(mb_ptr,
((i < (NB_RX_MB - 1)) ? AT91C_CAN_MOT_RX : AT91C_CAN_MOT_RXOVERWRITE)
| AT91C_CAN_PRIOR, // Mailbox Mode Reg
0x00000000, // Mailbox Acceptance Mask Reg
0x00000000, // Mailbox ID Reg
0x00000000, // Mailbox Data Low Reg
0x00000000, // Mailbox Data High Reg
0x00000000); // Mailbox Control Reg
for ( ; i < NB_MB; i++, mb_ptr++)
// Configure transmit MBs
AT91F_InitMailboxRegisters(mb_ptr,
AT91C_CAN_MOT_TX
| AT91C_CAN_PRIOR, // Mailbox Mode Reg
0x00000000, // Mailbox Acceptance Mask Reg
0x00000000, // Mailbox ID Reg
0x00000000, // Mailbox Data Low Reg
0x00000000, // Mailbox Data High Reg
0x00000000); // Mailbox Control Reg
// Enable Reception on all receive Mailboxes
AT91F_CAN_InitTransferRequest(AT91C_BASE_CAN, RX_INT_MSK);
// Enable all receive interrupts
AT91F_CAN_EnableIt(AT91C_BASE_CAN, RX_INT_MSK);
return 1;
}
unsigned char canSend(CAN_PORT notused, Message *m)
/******************************************************************************
The driver send a CAN message passed from the CANopen stack
INPUT CAN_PORT is not used (only 1 avaiable)
Message *m pointer to message to send
OUTPUT 1 if hardware -> CAN frame
******************************************************************************/
{
unsigned int mask;
AT91S_CAN_MB *mb_ptr = AT91C_BASE_CAN_MB0 + START_TX_MB;
if ((AT91F_CAN_GetStatus(AT91C_BASE_CAN) & TX_INT_MSK) == 0)
return 0; // No free MB for sending
for (mask = 1 << START_TX_MB;
(mask & TX_INT_MSK) && !(AT91F_CAN_GetStatus(AT91C_BASE_CAN) & mask);
mask <<= 1, mb_ptr++) // Search the first free MB
{
}
AT91F_CAN_CfgMessageIDReg(mb_ptr, m->cob_id, 0); // Set cob id
// Mailbox Control Register, set remote transmission request and data lenght code
AT91F_CAN_CfgMessageCtrlReg(mb_ptr, m->rtr ? AT91C_CAN_MRTR : 0 | (m->len << 16));
AT91F_CAN_CfgMessageDataLow(mb_ptr, *(UNS32*)(&m->data[0]));// Mailbox Data Low Reg
AT91F_CAN_CfgMessageDataHigh(mb_ptr, *(UNS32*)(&m->data[4]));// Mailbox Data High Reg
// Start sending by writing the MB configuration register to transmit
AT91F_CAN_InitTransferRequest(AT91C_BASE_CAN, mask);
return 1; // successful
}
unsigned char canReceive(Message *m)
/******************************************************************************
The driver passes a received CAN message to the stack
INPUT Message *m pointer to received CAN message
OUTPUT 1 if a message received
******************************************************************************/
{
unsigned int mask;
AT91S_CAN_MB *mb_ptr = AT91C_BASE_CAN_MB0;
if ((AT91F_CAN_GetStatus(AT91C_BASE_CAN) & RX_INT_MSK) == 0)
return 0; // Nothing received
for (mask = 1;
(mask & RX_INT_MSK) && !(AT91F_CAN_GetStatus(AT91C_BASE_CAN) & mask);
mask <<= 1, mb_ptr++) // Search the first MB received
{
}
m->cob_id = AT91F_CAN_GetFamilyID(mb_ptr);
m->len = (AT91F_CAN_GetMessageStatus(mb_ptr) & AT91C_CAN_MDLC) >> 16;
m->rtr = (AT91F_CAN_GetMessageStatus(mb_ptr) & AT91C_CAN_MRTR) ? 1 : 0;
*(UNS32*)(&m->data[0]) = AT91F_CAN_GetMessageDataLow(mb_ptr);
*(UNS32*)(&m->data[4]) = AT91F_CAN_GetMessageDataHigh(mb_ptr);
// Enable Reception on Mailbox
AT91F_CAN_CfgMessageModeReg(mb_ptr, AT91C_CAN_MOT_RX | AT91C_CAN_PRIOR);
AT91F_CAN_InitTransferRequest(AT91C_BASE_CAN, mask);
return 1; // message received
}
/******************************************************************************
******************************* CAN INTERRUPT *******************************/
void can_irq_handler(void)
/******************************************************************************
CAN Interrupt
******************************************************************************/
{
volatile unsigned int status;
static Message m = Message_Initializer; // contain a CAN message
status = AT91F_CAN_GetStatus(AT91C_BASE_CAN) & AT91F_CAN_GetInterruptMaskStatus(AT91C_BASE_CAN);
if(status & RX_INT_MSK)
{ // Rx Interrupt
if (canReceive(&m)) // a message received
canDispatch(&ObjDict_Data, &m); // process it
}
}