Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
The case for CAN
I have been working on various new machines, planters, fire engines, etc for years.
There never was any question, distributed computing was always used. At first 8085 types, then Atmel 328 was used, mainly due to the avalability of Arduino Nano boards and WinAVR.
The AVR does work, but debugging is sadly lacking. I have also used Raspi, and was disgusted with the bootup sequence. That is totally out of the question.
Why use such a horrible operating system on any machine? Nobody wants to wait that long for any machine to start working.
ARM boards became available, and I switched to STM32F103 initially, using Embitz. What a marvellous upgrade! Embitz and the EBmoitor is absolutely marvellous!
Why struggle with AVR? The STM32 units are cheap enough.
The first consideration then is what interconnection type to use between units.
I did use serial in the form of RS485. All micros I used have serial, and it is always easy to add another bit bang one. The problem with a RS485 setup is that it is a master - slave setup.
For fast response, the master has to poll often, resulting in micros spending time looking at serial, while neglecting its real work.
The STM32 units can receive serial without using processor time, but the problem of fast transmit response remain. DMA does not do it for short massages.
I have used Ethernet with the Raspis, disasterly. Those sockets are simply horrible in a moving and shaking machine.
Essentially, any master slave setup is not the best. It has to be multimaster, minimum wiring, and no collisions.
No wonder canbus is used so widely. It is really the answer.
It appears all the STM32 units has the provision for Canbus. It is easily applied, does not use processor time for receiving, and has numerous filters to block any unwanted messages.
To use the full Canbus specs, driver chips must be used, but canbus can even be used without that. See Siemens Appnote AP2921. Their one wire setup can  be extended simply by using LM393 comparators and higher voltage on the one wire. That will be the cheapest setup for longer connections.
Canbus will transmit when the bus becomes free, the processor only posts the txmessage.
Received messages are filtered and stored, the processor reads the messages when there is time available, no interrupts are required, and no unnecessary messages are received.
The filters only pass messages intended for the particular unit.
The initial code for a STM32F407 is
 //p1099 CAN master control register Page numbers refer to the STM32F407 reference manual
  CAN1->MCR &= (~(uint32_t)CAN_MCR_SLEEP); //wake up from sleep mode
  CAN1->MCR = (CAN_MCR_INRQ);       //p1083 init mode, disable auto retransmission//CAN_MCR_NART |
  uitime = uimillis + 500;
  while(!(CAN1->MSR & CAN_MSR_INAK)){assert(uimillis, <, uitime);} //p1083 wait for confirmation
Set up the baudrate

  //A good rule of thumb is to have your sampling point at 70-80% of the nominal bit time.
  //p1095 For 125Khz CAN: APB1 42Mhz;(APB1 clocked at 42 MHz)
  // quanta 1+9+4 = 14, 14 * 24 = 336, 42000000 / 336 = 125000
  // CAN Baudrate = 125Kbps (CAN clocked at 42 MHz) Prescale = 24

  CAN1->BTR  = 0x01 << 24; //p1108 CAN bit timing register  Resynchronization jump width
  CAN1->BTR |= 0x03 << 20; //TS2 tBS2 = tq x (TS2[2:0] + 1)p1108
  CAN1->BTR |= 0x08 << 16; //TS1 tBS1 = tq x (TS1[3:0] + 1)p1109
  CAN1->BTR |= 0x17;       //prescaler 24 p1109
  CAN1->FMR  = 0x0E << 8;   //p1116 CAN filter master register
This must be changed to the required speed and APB1 clock speed
Set up the receive filters

  CAN1->FMR  = 0x0E << 8;   //p1116 CAN filter master register
  CAN1->FMR |= 1;          //p1116 Initialization mode for the filters.
  CAN1->FM1R = 0;          //p1117 Filter mode register 1:32bit filters mask mode
  CAN1->FS1R  = 0x0FFFFFFF;//p1117 Single 32-bit scale configuration
  CAN1->FFA1R = 0x00000000;//p1118 Fifo assignment register
  CAN1->sFilterRegister[0].FR1 = 0x00B << 21;//p1091,1119 COMP
  CAN1->sFilterRegister[1].FR1 = 0x00D << 21;//p1091,1119 COMP
  CAN1->sFilterRegister[0].FR2 = 0x47F << 21;//p1091,1119 MASK
  CAN1->sFilterRegister[1].FR2 = 0x47F << 21;//p1091,1119 MASK
  CAN1->FA1R  = 0x00000001;//p1118 filter activation register filters 0 only
  CAN1->FMR   = 0x0E << 8; //p1116 CAN filter master register clear init bit
  CAN1->MCR &= ~(CAN_MCR_INRQ);// p1083 normal mode
  uitime = uimillis + 500;
  while(CAN1->MSR & CAN_MSR_INAK){assert(uimillis, <, uitime);};  //p1083 wait for confirmation

Set up a tx message struct

typedef struct
{ u16   id;                 // 11 bit identifier
  u8    data[8];            // Data field
  u8    len;                // Length of data field in bytes
  u8    format;             // 0 - STANDARD, 1- EXTENDED IDENTIFIER
  u8    type;               // 0 - DATA FRAME, 1 - REMOTE FRAME
canmsg cantxmsg;

I found that most messages used were the 11bit id only, or id + 1. The full 8 bytes data was rarely used.
The transmit code:

  while(!(CAN1->TSR & (1 << 26)))//p1103 TME0 Mailbox empty
  {assert(uimillis, <, uitime);} //NAK?
  CAN1->sTxMailBox[0].TIR = 0;                     //p1110
  CAN1->sTxMailBox[0].TIR |= (txmsg->id << 21)|txmsg->type;
  CAN1->sTxMailBox[0].TDTR = (txmsg->len & 0x07);    //p1111
  if(0 == txmsg->len)
 { CAN1->sTxMailBox[0].TDLR = (txmsg->data[0]);
 }else if(1 == txmsg->len)
  { CAN1->sTxMailBox[0].TDLR = ((txmsg->data[1] << 8) |  (txmsg->data[0]));
  { CAN1->sTxMailBox[0].TDHR = ((txmsg->data[7] << 24) //p1112
                                 |(txmsg->data[6] << 16)
                                 |(txmsg->data[5] <<  8)
    CAN1->sTxMailBox[0].TDLR = ((txmsg->data[3] << 24)
                                 |(txmsg->data[2] << 16)
                                 |(txmsg->data[1] <<  8)
  CAN1->sTxMailBox[0].TIR |= 0x01; //p1110 TXRQ

Receive is:

volatile u32 mail0 = 0;
    rxid = (((CAN1->sFIFOMailBox[0].RIR) >> 21) & 0x07ff);  //p1113 11 bits only (If you require the id in your code)
    datalen = (CAN1->sFIFOMailBox[0].RDTR) & 0x0F; //p1114
    //else if 0 datalen simply read CAN1->sFIFOMailBox[0].RIR
     mail0 = CAN1->sFIFOMailBox[0].RDLR;
      rxdata[0] = (mail0 & 0xFF);
      mail0 >>= 8;
      rxdata[1] = (mail0 & 0xFF);
      mail0 >>= 8;
      rxdata[2] = (mail0 & 0xFF);//p1115
      mail0 >>= 8;
      rxdata[3] = (mail0 & 0xFF);////p1115
      mail0 = CAN1->sFIFOMailBox[0].RDHR;
       rxdata[4] = (mail0 & 0xFF);////p1115
       mail0 >>= 8;
       rxdata[5] = (mail0 & 0xFF);////p1115
       mail0 >>= 8;
       rxdata[6] = (mail0 & 0xFF);////p1115
       mail0 >>= 8;
       rxdata[7] = (mail0 & 0xFF);//p1115
 Change as you like
The filters are not easy to envisage, but can easily be proven by this code:

  #define COMP 0x00D //change as required
  #define MASK 0x47F  //change as required
  u16 id= 0;
     for(id=0; id < 0x800; id++)
        {// printf("%d ",id);
            if ((id & MASK) == COMP)
           { printf("0x%03X\n", id);
Canbus is also easily tested in logic analysers.
I am not aware of anything that can beat canbus for interconnection.
I hope this post is of help to somebody.
Johan Smit
Hi Johan,
Having started myself with the 8085 and companions I can only agree with your views. AVR is mis-designed and slow; RPI, Beaglebone and the like are totally unsuitable for serious embedded applications, one reason being the never ending bootup. Currently I happily use STM32F0 and F3, mainly. A forthcoming project uses CAN so thank you for the code snippets: I'm sure they will come in handy.
(03-09-2018, 11:07 PM)escalator Wrote: Hi Johan,
Having started myself with the 8085 and companions I can only agree with your views. AVR is mis-designed and slow; RPI, Beaglebone and the like are totally unsuitable for serious embedded applications, one reason being the never ending bootup. Currently I happily use STM32F0 and F3, mainly. A forthcoming project uses CAN so thank you for the code snippets: I'm sure they will come in handy.
Hi Escalator,
My pleasure.
A part I did not mention is the availability and low cost of the ST-link V2.
That is really nice about STM32 (and STM8).
Also what I found very helpful in setting up PID motion control is STMStudio.
That makes it easy to view graphically the value of any register or variable.
Sometimes it is not easy to know the address of the register or variable. Then in debugger mode, right click on the item and choose memory view at .. Use that memory address in STMStudio. 
Johan Smit
If i read the Stories about the way from i8085 to STM32, my way was near similar. I had started with embedded programming on a cheap i51 and moved over the hole Siemens sab80x5xx Family. That time, Debugging was done by just a few LED's or later, using by a bit-bang Serial port, of none was available. I also had ride on the AVR road and that Controllers was easier in programming and got an OCD. Compared by i51 Family, they does'nt have Flash or OCD available, the AVR was a big Advantage. They clocked up to 16Mhz and was very fast for an 8 bit mpu. The dis-advantage was the lacks of an external bus and the horrible havard implementation. The JTAG/SWD
pods was very expensive - $300 and up. I had left the AVR as i got a cheap STM32F103VC board and a Keil JTAG Pod, that the compy i had worked for, has replaced by a J-Link. The chinese 103 board contained a segger demo of their gui and Windows system, displayed on a cheap 2.8" TFT. It was amazing fast, compared by the 8but LCD Displays based upon Toshiba t6963c, linked with an avr by just a i/O ports, instead a bus.
I had moved to the STM32 in about 2013 and did some hacks with the discovery ,nucleo and cutom boards. Well, ST has done a good Job developing this Chips. They are not "the lords last answer of any question" - ST sometimes lacks in the Quality Management and offers buggy libraries and Tools. Well, you have the decision using that or not. The developing Tools are cheap and gives a beginner a good ground to start and learn how this works and if the mpu fit's your requirements.
I am currently not using the last Generation STM32H7xx, because i don't need such powerful MPU this time. Some experiences are available using STM32F746/767 Mpu's. but currently, i am using the STM32F407 MPU's in my projects.

The Debugger is a J-Trace and the IDE is currently µVision for Commercial use and Atollic TrueStudio with j-Link OB for my hobby purposes.
I am sure, i would never move back to an 8Bit AVR or other. The Cortex-M Family is a powerful and cheap MPU Family, wo is highly versatile and Comes with a bunch of
on-chip peripheral Interfaces like SIO, CAN, RS232/485/422, Ethernet, SPI,IIC. They Supports DMA and edge-triggered i/o Inputs, some Levels of IRQ, timers, Counters, and decoders. I had used the most of them one time and could say, using all that could be a Horror if the SPL or HAL is used. I can recomend to program the Registers directly.

Forum Jump:

Users browsing this thread: 1 Guest(s)