Skip to content

Latest commit

 

History

History
240 lines (208 loc) · 8.02 KB

README.md

File metadata and controls

240 lines (208 loc) · 8.02 KB

CAN Triple 1.0 Documentation

The CAN Triple is designed to simplify the scope of interfacing multiple CAN Buses with a small form factor for Automotive Environments. Offers an Efficient and lightweight way to manage traffic among 3 CAN 2.0 Networks. Nearly all code should be written in the *user_code.c* file. Programming is completed by using a STlink V3 Debugger.

Prerequisites

Value Added Extensions within VS Code

  • Teleplot : A plotting tool for UART messages
  • Serial Monitor : Easy to use Serial Monitor

Code Function Calls for user_code.c

Setting CAN Bitrate :

uint8_t setCANBitrate(uint8_t bus, uint32_t mainBitrate)
Sets CANbus Bitrate

Parameters:
busCAN_1, CAN_2, and/or CAN_3.
mainBitrateBitrate of CANbus in bits per second.

Returns:
0 if no errors.

Setting internal 120 Ω Termination Resistor for CAN Bus(es) :

uint8_t setCAN_Termination(uint8_t bus, bool activated)
Enable or Disable CAN Termination across CANbuses

Parameters:
busCAN_1, CAN_2, and/or CAN_3.

Returns:
0 if no errors

Starting CAN Bus(es) :

uint8_t startCANbus(uint8_t bus)
Starts CANbus

Parameters:
busCAN_1, CAN_2, and/or CAN_3.

Returns:
0 if no errors.

Stopping CAN Bus(es) :

uint8_t stopCANbus(uint8_t bus)
Stops CANbus Bitrate

Parameters:
busCAN_1, CAN_2, and/or CAN_3.

Returns:
0 if no errors.

Sending a CAN Message :

uint8_t send_message(uint8_t bus, bool is_extended_id, uint32_t arbitration_id, uint8_t dlc, uint8_t *data)
Sends message to Queue to be pushed to the CANbus

Parameters:
busCAN_1, CAN_2, and/or CAN_3.
is_extended_idTrue or False.
arbitration_idMessage ID.
dlcData Length.
dataMessage data (8 Bytes).

Returns:
0 if no errors.

Turning GPIO LED on/off :

void writeLED(uint8_t led_enum, bool high)
Writes OnBoard LED

Parameters:
led_enumLED_1.
highBoolean.

Returns:
0 if no errors.

Toggling GPIO LED :

void toggleLED(uint8_t led_enum)
Toggles OnBoard LED

Parameters:
led_enumLED_1.

Returns:
0 if no errors.

Managing Received CAN Messages :

void onReceive(CAN_Message)
Handles the receipt of a CAN message. This function is called when a new CAN message is received.

Parameters:
MessageThe CAN message that was received.
typedef struct {
    uint8_t Bus;             /**< ID of the CAN bus the message is associated with. */
    bool is_extended_id;     /**< True if using an extended ID, false if using a standard ID. */
    uint32_t arbitration_id; /**< The identifier for the message, either standard or extended based on is_extended_id. */
    uint8_t dlc;             /**< Data length code, the number of valid bytes in the data field. */
    uint8_t data[8];         /**< Data payload of the CAN message. */
} CAN_Message;

// we'll define the CAN_Message and call each field using the [dot] operator.
// eg, for which bus the message came from, use Message.Bus 

Processing Received CAN Data..

There's a few functions to help process incoming CAN Message data to convert it to it's apppropriate data type. There's a few things to consider though.

If: The signal has ANY Decimal places, it will need to be stored as a float or double.

If: The signal is NOT a float or double, {AND} CAN hold a negative value at ANY time, it will need to be stored as a signed integer.

All other data can be stored as an unsigned integer.

Storing signals as a float

float process_float_value(uint32_t value, uint32_t bitmask, bool is_signed, float factor, float offset, uint8_t decimal_places);

//Input a value, bitmask, the is_signed Boolean, a factor, and offset and return a floating point. 

Lets assume the Engine speed is an unsigned 16 bit or 2 byte Big Endian CAN Signal on Bus 1 and Message ID 0x123 and is the first 2 bytes(indexes 0 and 1) of the Data field. It has a factor of 0.125 and an offset of 0 and we want to constrain to 3 decimal places. The code could be setup the following way.

float engine_Speed = 0;
onReceive(CAN_Message Message){
	if (Message.Bus == CAN_1){
        if (Message.arbitration_id == 0x123){
            // generic variable to hold the data bytes needed for the process
            uint32_t message_info = (Message.data[0]<< 8)| (Message.data[1]);
            engine_speed = process_float_value(message_info, 0xFFFF,false,0.125,0,3);
        }
    }
}

Storing signals an integer

int32_t process_int_value(uint32_t value, uint32_t bitmask, bool is_signed, int32_t factor, int32_t offset);

Lets assume the Engine Coolant Temp is an unsigned 10 bit Little Endian CAN Signal on Bus 1 and Message ID 0x124 and is the all 8 bits of the 3rd byte(index 2), and 2 bits of the 4th byte(index 3) of the Data field. It has a factor of 1 and an offset of -40. The code could be setup the following way.

int32_t engine_coolant_temp = 0;
onReceive(CAN_Message Message){
	if (Message.Bus == CAN_1){
        if (Message.arbitration_id == 0x124){
            // generic variable to hold the data bytes needed for the process
            uint32_t message_info = (Message.data[3]<< 8)| (Message.data[2]);
            engine_coolant_temp = process_int_value(message_info, 0x03FF,false,1,-40);
        }
    }
}

Storing signals an unsigned integer

uint32_t process_unsigned_int_value(uint32_t value, uint32_t bitmask, uint32_t factor, uint32_t offset);

Lets assume the Engine Oil Pressure is an unsigned 10 bit Big Endian CAN Signal on Bus 1 and Message ID 0x125 and is the all 8 bits of the 6th byte(index 5), and 2 bits of the 5th byte(index 4) of the Data field. It has a factor of 1 and an offset of 0. The code could be setup the following way.

int32_t engine_oil_pressure = 0;
onReceive(CAN_Message Message){
	if (Message.Bus == CAN_1){
        if (Message.arbitration_id == 0x125){
            // generic variable to hold the data bytes needed for the process
            uint32_t message_info = (Message.data[4]<< 8)| (Message.data[5]);
            engine_oil_pressure = process_int_value(message_info, 0x03FF,1,-40);
        }
    }
}

Simple Bitmasking and bit shifting right (if needed)

uint32_t process_raw_value(uint32_t value, uint32_t bitmask);

Lets assume you are wanting to extract a bit field for an AC switch found on CAN Bus 2 and Message ID 0x126. first byte, 5th bit [00010000]. The code could be setup the following way.

uint32_t ac_Switch = 0;
onReceive(CAN_Message Message){
	if (Message.Bus == CAN_2){
        if (Message.arbitration_id == 0x126){
            ac_switch = process_raw_value(Message.data[0], 0x10);
        }
    }
}

Rounding floats

float roundfloat(float num, uint8_t decimal_places);
//provide the number, and how many decimal places you want to round to.

Converting Floats to Decimal values with *10 factor for decimal places.

int32_t roundfloat_to_int32(float num, uint8_t decimal_places);

Value will be an integer value decimal shifted by the decimal places.

float startingvalue =  3.14159267;
int32_t endingvalue = roundfloat_to_int32(startingvalue, 4);
// endingvalue would == 31416

Debugging with print statements

Debugging using print statements is offered in a few ways. while printf is supported, it is deprecated and recommend using a char array, snprintf, and serialPrint() for your code.

float engine_Speed = 1234.567;
float vehicle_speed = 55.2;
int32_t engine_coolant_temp = 98;
char test = "Test_Message";
char debug_buffer[100];
snprintf(debug_buffer, sizeof(debug_buffer), "Engine Speed: %5.1f, Vehicle Speed:%2.1f,Coolant Temp = %i,  %s", engine_Speed, vehicle_speed,engine_coolant_temp,  test);
serialPrint(debug_buffer);
// "Engine Speed: 1234.6, Vehicle Speed:55.2,Coolant Temp = 98,  Test_Message" would be printed to terminal..