182 lines
7.2 KiB
C++
182 lines
7.2 KiB
C++
#include <HardwareCAN.h>
|
|
#include "changes.h"
|
|
/*
|
|
* Example of use of the HardwareCAN library
|
|
* This application receives two frames containing various data. It also produces data that are sent periodically using another two frames.
|
|
* Please read the file changes.h to see the changes to be performed to the core in order to use this
|
|
*/
|
|
// Define the values of the identifiers
|
|
#define GYRO_ID 0x27
|
|
#define JOYSTICK_VALUES_ID 0x5A
|
|
#define TANK_LEVEL_ID 0x78
|
|
#define MOTOR_CONTROL_ID 0x92
|
|
|
|
// Limit time to flag a CAN error
|
|
#define CAN_TIMEOUT 100
|
|
#define CAN_DELAY 10 // ms between two processings of incoming messages
|
|
#define CAN_SEND_RATE 200 // ms between two successive sendings
|
|
|
|
// Message structures. Each message has its own identifier. As many such variables should be defined
|
|
// as the number of different CAN frames the application has to send. Here, they are two.
|
|
CanMsg msgGyroscope ;
|
|
CanMsg msgMotorControl ;
|
|
|
|
// Traffic handling data
|
|
int CANquietTime ; // Quiet time counter to detect no activity on CAN bus
|
|
bool CANError ; // Indicates that incoming CAN traffic is missing
|
|
int CANsendDivider ; // Used to send frames once every so many times loop() is called
|
|
|
|
// Applicaton variables
|
|
int Contents[4] ; // Contents of the four tanks
|
|
int JoystickX ; // Setting of the joystick, X axis
|
|
int JoystickY ; // ... Y axis
|
|
int AngularRate ; // Output of local gyroscope
|
|
int Throttle ; // Motor control value, produced by some local processing
|
|
bool ErreurGyroscope = false ;
|
|
|
|
// Instanciation of CAN interface
|
|
HardwareCAN canBus(CAN1_BASE);
|
|
|
|
|
|
// Note : for the predefined identifiers, please have a look in file can.h
|
|
|
|
void CANSetup(void)
|
|
{
|
|
CAN_STATUS Stat ;
|
|
|
|
// Initialize the message structures
|
|
// A CAN structure includes the following fields:
|
|
msgGyroscope.IDE = CAN_ID_STD; // Indicates a standard identifier ; CAN_ID_EXT would mean this frame uses an extended identifier
|
|
msgGyroscope.RTR = CAN_RTR_DATA; // Indicated this is a data frame, as opposed to a remote frame (would then be CAN_RTR_REMOTE)
|
|
msgGyroscope.ID = GYRO_ID ; // Identifier of the frame : 0-2047 (0-0x3ff) for standard idenfiers; 0-0x1fffffff for extended identifiers
|
|
msgGyroscope.DLC = 3; // Number of data bytes to follow
|
|
msgGyroscope.Data[0] = 0x0; // Data bytes, there can be 0 to 8 bytes.
|
|
msgGyroscope.Data[1] = 0x0;
|
|
msgGyroscope.Data[2] = 0x0;
|
|
|
|
msgMotorControl.IDE = CAN_ID_STD;
|
|
msgMotorControl.RTR = CAN_RTR_DATA;
|
|
msgMotorControl.ID = MOTOR_CONTROL_ID ;
|
|
msgMotorControl.DLC = 2;
|
|
msgMotorControl.Data[0] = 0x0;
|
|
msgMotorControl.Data[1] = 0x0;
|
|
|
|
// Initialize CAN module
|
|
canBus.map(CAN_GPIO_PB8_PB9); // This setting is already wired in the Olimexino-STM32 board
|
|
Stat = canBus.begin(CAN_SPEED_125, CAN_MODE_NORMAL); // Other speeds go from 125 kbps to 1000 kbps. CAN allows even more choices.
|
|
|
|
canBus.filter(0, 0, 0);
|
|
canBus.set_irq_mode(); // Use irq mode (recommended), so the handling of incoming messages
|
|
// will be performed at ease in a task or in the loop. The software fifo is 16 cells long,
|
|
// allowing at least 15 ms before processing the fifo is needed at 125 kbps
|
|
Stat = canBus.status();
|
|
if (Stat != CAN_OK)
|
|
/* Your own error processing here */ ; // Initialization failed
|
|
}
|
|
|
|
// Send one frame. Parameter is a pointer to a frame structure (above), that has previously been updated with data.
|
|
// If no mailbox is available, wait until one becomes empty. There are 3 mailboxes.
|
|
CAN_TX_MBX CANsend(CanMsg *pmsg)
|
|
{
|
|
CAN_TX_MBX mbx;
|
|
|
|
do
|
|
{
|
|
mbx = canBus.send(pmsg) ;
|
|
#ifdef USE_MULTITASK
|
|
vTaskDelay( 1 ) ; // Infinite loops are not multitasking-friendly
|
|
#endif
|
|
}
|
|
while(mbx == CAN_TX_NO_MBX) ; // Waiting outbound frames will eventually be sent, unless there is a CAN bus failure.
|
|
return mbx ;
|
|
}
|
|
|
|
// Process incoming messages
|
|
// Note : frames are not fully checked for correctness: DLC value is not checked, neither are the IDE and RTR fields. However, the data is guaranteed to be corrrect.
|
|
void ProcessMessages(void)
|
|
{
|
|
int Pr = 0 ;
|
|
int i ;
|
|
|
|
CanMsg *r_msg;
|
|
|
|
// Loop for every message in the fifo
|
|
while ((r_msg = canBus.recv()) != NULL)
|
|
{
|
|
CANquietTime = 0 ; // Reset at each received frame
|
|
CANError = false ; // Clear CAN silence error
|
|
switch ( r_msg->ID )
|
|
{
|
|
case TANK_LEVEL_ID : // This frame contains four 16-bit words, little endian coded
|
|
for ( i = 0 ; i < 4 ; i++ )
|
|
Contents[i] = (int)r_msg->Data[2*i] | ((int)r_msg->Data[(2*i)+1]) << 8 ;
|
|
break ;
|
|
|
|
case JOYSTICK_VALUES_ID : // This frame contains two 16-bit words, little endian coded
|
|
Pr = (int)r_msg->Data[0] ;
|
|
Pr |= (int)r_msg->Data[1] << 8 ;
|
|
JoystickX = Pr ;
|
|
|
|
Pr = (int)r_msg->Data[2] ;
|
|
Pr |= (int)r_msg->Data[3] << 8 ;
|
|
JoystickY = Pr ;
|
|
break ;
|
|
|
|
default : // Any frame with a different identifier is ignored
|
|
break ;
|
|
}
|
|
|
|
canBus.free(); // Remove processed message from buffer, whatever the identifier
|
|
#ifdef USE_MULTITASK
|
|
vTaskDelay( 1 ) ; // Infinite loops are not multitasking-friendly
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Send messages
|
|
// Prepare and send 2 frames containing the value of process variables
|
|
// Sending all frames at once is a choice; they could be sent separately, at different times and rates.
|
|
void SendCANmessages(void)
|
|
{
|
|
// Prepare Gyroscope frame : send angular rate
|
|
msgGyroscope.Data[0] = AngularRate & 0xff ;
|
|
msgGyroscope.Data[1] = ( AngularRate >> 8 ) & 0xff ;
|
|
msgGyroscope.Data[2] = ErreurGyroscope ? 1 : 0 ;
|
|
CANsend(&msgGyroscope) ; // Send this frame
|
|
|
|
msgMotorControl.Data[0] = Throttle & 0xff ;
|
|
msgMotorControl.Data[1] = ( Throttle >> 8 ) & 0xff ;
|
|
CANsend(&msgMotorControl) ;
|
|
}
|
|
|
|
// The application program starts here
|
|
void setup() {
|
|
// put your setup code here, to run once:
|
|
CANSetup() ; // Initialize the CAN module and prepare the message structures.
|
|
}
|
|
|
|
void loop() {
|
|
// Process incoming messages periodically (should be often enough to avoid overflowing the fifo)
|
|
ProcessMessages() ; // Process all incoming messages, update local variables accordingly
|
|
|
|
// This is an example of timeout management. Here it is global to all received frames;
|
|
// it could be on a frame by frame basis, with as many control variables as the number of frames.
|
|
CANquietTime++ ;
|
|
if ( CANquietTime > CAN_TIMEOUT )
|
|
{
|
|
CANquietTime = CAN_TIMEOUT + 1 ; // To prevent overflowing this variable if silence prolongs...
|
|
CANError = true ; // Flag CAN silence error. Will be cleared at first frame received
|
|
}
|
|
|
|
// Send messages containing variables to publish. Sent less frequently than the processing of incoming frames (here, every 200 ms)
|
|
CANsendDivider-- ;
|
|
if ( CANsendDivider < 0 )
|
|
{
|
|
CANsendDivider = CAN_SEND_RATE / CAN_DELAY ;
|
|
SendCANmessages() ;
|
|
}
|
|
delay(CAN_DELAY) ; // The delay must not be greater than the time to overflow the incoming fifo (here about 15 ms)
|
|
}
|
|
|
|
|