*I am not an expert on CANbus if you see something I am doing is wrong or can be done in a better way please let me know!
IntroductionIt is very likely that you have heard of CAN/CAN-BUS; it is very widely used in the automotive Industry, robotics, and automation.
Why would you choose to go for CANbus??
The answer is why wouldn't you... (I wont go into a lot of detail about it).
CANCANbus was developed by BOSCH to make the ever growing in complexity automotive electronics systems easier to manage and wire, so the idea is instead of every single device being connected to a main computer you work with a distributed system that runs over a network
Below are two very clear comparisons of a traditional wiring and networked wiring (CAN) most of the actual vehicles run with CAN and work with an interface called ODB-II for debugging and programming.
- On top of the reduced physical complexity, you get a network capable of working in most cases up to 40m lenght configurations, and with a slower network even up to 100m.
- It is a message based network this means any node can receive and transmit messages if the bus is available. (Multi Master capable)
- With every message you get an error checksum to make sure the message was not disturbed.
- robust and fast communication.
The basic CAN message is built with this shape.
- SOF Start of Frame
- Identifier ID to establish the priority of the message (where is it destined to go)
- RTR Remote transmission request
- IDE Used to identify a Standard or extended CAN message
- r0 Reserved
- DLC 4 bit Data length code (how many bytes will be transmitted)
- Data The actual message to be sent up to 8 bytes.
- CRC 16 bit cyclic redundancy check (CRC) for error check
- ACK Every node receiving an accurate message overwrites this recessive bit in the original message
- EOF end-of-frame 7-bit field marks the end of a CAN frame (message)
- IFS 7-bit interframe space (IFS) contains the time required by the controller to move a correctly received frame to its proper position in a message buffer area.
The good news about this is that most of the data required to build the CAN message is done by the CAN Controller Itself, but still in every case all the MCU's out there require an external CAN transceiver to translate the messages to the actual wires. So, in the PSoC this will be all you need to get started.
Now I will tell you a bit of the application. In the last couple of years there has been a huge adoption of BLDC motors thanks to drones and e-skateboards, scooters, hoover boards, etc. and a lot of this components are very well suited for robotics, R/C and hobby projects.
There is a very popular ESC (Electronic Speed Control) for BLDC motors, which is open source the vESC https://vesc-project.com/ amongst its various features it has CANbus capability.
The thing is there is not a lot of documentation around making them work with CANbus so getting them to work is a bit tricky.
THIS IS THE MOST BASIC EXAMPLE OF SENDING CAN MESAGESThere are a lot more things that can be implemented but will take forever to explain this is to show the way it works (the mailbox is a really good feature to work with I might post something later on that).
- First we need to setup the signal, select a baud rate and double click on the desired settings provided on the table below.
- The vESC is programmed to read this messages through CAN
typedef enum {
CAN_PACKET_SET_DUTY = 0,
CAN_PACKET_SET_CURRENT,
CAN_PACKET_SET_CURRENT_BRAKE,
CAN_PACKET_SET_RPM,
CAN_PACKET_SET_POS,
CAN_PACKET_FILL_RX_BUFFER,
CAN_PACKET_FILL_RX_BUFFER_LONG,
CAN_PACKET_PROCESS_RX_BUFFER,
CAN_PACKET_PROCESS_SHORT_BUFFER,
CAN_PACKET_STATUS
} CAN_PACKET_ID;
- Remember the 11bit identifier? Depending on the ID of the device we want to address and what command we want to send, the address will be in this format.
- device ID is 1
- ID 0x301
Now to the firmware...
- First we set some CAN variables ( part of the CAN block API).
CAN_TX_MSG messageRPM;
CAN_DATA_BYTES_MSG Data;
- define a buffer function to organize the data in 4 byte format (remember there is actually room for 8 bytes in the message)
void buffer_append_int32(uint8_t* buffer, int32_t number, int32_t *index) {
buffer[(*index)++] = number >> 24;
buffer[(*index)++] = number >> 16;
buffer[(*index)++] = number >> 8;
buffer[(*index)++] = number;
}
- function to build the message, Identification and send message
void can_set_rpm(uint8_t controller_id, float rpm) {
uint8 bIndex;
int32_t send_index = 0;
uint8_t buffer[4];
uint8 MESSAGE[8];
messageRPM.id =controller_id | ((uint32_t)CAN_PACKET_SET_RPM << 8);
buffer_append_int32(buffer, (int32_t)rpm, &send_index);
MESSAGE[0]=buffer[0];MESSAGE[1]=buffer[1];MESSAGE[2]=buffer[2];MESSAGE[3]=buffer[3];
//MESSAGE [4-7]={0x00,0x00,0x00,0x00};//define 8 bytes of data
for(bIndex=0;bIndex<DATALENGTH;bIndex++){
Data.byte[bIndex] = MESSAGE[bIndex]; /* move data to the structure*/
}
messageRPM.msg = &Data;
CAN_SendMsg(&messageRPM);
}
- and the main sequence initializes the components of the message, the id, and msg parameters should not be initialized at this stage since it is being changed every time the function is called, but it is helpful to see them together.
int main(){
CYGlobalIntEnable; /*enable global interrupts*/
messageRPM.id = 0x301; /*write the value of ID to the structure*/
messageRPM.rtr = 0; /*write the value of RTR to the structure*/
messageRPM.ide = 1; /*write the value of IDE to the structure*/
messageRPM.dlc = DATALENGTH; /*write the value of DLC to the structure*/
messageRPM.irq = 1; /*write the value of IRQ to the structure*/
messageRPM.msg = &Data; /* write address of structure that represents data*/
CAN_Init(); /* initialize CAN node */
CAN_Start(); /* start CAN node */
CyDelay(400);
while (1)
{
can_set_rpm(1,1000);
CyDelay(150);
}
}
ImagesThe transceiver board I used is not the ideal for working with the PSOC, because it includes a SPI to CAN converter which will not make sense to use with the PSOC since it has the integrated CAN controller, so I just soldered some wires to the TX and RX lines on the transceiver chip.
The wires on J1 are just a jumper didn't have one handy.
I am powering the CAN board with the FreeSOC and also giving a ground reference to the vESC it worked without it anyway.
I will start working on the more advanced features.
Hope this was helpful, would love to hear some comments and suggestions!
Comments
Please log in or sign up to comment.