CAN - STM32F107 - John Kneen Microcontrollers
CAN - STM32F107 - John Kneen Microcontrollers
com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
Home 28.Keil IDE 15.Clocks 16.Input Output 18.ARM SCI 18a.ARM SPI 18b.ARM I2C
1 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
21.SystemTick
Tick_F107
Tick_LPC1768
22.Interrupts
27.Performance
1.Railway Analogy
2.Profiling
Techniques
3.Profiling Inputs
4.Great Circle
Example
5.Flat Earth
Approximation
6.Reducing
Resolution
7.Simplify Trig
Functions
8.Other Speed Ups
9.Small
Microcontrollers
Exercises
28.Keil IDE
1.Importance
The CAN-ARM Interface
2.New Project
2a.New Project 5 The bxCAN has three transmit mailboxes for the software to set up messages and 28 scalable/configurable identifier filter banks for
3.Configure selecting the incoming messages. Two receive FIFOs (First In First Out) are used by the hardware to store the incoming messages. Three
Debugger
complete messages can be stored in each FIFO.
4.Create Program
5.Debug programs With the Keil MCB32C EVB the CAN bus is physically wired to PD1/0 (CAN1) so programming/ re-mapping AFIO_MAPR register is
6.Startup code
required.
7.IDE_Problems
49.USB
USB_Mouse_1768
USB_OUSB1768
50.Ethernet
Ethernet_LPC1768
70.RS232 Project
1.Init USART
2.Up Date GPS
3.Flight Path
71.LCD Project
LCD_1768
Sitemap
Recent site activity CAN Bus wiring.
2 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
The example will be implemented using two STM F107 boards. (Note the author originally used the master and slave of one board to
simulate two boards) One board will be programmed as a talker and will write a one word message to the bus. The second board will be
programmed to read the message. In this example the message will be text only - however it could be the status of a number of on-off
switches, the reading from a sensor, or it could be a setting for some output device. The message will use the identifier 0x1badcafe.
Example to be implemented.
The talker will be implemented first and its output observed using a logic analyser. This will be used as a test system for the listener. The
developer can then be reasonably confident that they have a working system. There is the possibility that the same mistake is made in both
with setting up the timing - this would need to be checked if an existing working CAN system became available for cross checking.
1. Programming the alternative function. These operations are generic in nature and not specific to the bxCAN.
3 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
Since the CAN is relatively complex unless the developer has recently used the IDE and microcontroller it is recomended that a small
program to flash the LEDs be entered as revision.
#include
int main( )
{
while (1) {
test( );
}
}
4 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
A project should be set up that includes the above program and the start up code (C:\Keil\ARM\Startup\ST\STM32F10x
\startup_stm32f10x_cl.s). The start up code calls the routine SystemInit( ). This can be left blank or actual initialisation code added as per
the example.
Enabling the clocks will require enabling the clock to the CAN peripheral, enabling the clock for the Alternative Function, and enabling the
clock for the CAN pins (port D). These operations involve setting bits in registers RCC_APB1ENR and RCC_APB2ENR. (Reset and Clock
Control - Advanced Peripheral Bus (1 or 2) Enable Registers. These registers are shown below.
5 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
For user convenience the ARM microcontroller allows alternative functions to be mapped to several GPIO pins. Mapping uses the
AFIO_MAPR mapping register. Since with the Keil MCB32C EVB the CAN bus is physically wired to PD1/0 (CAN1) and PB5/6 (CAN2)
programming/ re-mapping AFIO_MAPR register is required.
When enabled each bxCAN utilises two general purpose input-output pins. In the Keil MCB32C EVB CAN1 is physically wired to PD0 (Rx)
and PD1 (Tx). This will require:
6 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
The basic configuration task will be to enable the desired signal paths.
The function of the input output pins is configured using two control registers CRL (Control Register Low) and CRH (Control Register High).
Each pin is controlled using 4 bits as illustrated in the following diagram.
7 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
The following sections will introduce the CAN registers. In the C language these can be described as registers within a structure. Most
registers are simple 32 bit unsigned integers. However there are several groups of multiple registers that themselves form a structure. The
definitions as used in the Keil C Compiler are shown below. These definitions are used in the examples in this chapter.
.
} CAN_TxMailBox_TypeDef;
8 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
typedef struct
{
__IO uint32_t RIR;
__IO uint32_t RDTR;
__IO uint32_t RDLR;
__IO uint32_t RDHR;
} CAN_FIFOMailBox_TypeDef;
typedef struct
{
__IO uint32_t FR1;
__IO uint32_t FR2;
} CAN_FilterRegister_TypeDef; Refer Struct
typedef struct
{
__IO uint32_t MCR; 0x000 Refer MCR
uint32_t RESERVED0[88];
9 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
uint32_t RESERVED1[12];
uint32_t RESERVED4;
__IO uint32_t FA1R; 0x20C Refer filters
uint32_t RESERVED5[8];
CAN_FilterRegister_TypeDef sFilterRegister[28]; 0x240..0x31C Refer Struct
} CAN_TypeDef;
With this simple example it will only be necessary to initialise the MCR, IER and BTR registers.
Reset Value: 0x0001 0002: CAN reception/transmission frozen during debug. CAN starts in sleep mode.
10 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
It will be necessary to place the bxCAN into initialisation mode then perform the bxCAN initialisation (using other registers) and when that is
complete return to the normal mode. The possible code stub is given below. It was decided that for this example the transmitted message
would be transmitted only rather than continously transmit until successful. This required setting bit 4 of the Master Control Register.
For the receive portion of this example an interrupt will be generated when the FIFO buffer is not empty. The code will be:
Bits SJW[1:0] Resynchronisation jump Maximum time quanta CAN hardware can lengthen or shorten a bit to perform
25:24 width resynchronisation.
At reset SJW = 1 giving 1+1 = 2 quanta
11 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
The CAN timing is based on a time quanta tq. Each CAN bit can be between 3 and 25 time quanta in length. Each CAN bit is divided into 3
segments:
1. Synchronization Segment - a bit change is expected to occur within this time segment. It has a fixed length of one time quanta.
2. Bit segment 1 - defines the location of the sample point.
3. Bit segment 3. - defines the location of the transmit point.
Both bit segments can vary in length to compensate for variations in the various nodes of the system. The resynchronization Jump Width
(SJW) defines a bound to the amount of lengthening and shortening of the bit segments. It can be programmed to between 1 and 4 time
quanta.
Timing Example:
(The illustration shows segments 1 and 2 of 2 quanta each making the nominal bit time of 5 time quanta).
For this example assume bit segment 1 = 13, bit segment 2 = 2 and re-synchronization jump width of 4. (These values were used to match
another CAN based system that was used for testing).
12 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
With one time quanta for the synchronisation segment the total bit width is 16 time quanta. For a CAN Baud rate of 50 khz the bit time = 20
us. Each quanta will be 20/16 = 1.25 us. (800kHz). With the APB1 clock of 8Mhz the divider (and BRP) will be 10-1 giving:
Collecting terms:
CAN1->BTR = 0x031C0009;
This example will transmit the message "CAN_Test" with identifier 0x1badcafe. This will be coded in two steps (see diagram)
1. The message will be placed into a message box, and
2. The message will be transferred to the bxCAN registers that will automatically place the message in the required format on the CAN
bus.
typedef struct {
unsigned int id; // 29 bit identifier
unsigned char data[8]; // Data field
unsigned char len; // Length of data field in bytes
unsigned char format; // 0 - STANDARD, 1- EXTENDED IDENTIFIER
unsigned char type; // 0 - DATA FRAME, 1 - REMOTE FRAME
} CAN_msg;
13 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
CAN_msg CAN_TxMsg;
.....
CAN1_TxMsg( );
The next step is to transfer the message to the appropriate transmit registers. The programming structure for the bxCAN hardware was
presented previously. There are 3 transmit mail boxes. This example will use TxMailBox[0]. Note the manual will use a different definition for
the registers. TxMailBox[x].TIR is CAN_TIxR etc where x = 0..2.
Bits 31:21 STID[10:0]/EXID[28:18] Standard or extended identifier Standard (IDE=0) or MSBs extended identifier(IDE=1).
Bits 20:3 EXID[17:0] Extended identifier LSBs of extended identifier.
14 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
1. Programming the extended identifier into bits 31:3 and setting bit 2 to indicate an extended identifier.
2. Clearing bit 1 to indicate it is a data frame.
3. After other actions are complete setting bit 0 to indicate to the hardware there is a new message to send.
CAN mailbox data low and high registers. CAN_TDLxR and CAN_TDHxR
In the example the message is given as msg->data[8] where data is a byte. These bytes will need to be transferred to the mailbox low
and high data registers. Possible code will be:
15 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
CAN mailbox data length control and time stamp register. CAN_TDTxR
CAN mailbox data length control and time stamp register. CAN_TDTxR
16 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
int main( )
{
initCAN1( );
while (1) {
..//other code - need time delay or Tx will hog CAN bus
GPIOE->BSRR = 1<<9; //LED ON for observation on MSO
CAN1_Tx_mess( );
GPIOE->BSRR = 1<<(9+16); // LED OFF
}
}
The developer can gain some confidence that the coding is correct by observing the output waveforms using a logic analyser. The results
are shown below. The top two traces are pins PD.0 and PD.1 while the lower is pin PE.9 which was programmed to toggle as part of the
CAN write code.
17 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
The overview appears to indicate that the CAN is operating correctly. In this example the message takes at least 2.47ms. To allow other
devices access to the bus there should be a delay of greater than this time before this device writes again to the bus.
Observation of the trace verifies the bit width of 20uS as programmed. The data can be read as
0,1,1011,1010,111101,1100,1010,1111,10110,0001,0000,1000......
Decoding this becomes SOF 1,B,A,D,C,A,F,E
The two centre bits (11) in the 'D' indicate extended identifier. The first '0' in the 'E' is bit stuffing. There had already been 5 '1s'.
This data corresponds to the programmed identifier verifying the CAN operation.
Note for the first waveform that the input signal on PD.0 (centre trace) is identical to the output signal on PD.1. This is the situation with no
other CAN device on the bus. Once a second working CAN device is available upon reading the data on the CAN bus it will generate an
acknowledge bit. This is shown as the final pulse on PD.0 - see trace below.
18 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
Trace of CAN bus activity showing acknowledge signal from second device.
Note the second device (and other devices) generate the acknowledge signal if they detect a valid CAN bus message regardless of the
identifier.
For the STMF107 based MCBSTM32C board the received CAN message will appear on pin PD.0. As illustrated below it will be filterd via
the filter and then transfered via firmware to the receiver message box where further actions can be taken.
9. CAN Filters
With the CAN protocol the transmitter broadcasts its message to all devices on the bus. The receiver node then decides - depending on the
identifier value - if the message is needed. To select the required messages the bxCAN Controller has 28 filter banks. Each filter bank x
consists of two 32-bit registers, CAN_FxR0 and CAN_FxR1.
Each filter bank can be scaled independently. Depending on the filter scale a filter bank provides:
1. One or two 32-bit filters for the STDID[10:0], EXTID[17:0], IDE and RTR bits.
19 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
2. Two or four 16-bit filters for the STDID[10:0], RTR, IDE and EXTID[17:15] bits.
To initialise the filters the FINT bit in the Filter Mask Register must be set then cleared to place the filters into active mode.
20 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
void init_filters(void) {
CAN1->FMR |= 1; //init mode for filters
//the filter initialisation goes her
CAN1->FMR &= ~1; // filters now active}
int main( )
{
....other
init_filters();
The software structures that describe the CAN were presented earlier. The structures relevant to the CAN filters are repeated below:
typedef struct
{
__IO uint32_t FR1;
__IO uint32_t FR2;
} CAN_FilterRegister_TypeDef;
typedef struct
{
//many other elements describing the bxCAN registers
CAN_FilterRegister_TypeDef sFilterRegister[28]; 0x240..0x31C
} CAN_TypeDef;
As indicated there are 28 filter registers each consisting of two 32 bit unsigned integers (The IO portion of the definition indicates that the
registers are volatile). As indicated (refer to diagram) these filters can have different modes/functions/definitions depending upon bits in the
FSC and FMB registers.
Bit x of FSC 0: Registers FR0 and FR1 become four 16 bit registers each.
1: Registers FR0 and FR1 are two 32 bit registers
1. FMBx = 1 corresponds to identification (ID) list mode so in 32 bit mode (FSCx=1) RxR0 and RxR1 handle one message each . In ID
mode all 32 message bits must match those in the registers.
2. In mask mode RxR0 specifies the identifier while RxR1 specifies the relevant bits. That is "must match" bits as opposed to "don't
21 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
care".
3. The receive filters are shared between the two CAN buses. Filters 0 to n use CAN1 and n to 27 are for CAN2 where n must be at
least 1.
1. deactivate and activate the corresponding bit in the CAN filter activation register (CAN_FA1R)
2. allocate the FIFO memory bank by setting the corresponding bit in the CAN filter FIFO assignment register (CAN_FFA1R)
In the example only one filter is required. The code has been left general to allow for further filters.
void CAN_wrFilter (unsigned int id, unsigned char format, unsigned char mess_type) {
statis unsigned short CAN_filterIdx = 0; //if multiple filters are to be used
unsigned int CAN_msgId = 0;
// Setup identifier information
if (format == STANDARD_FORMAT) { // Standard ID
CAN_msgId |= (unsigned int)(id << 21) | 0; //CAN_ID_STD;
} else { // Extended ID
CAN_msgId |= (unsigned int)(id << 3) | 4; //CAN_ID_EXT;
}
if (mess_type == REMOTE_FRAME) CAN_msgId |= 2;
// initialize filter
CAN1->FS1R |= (unsigned int)(1 << CAN_filterIdx);// set 32-bit scale configuration
CAN1->FM1R |= (unsigned int)(1 << CAN_filterIdx);// set 2 32-bit identifier list mode
22 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
void init_filters(void) {
CAN1->FMR |= 1; //init mode for filters
CAN_wrFilter (Id0, EXTENDED_FORMAT,DATA_FRAME); //the filter
//other filters if required
CAN1->FMR &= ~1; // reset Initialisation mode for filter banks
}
int main( )
{
....other
init_filters();
For this example interrupts will be used. This will require three actions:
1. Interrupts will need to be enabled in the bxCAN. This was performed as part of the CAN initialisation.
2. Interrupts will need to be enabled at the ARM NVIC (Nested Vector Interrupt controller). From the start up code the CAN receiver
interrupt is number 20.
To enable the interrupt bit 20 in the Interrupt Set Enable Register must be set. With many interrupt sources the Interrupt Set Enable
Register is actually several registers or an array. ISER[0] will handle interrupt request numbers from 0 to 31, ISER[1] will handle
interrupts requests 32 through 63 etc.
NVIC->ISER[0] handles interrupts 0 through 31. That is when IRQn/32 = 0 Bit in ISER[0] = IRQn % 32
NVIC->ISER[1] handles interrupts 32 through 63. That is when IRQn/32 = 0 Bit in ISER[1] = IRQn % 32
NVIC->ISER[2] handles interrupts 64 through 95. That is when IRQn/32 = 0 Bit in ISER[1] = IRQn % 32
23 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
3. An interrupt service routine will need to be written. The start up code has placed the label CAN1_RX0_IRQHandler in the vector
location for this interrupt so this label should be used.
The interrupt routine should incude testing the register CAM_RF0R for the number of received messages in memory FIFO.
Bits 1:0 FMP0[1:0] FIF0 message pending Number of messages pending in receive FIFO.
Increased when hardware stores a new message.
Decreased when software releases the mailbox by setting RFOM0 bit.
The code is given below. It will call the routine CAN_RxMsg that will place the message into variable CAN_RxMsg. See next section for
details.
The final operation is to read the data in the FIFO message bank into the message structure CAN_RxMsg. Refer to structures. For
convenience the CAN_FIFOMailBox_TypeDef and CAN_msg are repeated below.
24 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
typedef struct
{
__IO uint32_t RIR;
__IO uint32_t RDTR;
__IO uint32_t RDLR;
__IO uint32_t RDHR;
} CAN_FIFOMailBox_TypeDef;
typedef struct {
unsigned int id; // 29 bit identifier
unsigned char data[8]; // Data field
unsigned char len; // Length of data field in bytes
unsigned char format; // 0 - STANDARD, 1- EXTENDED IDENTIFIER
unsigned char type; // 0 - DATA FRAME, 1 - REMOTE FRAME
} CAN_msg;
The CAN format is contained in bit 2 of the CAN receive FIFO mailbox identifier register (CAN_RIR)
The required code to read the format, identifier and type from CAN_RIR will be:
25 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
} else { // Extended ID
msg->format = EXTENDED_FORMAT;
msg->id = (unsigned int) 0x1FFFFFFF & ((CAN1->sFIFOMailBox[0].RIR >> 3));
}
// Read type information
if ((CAN1->sFIFOMailBox[0].RIR & 0x2) ==0) {
msg->type = DATA_FRAME; // DATA FRAME
} else {
msg->type = REMOTE_FRAME; // REMOTE FRAME
}
//other actions
}
CAN receive FIFO mailbox data length control and time stamp register (CAN_RDTxR) (x=0..1)
The number of data bytes can be read from bits 3..0 of the register CAN_RDTR.
Bits 3..0 DLC[3..0] Data length code. Maximum 8. 0 in case of remote frame request
CAN receive FIFO mailbox data length control and time stamp register (CAN_RDTxR) (x=0..1)
CAN receive FIFO mailbox data low and high registers (CAN_RDLxR) (CAN_RDHxR) (x=0..1)
26 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
The actual data may be read from the FIFO mailbox registers. Possible code will be:
Connecting the receiver to the talker the following results were obtained.
27 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
1 Talker received signal Consists of its own talk signal plus talk signals from other devices on bus.
Note in the above signal 4 verifies that the receiver recognises a CAN packet on the bus. It is signal 5 that verifies the identifier
(0x1badcafe) has been recognised. To verify the actual message the structure CAN_RxMsg may be displayed using the IDE debugger.
Decoding gives the 32 bit address (little Endian format) 1B,AD,CA,FE, the ASCII data "CAN Test", the number of bytes 8, 01 = extended
address and 00 for data field. as per the message structure:
typedef struct {
unsigned int id; // 29 bit identifier
unsigned char data[8]; // Data field
unsigned char len; // Length of data field in bytes
unsigned char format; // 0 - STANDARD, 1- EXTENDED IDENTIFIER
unsigned char type; // 0 - DATA FRAME, 1 - REMOTE FRAME
} CAN_msg;
With a real CAN system the data field will be actual measurements that will require some further actions.
28 of 29 10/21/2022, 3:10 PM
CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107
Comments
Sign in | Recent Site Activity | Report Abuse | Print Page | Powered By Google Sites
29 of 29 10/21/2022, 3:10 PM