FIX: - if a sdo transfer timeout occurres, reset the sdo line even if the callback function does not.
/*
This file is part of CanFestival, a library implementing CanOpen Stack.
Copyright (C): Edouard TISSERANT and Francis DUPIN
AVR Port: Andreas GLAUSER and 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_AVR.h"
#include "canfestival.h"
volatile unsigned char msg_received = 0;
unsigned char canInit(unsigned int bitrate)
/******************************************************************************
Initialize the hardware to receive CAN messages and start the timer for the
CANopen stack.
INPUT bitrate bitrate in kilobit
OUTPUT 1 if successful
******************************************************************************/
{
unsigned char i,k;
//- Pull-up on TxCAN & RxCAN one by one to use bit-addressing
CAN_PORT_DIR &= ~(1<<CAN_INPUT_PIN );
CAN_PORT_DIR &= ~(1<<CAN_OUTPUT_PIN);
CAN_PORT_OUT |= (1<<CAN_INPUT_PIN );
CAN_PORT_OUT |= (1<<CAN_OUTPUT_PIN);
Can_reset(); // Reset the CAN controller
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
CANBT1 = ((F_CPU/16/1000/bitrate-1) << BRP); // set bitrate
CANBT2 = ((1-1) << SJW) |((5-1) << PRS); // set SJW, PRS
CANBT3 = (((2-1) << PHS2) | ((8-1) << PHS1) | (1<<SMP)); // set PHS1, PHS2, 3 sample points
}
else
return 0;
// Reset all mailsboxes (MObs), filters are zero (accept all) by clear all MOb
// Set the lower MObs as rx buffer
for (i = 0; i < NB_MOB; i++)
{
Can_set_mob(i); // Change to MOb with the received message
Can_clear_mob(); // All MOb Registers=0
for (k = 0; k < NB_DATA_MAX; k++)
CANMSG = 0; // MOb data FIFO
if (i < NB_RX_MOB) // Is receive MOb
Can_config_rx_buffer(); // configure as receive buffer
}
// The tx MOb is still disabled, it will be set to tx mode when the first message will be sent
// Enable the general CAN interrupts
CANGIE = (1 << ENIT) | (1 << ENRX) | (1 << ENTX) | (0 << ENERR) | (0 << ENERG) | (0 << ENOVRT);
CANIE1 = 0x7F; // Enable the interrupts of all MObs (0..14)
CANIE2 = 0xFF;
Can_enable(); // Enable the CAN bus controller
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 char i;
for (i = START_TX_MOB; i < NB_MOB; i++) // Search the first free MOb
{
Can_set_mob(i); // Change to MOb
if ((CANCDMOB & CONMOB_MSK) == 0) // MOb disabled = free
{
break;
}
}
if (i < NB_MOB) // free MOb found
{
Can_set_mob(i); // Switch to the sending messagebox
Can_set_std_id(m->cob_id); // Set cob id
if (m->rtr) // Set remote transmission request
Can_set_rtr();
Can_set_dlc(m->len); // Set data lenght code
for (i= 0; i < (m->len); i++) // Add data bytes to the MOb
CANMSG = m->data[i];
// Start sending by writing the MB configuration register to transmit
Can_config_tx(); // Set the last MOb to transmit mode
return 1; // succesful
}
else
return 0; // not succesful
}
unsigned char canReceive(Message *m)
/******************************************************************************
The driver pass a received CAN message to the stack
INPUT Message *m pointer to received CAN message
OUTPUT 1 if a message received
******************************************************************************/
{
unsigned char i;
if (msg_received == 0)
return 0; // Nothing received
for (i = 0; i < NB_RX_MOB; i++) // Search the first MOb received
{
Can_set_mob(i); // Change to MOb
if ((CANCDMOB & CONMOB_MSK) == 0) // MOb disabled = received
{
msg_received--;
break;
}
}
if (i < NB_RX_MOB) // message found
{
Can_get_std_id(m->cob_id); // Get cob id
m->rtr = Can_get_rtr(); // Get remote transmission request
m->len = Can_get_dlc(); // Get data lenght code
for (i= 0; i < (m->len); i++) // get data bytes from the MOb
m->data[i] = CANMSG;
Can_config_rx_buffer(); // reset the MOb for receive
return 1; // message received
}
else // no message found
{
msg_received = 0; // reset counter
return 0; // no message received
}
}
/***************************************************************************/
unsigned char canChangeBaudRate_driver( CAN_HANDLE fd, char* baud)
{
return 0;
}
#ifdef __IAR_SYSTEMS_ICC__
#pragma type_attribute = __interrupt
#pragma vector=CANIT_vect
void CANIT_interrupt(void)
#else // GCC
ISR(CANIT_vect)
#endif // GCC
/******************************************************************************
CAN Interrupt
******************************************************************************/
{
unsigned char saved_page = CANPAGE;
unsigned char i;
if (CANGIT & (1 << CANIT)) // is a messagebox interrupt
{
if ((CANSIT1 & TX_INT_MSK) == 0) // is a Rx interrupt
{
for (i = 0; (i < NB_RX_MOB) && (CANGIT & (1 << CANIT)); i++) // Search the first MOb received
{
Can_set_mob(i); // Change to MOb
if (CANSTMOB & MOB_RX_COMPLETED) // receive ok
{
Can_clear_status_mob(); // Clear status register
Can_mob_abort(); // disable the MOb = received
msg_received++;
}
else if (CANSTMOB & ~MOB_RX_COMPLETED) // error
{
Can_clear_status_mob(); // Clear status register
Can_config_rx_buffer(); // reconfigure as receive buffer
}
}
}
else // is a Tx interrupt
{
for (i = NB_RX_MOB; i < NB_MOB; i++) // Search the first MOb transmitted
{
Can_set_mob(i); // change to MOb
if (CANSTMOB) // transmission ok or error
{
Can_clear_status_mob(); // clear status register
CANCDMOB = 0; // disable the MOb
break;
}
}
}
}
CANPAGE = saved_page;
// Bus Off Interrupt Flag
if (CANGIT & (1 << BOFFIT)) // Finaly clear the interrupt status register
{
CANGIT |= (1 << BOFFIT); // Clear the interrupt flag
}
else
CANGIT |= (1 << BXOK) | (1 << SERG) | (1 << CERG) | (1 << FERG) | (1 << AERG);// Finaly clear other interrupts
}
#ifdef __IAR_SYSTEMS_ICC__
#pragma type_attribute = __interrupt
#pragma vector=OVRIT_vect
void OVRIT_interrupt(void)
#else // GCC
ISR(OVRIT_vect)
#endif // GCC
/******************************************************************************
CAN Timer Interrupt
******************************************************************************/
{
CANGIT |= (1 << OVRTIM);
}