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