CAN Bus Library for STM32F103

Can someone help me port this library?
Phono
Posts: 91
Joined: Tue May 05, 2015 6:08 am
Location: Ermont, France

Re: CAN Bus Library for STM32F103

Post by Phono » Thu Jul 20, 2017 12:02 pm

@RogerClark: I understand that you are not experienced enough to support the HardwareCAN library, and thus, you did not include it in your last version.
However, I would like to request you to include in the next version of the core the few changes that are required to be able to include the library in a project. These changes are simple and cannot add a threat to the stability of the core.
Thanks in advance.

macbeth
Posts: 13
Joined: Fri Jun 17, 2016 12:59 pm

Re: CAN Bus Library for STM32F103

Post by macbeth » Wed Jul 26, 2017 2:06 pm

I'd definitely vote for merging Phono's patch into master as well.

But I still have 2 more general questions (and this seems to be the thread where the CAN-geeks hang out)

1: Is there a way to reset the communication in case of a temporary short circuit of the CAN bus? Even when I try to escape the blocking while loop in CANsend I never again get mbx == CAN_TX_NO_MBX

Code: Select all

CAN_TX_MBX CANsend(CanMsg *pmsg) {
	uint32 ct=0;
	CAN_TX_MBX mbx;
    digitalWrite(BOARD_LED,1);
	do
		mbx = canBus.send(pmsg);
	while (mbx == CAN_TX_NO_MBX && ct++<20000);
	digitalWrite(BOARD_LED,0);
	return mbx;
}
2: In a bus-system with quite a few members (32 nodes sending with 50ms) I sometimes see that a node stops transmitting for 5 seconds (!!). As far as I read the code there are 3 "mailboxes" that get filled with the transmit-data. Jut like a small buffer. But what happens in case of a collision? Does the hardware-part on the STM handle the "resending" until the frame is on the bus? Or do I have to take care of the re-sending in my code? Is there a transmit-status?

Thanks for helping out!

tjb12345
Posts: 11
Joined: Sun Aug 06, 2017 6:23 am

Re: CAN Bus Library for STM32F103

Post by tjb12345 » Sun Aug 06, 2017 8:28 am

I am trying to get Phono's library working on a MCP2551 and a blue pill (STM32F103C8), I have it connected to a active CANBUS, and I have successfully received and sent message using this same chip with an Arduino Due. I am trying to use the same code that And_Ru posted a while back (modified slightly to just send a message every second. However it fails and get stuck in the mbx = CAN_TX_NO_MBX loop. Assuming this is because it can't successful transmit the messages, so they remain in the TX Mailbox, and it gets full after 3 messages. Here is my connections:

MCP2551 Blue Pill
TXD............PB9
VSS............GND
VDD...........5V
RXD..........PB8
Vref.........Nothing
CAN H......to CAN H on CANBUS
CAN L......to CAN L on CANBUS
Rs..........to GND (through a 4.7k resistor....tried directly to GND, but the 4.7k is what use on the DUE and that works)

I have a FTDI setup on Serial1 to monitor the status, using PA2

The MPC2551 is a 5V transceiver, so on the DUE I use a logic level converter, and that works great. I tried with and without on the Blue Pill since PB8 and PB9 are 5V tolerant. I'm running at 250kbps on the baud, and I have that configured in the setup. I can't tell what I have going on different that what And_Ru has in his video, but there must be something. Any ideas? I can post code if needed.

User avatar
RogerClark
Posts: 7187
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: CAN Bus Library for STM32F103

Post by RogerClark » Sun Aug 06, 2017 10:27 am

Phono wrote:
Thu Jul 20, 2017 12:02 pm
@RogerClark: I understand that you are not experienced enough to support the HardwareCAN library, and thus, you did not include it in your last version.
However, I would like to request you to include in the next version of the core the few changes that are required to be able to include the library in a project. These changes are simple and cannot add a threat to the stability of the core.
Thanks in advance.

Is someone going to create a PR for this change?

tjb12345
Posts: 11
Joined: Sun Aug 06, 2017 6:23 am

Re: CAN Bus Library for STM32F103

Post by tjb12345 » Mon Aug 07, 2017 9:16 pm

Update:

been working on this yet, and I got it to send 1 message, and then it freezes. I received the first message on my Due. I tried different serial ports and no serial ports, but it still only sends 1 before freezing. I also added the digitalWrite in the main loop that fires every second to make sure it wasn't just failing to send. It does not continue to blink. It is also not geting stuck in the No MBX loop anymore, as I put the digitalWrite there (with a small delay to make sure I could see the blink.)

Anyone out there? :?

EDIT: re-reading above posts and saw that jongjejung had the same issue, however its not clear what was wrong in his case. I definitely have 5V at the MPC2551.


Code: Select all

#include <HardwareCAN.h>
/*
 * 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.
uint32_t lastSent = 0;
int count = 1;
int ledState = 0;
// Instanciation of CAN interface
HardwareCAN canBus(CAN1_BASE);
CanMsg msg ;

void CANSetup(void)
{
  CAN_STATUS Stat ;

  // Initialize CAN module
  //Serial1.println("test1");
  canBus.map(CAN_GPIO_PB8_PB9);  
  //  Serial1.println("test2");// This setting is already wired in the Olimexino-STM32 board
  Stat = canBus.begin(CAN_SPEED_250, CAN_MODE_NORMAL);    // Other speeds go from 125 kbps to 1000 kbps. CAN allows even more choices.
    //       Serial1.print("Status: ");
   // Serial1.println(Stat);        
  //Serial1.println("test3");
  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){
   // Serial1.println("CAN initialization Failed");
    /* 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) ;
   // Serial1.print("MBX: ");
   // Serial1.println(mbx);
#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_EXT;          // 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 ;
  
  Serial2.println("before CANSend");
  
  CANsend(&msg) ;      // Send this frame
 // Serial1.println("after CANSend");

}

// 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:
    Serial2.begin(115200);
 //  Serial1.println("before CANSetup");
  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.println("Hello World!");
  msgD0 = 0x01;
  delay(500);
}

void loop() {
 // bState = digitalRead(BPIN);
 // sState = digitalRead(SPIN);
  //Serial1.println("loop");
  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  uint32_t currentMillis = millis();
  if ((currentMillis - lastSent) >= 1000) {
    digitalWrite(PC13, ledState);
    ledState != ledState;
    lastSent = currentMillis;
  uint32_t msgID = 0x1CFFEEF0 ;
        
   // Serial1.print("start CAN Message: ");
 // Serial1.println(count);
  
  SendCANmessage(msgID, 3, 0x01, 0x6f, count) ; 
count++;
  }
  
  // check if the switch is high.
  // if it is:

// 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]);

  canBus.free();
  }

  
}

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

Re: CAN Bus Library for STM32F103

Post by Phono » Wed Aug 09, 2017 8:31 pm

Been in vacations for several weeks, thus my silence.
@macbeth
Question 1 :
you can insert in the loop that processes incoming messages the following code:

Code: Select all

    if ( canBus.Port->ESR & CAN_ESR_BOFF )
      CANSetup() ;
This my usual practice, and it works fine.

Question 2:
in case of a collision, the hardware does or does not automatically retry sending, according to the configuration option.
In the code of the library you find this:

Code: Select all

CAN_STATUS HardwareCAN::begin(CAN_SPEED speed, uint32 mode)
{
/*  Begin Fix JMD
	if (can_init(Port, CAN_MCR_NART, CAN_SPEED_250) == CAN_OK)	
		// NART inhibits the automatic resending in case of collision
 */
	Serial.end();						// disable USB interface -- JMD
	if (can_init(Port, 0, speed) == CAN_OK)
 // End Fix JMD
		return can_set_mode(Port, mode);
	return can_status();
}
The original version did not automatically resend, leading to missing frames on transmission.
I fixed this.

@tjb12345:
looks like the transmit interrupt is not activated. Did you perform the changes in the two core files as described in the file changes.h of the example of the HardwareCAN library?

@all: these changes in the core files are what I request RogerClark to include in the root to allow for integration of the library!

tjb12345
Posts: 11
Joined: Sun Aug 06, 2017 6:23 am

Re: CAN Bus Library for STM32F103

Post by tjb12345 » Thu Aug 10, 2017 4:20 am

I did go through the changes.h file, and I thought I had them all, but I might have missed it. Its very possible that I overlooked one or got mixed up, as I copied and moves the core files when I was trying different things. Knowing me I might have changed ones that weren't in the Arduino folder.

I double check tomorrow and report back.

Thanks much.

tjb12345
Posts: 11
Joined: Sun Aug 06, 2017 6:23 am

Re: CAN Bus Library for STM32F103

Post by tjb12345 » Fri Aug 11, 2017 8:49 pm

Phono wrote:
Wed Aug 09, 2017 8:31 pm
@tjb12345:
looks like the transmit interrupt is not activated. Did you perform the changes in the two core files as described in the file changes.h of the example of the HardwareCAN library?

@all: these changes in the core files are what I request RogerClark to include in the root to allow for integration of the library!
So I cleaned out the STM32 core files and started over, downloading the branch from RogerClark's repo that he pulled in from your fork

this link: https://github.com/rogerclarkmelbourne/ ... og-patch-1

Went through the changes.h file, but they were all made already, with one exception. (Im assuming since I am pulling from your fork?)

the only difference (unless im blind) is the last CAN_RX0_IRQ_Handler function. in the changes.h file it returns 1, but the core file had return 0. I changed it but it still gets hung.

I just got an Olimexino board delivered today, so im going to try with that as well to eliminate hardware, but I can take this same MPC2551 and hook it to my Due, and it works on that.

Code: Select all

2.3.1) inserted 12 lines, position 186
// JMD : default ISRs of CAN, to be overridden if HardwareCAN library is used in sketch
void __attribute__((weak)) USB_HP_CAN_TX_IRQHandler(void) 
{ ; }      // Dummy ISR

void __irq_usb_hp_can_tx(void)
{
  USB_HP_CAN_TX_IRQHandler () ;
}

uint8 __attribute__((weak)) CAN_RX0_IRQ_Handler(void)
{ return 1 ; }      // Dummy ISR 
Also noticed if I unhook the CANRX line from PB8, the sketch continues, and blinks, but of course the message isn't transmitted properly.

I started messing with the code mostly just adding a return in the transmit functions in the CAN.c file, to see where it gets stuck, and it works and comes back to the loops until line 347 which is:

Code: Select all

    CANx->sTxMailBox[mbx].TIR = (data | CAN_TMIDxR_TXRQ);
again, of course that is the line the requests the transmission, so when I have the "return mbx;" just before that, it never gets sent.

tjb12345
Posts: 11
Joined: Sun Aug 06, 2017 6:23 am

Re: CAN Bus Library for STM32F103

Post by tjb12345 » Mon Aug 14, 2017 2:41 pm

So I decided to try testing in Loopback mode, to eliminate the MCP2551 from the setup. I tested in loopback mode on the blue pill, and on the Olimexino (STM32F103RBT6) board that I just got. Script works no problem on the that board. waits 5 seconds, sends 1 message, and then returns to the loops and just flashes led (not using delay() here).

The Blue pill sends the message and then freezes. I have replaced the 1.5k R10 resistor on the D+ line, and tried to see if there was other soldering issues, but I can't find any. Tried it on a different board as well with same results. I know they are cheap clones, so maybe all the ones i have have something wrong with them.

For now I am going to continue my prototyping with the Olimexino-STM32 board, but I would like to use the blue pill if possible, as they are cheaper and smaller, and I already have a CAN transceiver board designed that matches up to it.

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

Re: CAN Bus Library for STM32F103

Post by Phono » Mon Aug 14, 2017 8:11 pm

Oops!
There is an error in my file changes.h.

the dummy interrupt service routine in C:\ArduinoForSTM32\arduino-1.6.9\hardware\Arduino_STM32-master\STM32F1\cores\maple\libmaple\usb\stm32f1\usb.c
should read
uint8 __attribute__((weak)) CAN_RX0_IRQ_Handler(void)
{ return 0 ; } // Dummy ISR
If you change it to 1, you crash the usb operation when the HardwareCAN library is not used.

I have only used the olimexino STM32 board, and it works. I did not try with another board. When you can, check with the olimexino board and tell me the result.

Post Reply