CAN Bus Library for STM32F103

Can someone help me port this library?
Post Reply
User avatar
RogerClark
Posts: 6712
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: CAN Bus Library for STM32F103

Post by RogerClark » Tue Nov 15, 2016 8:35 am

@phono

Actually, in hindsight, you are better off staying with LibMaple as the core for at least the next 6 months as to use CAN on the new core would require a lot of rewriting as the STM core uses STM's own HAL (not libmaple) so there would need to be a lot of changes to port to that core.

And_Ru
Posts: 19
Joined: Thu Nov 10, 2016 1:16 pm

Re: CAN Bus Library for STM32F103

Post by And_Ru » Fri Nov 18, 2016 5:46 am

Phono wrote:to And_Ru : I am sorry, but the library is dedicated to the integral CAN interface of the STM32F103. Maybe one day it will be expanded to other interfaces.
Ok, this is even better. Then, I will connect MCP2515 board to Raspberry Pi. And try to communicate.
One question in advance: do the library work with one wire CAN-Low connection?

Phono
Posts: 87
Joined: Tue May 05, 2015 6:08 am
Location: Ermont, France

Re: CAN Bus Library for STM32F103

Post by Phono » Fri Nov 18, 2016 7:02 pm

If you mean whether it is possible to connect only the CANL wire without connecting the CANH, it is not up to the library. The ISO 11898-compliant CAN transceivers requires that both wires be connected, and in addition, that the line be terminated with a 120 ohm resistor at both ends.
If you need only one wire, you may want to look at the NCV7356 for example.

And_Ru
Posts: 19
Joined: Thu Nov 10, 2016 1:16 pm

Re: CAN Bus Library for STM32F103

Post by And_Ru » Mon Nov 28, 2016 5:10 pm

Phono wrote:If you mean whether it is possible to connect only the CANL wire without connecting the CANH, it is not up to the library. The ISO 11898-compliant CAN transceivers requires that both wires be connected, and in addition, that the line be terminated with a 120 ohm resistor at both ends.
If you need only one wire, you may want to look at the NCV7356 for example.
Hi! Thanks for the link, will investigate later.

For now, I kind of have tuned the train mcp2515--raspberry pi and have the instrument to send into CAN bus as well as listen.
Also I have two STM32 boards and I'm willing to test the comunication between them.
I would ask again (because your example is rather complex for the beginner...) :
Could you make an example that just listen for the CAN bus and print it using "serial.print"?
And another one that just send something once a second.

This will be very helpful for me and other future users.

SyRus
Posts: 2
Joined: Sat Dec 10, 2016 1:19 am

Re: CAN Bus Library for STM32F103

Post by SyRus » Sat Dec 10, 2016 2:36 pm

Hi guys...

I don't know what's the big deal here??? The MCP2515 shield for Arduino works perfectly with Iteadmaple 1.0 Arduino compatible board. The library compiles the board inits and then all runs smooth and easy like Arduino accept it's much faster. All you need to do is a little bit rewire it. Not all of the CAN_BUS shield pins goes to the board. But if you really wants then you defanatelly figure it out. Program board through the Arduino IDE...

Also it works with Teensy 3.1 3.2.. Without any problem..

Phono
Posts: 87
Joined: Tue May 05, 2015 6:08 am
Location: Ermont, France

Re: CAN Bus Library for STM32F103

Post by Phono » Tue Dec 13, 2016 7:32 pm

Maybe you do not know, but the Olimexino STM32 board includes all the CAN hardware. You just have to connect your can bus to a terminal strip and you're done. No need for an extra shield.

SyRus
Posts: 2
Joined: Sat Dec 10, 2016 1:19 am

Re: CAN Bus Library for STM32F103

Post by SyRus » Thu Dec 15, 2016 4:36 am

I know if your answer was to me Phono . But then you have to write your own functions to maintain CAN ah? From this thread it seems people have wish to run that exactly shield by STM32 because STM much faster and second that the shield has very very convenient library with just a few very very convenient functions. Nothing more just what you need.
Though seems no body here actually tryd to hook up the PCM2515 CAN shield with STM. I did.. that's why Im here to tall you about.

And_Ru
Posts: 19
Joined: Thu Nov 10, 2016 1:16 pm

Re: CAN Bus Library for STM32F103

Post by And_Ru » Thu Dec 15, 2016 7:12 am

@SyRus, you're right, MCP2515 works perfectly (correction - I mean not the shield, but the MCP2515 chip itself :) ).
My first mistake was to connect CAN bus directly to the board (CAN TX, RX).
Second fail was because TJA1050 that I tried was defective (infinite resistance between CAN Hi - CAN Lo).
Third - both TJA1050 and MCP2515 must be supplied with 5V to be able to send messages.

I've simplified the code by Phono to just send a message for test reasons:

Code: Select all

// HardwareCAN_simplified_send1.ino
#include <HardwareCAN.h>
//#include "changes.h"
/*
 * Example of use of the HardwareCAN library
 * Please read the file changes.h to see the changes to be performed to the core in order to use this
 */

byte msgD0 ; // variable to be used in the example.

// Instanciation of CAN interface
HardwareCAN canBus(CAN1_BASE);
CanMsg msg ;

void CANSetup(void)
{
  CAN_STATUS Stat ;

  // 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) // Should be moved to the library?!
{
  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 ;
}

// Send message
// Prepare and send a frame containing some value 
void SendCANmessage(long id=0x001, byte d0=0x00, byte d1=0x00, byte d2=0x00, byte d3=0x00, byte d4=0x00, byte d5=0x00, byte d6=0x00, byte d7=0x00)
{
  // Initialize the message structure
  // A CAN structure includes the following fields:
  msg.IDE = CAN_ID_STD;          // Indicates a standard identifier ; CAN_ID_EXT would mean this frame uses an extended identifier
  msg.RTR = CAN_RTR_DATA;        // Indicated this is a data frame, as opposed to a remote frame (would then be CAN_RTR_REMOTE)
  msg.ID = id ;                  // Identifier of the frame : 0-2047 (0-0x3ff) for standard idenfiers; 0-0x1fffffff for extended identifiers
  msg.DLC = 8;                   // Number of data bytes to follow

  // Prepare frame : send something
  msg.Data[0] = d0 ;
  msg.Data[1] = d1 ;
  msg.Data[2] = d2 ;
  msg.Data[3] = d3 ;
  msg.Data[4] = d4 ;
  msg.Data[5] = d5 ;
  msg.Data[6] = d6 ;
  msg.Data[7] = d7 ;

  digitalWrite(PC13, LOW);    // turn the onboard LED on
  CANsend(&msg) ;      // Send this frame
  delay(180);              
  digitalWrite(PC13, HIGH);   // turn the LED off 
  delay(100);  
}

// 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.
  pinMode(PC13, OUTPUT);
  msgD0 = 0x01;
}

void loop() {
  delay(1000);
  long msgID = 0x101 ;
  SendCANmessage(msgID, msgD0) ;       
  msgD0++;
}
It powers up onboard LED, sends message, power down LED. So if a message is not sent, LED is left ON.
STM32F103C8T6_23x53_pic.jpg
STM32F103C8T6_23x53_pic.jpg (40.05 KiB) Viewed 1227 times
+
20161209_221818.jpg
20161209_221818.jpg (23.03 KiB) Viewed 1227 times
@Phono, could you please add CAN_SPEED_33, CAN_SPEED_95 settings? Or point me how to do it. (I know that newcommers are not loved here, but any help will be appreciated!)

Phono
Posts: 87
Joined: Tue May 05, 2015 6:08 am
Location: Ermont, France

Re: CAN Bus Library for STM32F103

Post by Phono » Thu Dec 15, 2016 6:07 pm

@And_Ru:
to add new speeds, you have to change the code at two places as shown below.
I am unsure of the numeric values to achieve these speeds. At least, it should work with a good physical bus line, but fine tuning the values SJW, TS1 and TS2 may further improve the robustness of the communication.
i have never heard of these speeds. To satisfy my curisosity, where are they used?

1) in the file can.h, change the enum definition:

Code: Select all

enum CAN_SPEED {
	CAN_SPEED_125,
	CAN_SPEED_250,
	CAN_SPEED_500,
	CAN_SPEED_1000,
};
to:

Code: Select all

enum CAN_SPEED {
	CAN_SPEED_33,
	CAN_SPEED_95,
	CAN_SPEED_125,
	CAN_SPEED_250,
	CAN_SPEED_500,
	CAN_SPEED_1000,
};
2) in file can.c, change

Code: Select all

static const struct can_speed_info can_speed_table[] = {
	[CAN_SPEED_125]		= { .btr = (
		(( 4-1) << CAN_BTR_SJW_POS) |
		((12-1) << CAN_BTR_TS1_POS) |
		(( 5-1) << CAN_BTR_TS2_POS) |
		(CAN_CLOCK / 125000UL - 1)
		)},
	[CAN_SPEED_250]		= { .btr = (
		(( 4-1) << CAN_BTR_SJW_POS) |
		((12-1) << CAN_BTR_TS1_POS) |
		(( 5-1) << CAN_BTR_TS2_POS) |
		(CAN_CLOCK / 250000UL - 1)
		)},
	[CAN_SPEED_500]		= { .btr = (
		(( 4-1) << CAN_BTR_SJW_POS) |
		((12-1) << CAN_BTR_TS1_POS) |
		(( 5-1) << CAN_BTR_TS2_POS) |
		(CAN_CLOCK / 500000UL - 1)
		)},
	[CAN_SPEED_1000]	= { .btr = (
		(( 4-1) << CAN_BTR_SJW_POS) |
		((12-1) << CAN_BTR_TS1_POS) |
		(( 5-1) << CAN_BTR_TS2_POS) |
		(CAN_CLOCK / 1000000UL - 1)
		)}
};
to:

Code: Select all

static const struct can_speed_info can_speed_table[] = {
	[CAN_SPEED_33]		= { .btr = (
		(( 4-1) << CAN_BTR_SJW_POS) |
		((12-1) << CAN_BTR_TS1_POS) |
		(( 5-1) << CAN_BTR_TS2_POS) |
		(CAN_CLOCK / 33000UL - 1)
		)},
	[CAN_SPEED_95]		= { .btr = (
		(( 4-1) << CAN_BTR_SJW_POS) |
		((12-1) << CAN_BTR_TS1_POS) |
		(( 5-1) << CAN_BTR_TS2_POS) |
		(CAN_CLOCK / 95000UL - 1)
		)},
	[CAN_SPEED_125]		= { .btr = (
		(( 4-1) << CAN_BTR_SJW_POS) |
		((12-1) << CAN_BTR_TS1_POS) |
		(( 5-1) << CAN_BTR_TS2_POS) |
		(CAN_CLOCK / 125000UL - 1)
		)},
	[CAN_SPEED_250]		= { .btr = (
		(( 4-1) << CAN_BTR_SJW_POS) |
		((12-1) << CAN_BTR_TS1_POS) |
		(( 5-1) << CAN_BTR_TS2_POS) |
		(CAN_CLOCK / 250000UL - 1)
		)},
	[CAN_SPEED_500]		= { .btr = (
		(( 4-1) << CAN_BTR_SJW_POS) |
		((12-1) << CAN_BTR_TS1_POS) |
		(( 5-1) << CAN_BTR_TS2_POS) |
		(CAN_CLOCK / 500000UL - 1)
		)},
	[CAN_SPEED_1000]	= { .btr = (
		(( 4-1) << CAN_BTR_SJW_POS) |
		((12-1) << CAN_BTR_TS1_POS) |
		(( 5-1) << CAN_BTR_TS2_POS) |
		(CAN_CLOCK / 1000000UL - 1)
		)}
};

And_Ru
Posts: 19
Joined: Thu Nov 10, 2016 1:16 pm

Re: CAN Bus Library for STM32F103

Post by And_Ru » Fri Dec 16, 2016 5:51 am

Many thanks, Phono!
Another place found in HardwareCAN.cpp (otherwise Arduino compiler don't pass it):

Code: Select all

/**
 * @brief Initialize a CAN peripheral
 * @param freq frequency to run at, must one of the following values:
 *           - CAN_SPEED_1000
 *           - CAN_SPEED_500
 *           - CAN_SPEED_250
 *           - CAN_SPEED_125
 *           - CAN_SPEED_95
 *           - CAN_SPEED_33
 */!
These speeds are used in my Opel Astra (and in general in GM wehicles).
So my test code is a button than sends "OK" button pressed and a switch that sends buttons 1--9 on the radio/CD player.

Code: Select all

#include <HardwareCAN.h>
//#include "changes.h"
/*
 * Example of use of the HardwareCAN library
 * Uses STM32duino with Phono patch. Must add 33 and 95 CAN speeds
  */
#define BPIN 0
#define SPIN 1
byte msgD0 ; // variable to be used in the example.

// Instanciation of CAN interface
HardwareCAN canBus(CAN1_BASE);
CanMsg msg ;

void CANSetup(void)
{
  CAN_STATUS Stat ;

  // Initialize CAN module
  canBus.map(CAN_GPIO_PB8_PB9);       // This setting is already wired in the Olimexino-STM32 board
  Stat = canBus.begin(CAN_SPEED_95, 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) // Should be moved to the library?!
{
  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 ;
}

// Send message
// Prepare and send a frame containing some value 
void SendCANmessage(long id=0x001, byte dlength=8, byte d0=0x00, byte d1=0x00, byte d2=0x00, byte d3=0x00, byte d4=0x00, byte d5=0x00, byte d6=0x00, byte d7=0x00)
{
  // Initialize the message structure
  // A CAN structure includes the following fields:
  msg.IDE = CAN_ID_STD;          // Indicates a standard identifier ; CAN_ID_EXT would mean this frame uses an extended identifier
  msg.RTR = CAN_RTR_DATA;        // Indicated this is a data frame, as opposed to a remote frame (would then be CAN_RTR_REMOTE)
  msg.ID = id ;                  // Identifier of the frame : 0-2047 (0-0x3ff) for standard idenfiers; 0-0x1fffffff for extended identifiers
  msg.DLC = dlength;                   // Number of data bytes to follow

  // Prepare frame : send something
  msg.Data[0] = d0 ;
  msg.Data[1] = d1 ;
  msg.Data[2] = d2 ;
  msg.Data[3] = d3 ;
  msg.Data[4] = d4 ;
  msg.Data[5] = d5 ;
  msg.Data[6] = d6 ;
  msg.Data[7] = d7 ;

  digitalWrite(PC13, LOW);    // turn the onboard LED on
  CANsend(&msg) ;      // Send this frame
  delay(180);              
  digitalWrite(PC13, HIGH);   // turn the LED off 
  delay(100);  
}

// The application program starts here
int bState = 0;         // variable for reading the pushbutton status
int sState = 0;         // variable for reading the switch status
byte st = 0x31; // buttot 1 on the CD30MP3

void setup() {
  // put your setup code here, to run once:
  CANSetup() ;        // Initialize the CAN module and prepare the message structures.
  pinMode(PC13, OUTPUT);
  pinMode(BPIN, INPUT); // input for hardware button
  pinMode(SPIN, INPUT); // input for hardware switch
  Serial1.begin(115200);
  Serial1.println("Hello World!");
  msgD0 = 0x01;
  delay(500);
}

void loop() {
  bState = digitalRead(BPIN);
  sState = digitalRead(SPIN);
  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (bState == HIGH) {
  long msgID = 0x201 ;
  SendCANmessage(msgID, 3, 0x01, 0x6f, 0x00) ;       
  Serial1.println("OK pressed");
  }
  
  // check if the switch is high.
  // if it is:
  if (sState == HIGH) {
    long msgID = 0x201 ;
      SendCANmessage(msgID, 3, 0x01, st, 0x00) ;
      Serial1.print("Station changed to ");
      Serial1.println(st);
      delay(500);       
      if (st == 0x39){st=0x31;} else {st++;};
  }
// try to read message and output to serial
CanMsg *r_msg;
if ((r_msg = canBus.recv()) != NULL){
  Serial1.print(r_msg->ID);
  Serial1.print("#");
  Serial1.print(r_msg->Data[0]);
  Serial1.print(".");
  Serial1.print(r_msg->Data[1]);
  Serial1.print(".");
  Serial1.print(r_msg->Data[2]);
  Serial1.print(".");
  Serial1.print(r_msg->Data[3]);
  Serial1.print(".");
  Serial1.print(r_msg->Data[4]);
  Serial1.print(".");
  Serial1.print(r_msg->Data[5]);
  Serial1.print(".");
  Serial1.print(r_msg->Data[6]);
  Serial1.print(".");
  Serial1.println(r_msg->Data[7]);
if (r_msg->ID == 0x201 and r_msg->Data[0] == 0x01 and r_msg->Data[1] == 0xFF){
// SETTINGS is pressed!
  Serial1.println("SETTINGS. Pause for 2 seconds.");
  digitalWrite(PC13, LOW);    // turn the onboard LED on
  delay(2000);              
  digitalWrite(PC13, HIGH);   // turn the LED off 
  }
  canBus.free();
  } 
}
In future I would like to add some features like closing windows on doors locking, automatic lights turn on and other non-harmfull things.

Code tested successfully on this:
test_bench.jpg
test_bench.jpg (127.96 KiB) Viewed 1197 times
A little inconvenience is that Serial1.print gives decimal value instead of hex. This will be my next learning.

Post Reply