0% found this document useful (0 votes)
388 views29 pages

CAN - STM32F107 - John Kneen Microcontrollers

The document discusses implementing a CAN bus example using two STM32F107 microcontroller boards. It describes connecting the boards to the CAN bus wires and configuring the alternate functions of the pins to act as CAN transceivers. The example code will transmit a one word message from one board using an identifier and have the other board receive and decode the message.

Uploaded by

Syed Ovais
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
388 views29 pages

CAN - STM32F107 - John Kneen Microcontrollers

The document discusses implementing a CAN bus example using two STM32F107 microcontroller boards. It describes connecting the boards to the CAN bus wires and configuring the alternate functions of the pins to act as CAN transceivers. The example code will transmit a one word message from one board using an identifier and have the other board receive and decode the message.

Uploaded by

Syed Ovais
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

CAN_STM32F107 - John Kneen: Microcontrollers https://sites.google.

com/site/johnkneenmicrocontrollers/19_can_bus/can_stm32f107

John Kneen: Microcontrollers Search this site

Home 28.Keil IDE 15.Clocks 16.Input Output 18.ARM SCI 18a.ARM SPI 18b.ARM I2C

Home 19_CAN_BUS >


00.Summary
01Acronyms CAN_STM32F107
09.Serial Comms
15.Clocks
Clock: LPC1768
Clock: STM32F107
Clock: STM32F407
USB_Clk_1768
16.Input Output STM32F107 CAN Example
NXP LPC1768 IO
STM32F107 IO 1. The CAN-ARM Interface
STM32F407 IO
2. Starting the code.
STM32F429_IO
3. Programming the alternate CAN function.
17.ADC_DAC
4. Structure of the CAN registers.
ADC_F107
5. Configuring the bxCAN
ADC_LPC1768
DAC_F107
6. Transmitting data over CAN
DAC_LPC1768 7. Testing the CAN transmitter.
18.ARM SCI 8. The CAN receiver.
SCI_1768 9. CAN Filters
SCI_F107 10. The CAN receiver code
SCI_F407 11. Decoding the received data.
18a.ARM SPI 12. Testing the CAN receiver.
SPI_F107
SPI_F407
SPI_F429 1. The CAN-ARM Interface
SPI_LPC1768
SSP(SPI)_LPC1768
With the ARM the CAN subsystem is known as bxCAN or Basic Extended CAN. A simplified block diagram of the bxCAN is shown below.
18b.ARM I2C
As shown the ARM contains two CAN interfaces, CAN1 the master and CAN2 the slave.
I2C_LPC1768
I2C_STM32F107
I2C_STM32F407
19_CAN_BUS
CAN_STM32F107
20.Timing
Time_F107
TIME_LPC1768

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

Pin No Main function Alternate function default AF remap KEIL MCBSTM32C


(after reset)
51 PB12 SPI2_NSS /I2S2_WS /I2C2_SMBAL / USART3_CK CAN2_Rx Codec
/TIM1_BKIN /CAN2_RX /ETH_MII_TXD0 /ETH_RMII_TXD0 LRCK
52 PB13 SPI2_SCK /I2S2_CKUSART3_CTS CAN2_Tx Codec
/TIM1_CH1N /CAN2_TX /ETH_MII_TXD1 SCLK
/ETH_RMII_TXD1
70 PA11 USART1_CTS /CAN1_RX /TIM1_CH4(6) /OTG_FS_DM
71 PA12 USART1_RTS /OTG_FS_DPCAN1_TX /TIM1_ETR
81 PD0 /OSC_IN CAN1_RX CAN1_RX
82 PD1 /OSC_OUT CAN1_TX CAN1_TX
91 PB5 I2C1_SMBAl / SPI3_MOSI / ETH_MII_PPS_OUT TIM3_CH2 CAN2_Rx
/ETH_RMII_PPS_OUT /SPI1_MOSI
/CAN2_RX
92 PB6 I2C1_SCL(6) /TIM4_CH1 USART1_TX CAN2_Tx
/CAN2_TX
95 PB8 TIM4_CH3(6) / ETH_MII_TXD3 I2C1_SCL /CAN1_RX I2C_CLK to multiple
devices
96 PB9 TIM4_CH4 I2C1_SDA / I2C_SDA to multiple
CAN1_TX devices

STM32F107VG pins and CAN alternative function.

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.

Programming the bxCAN is broken into four:

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

2. Programming the bxCAN for the desired configuration.


3. Programming the bxCAN transmit mailbox.
4. Reading the bxCAN receive mailbox.
5. Programming the filters.

2. Starting the code.

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

void SystemInit( ) //called by start up code


{
RCC->APB2ENR |= 1 << 6; // Enable GPIOE clock
GPIOE->CRH = 0x33333333; //Configure the GPIO for LEDs
}
void delay(int count)
{
int i;
for (i = 0; i < (count); i++) { };
}
void test( ) //flash LEDs to test
{
GPIOE->BSRR = 1<<8;
delay(1000000);
GPIOE->BSRR = 1<<(8+16);
delay(1000000);
}

int main( )
{
while (1) {
test( );
}
}

Start up code to revise IDE and ARM microcontroller.

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.

3. Programming the alternate CAN function.

Programming the alternate CAN function requires three actions:


▪ Enabling the clocks
▪ Remapping the I/O for the required CAN function.
▪ Programming the pin functions.

Enabling the clocks

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.

Reset and Clock Control - Advanced Peripheral Bus 1 Enable Register

RCC->APB1ENR |= 1&LT;&LT;25; // enable clock for CAN1

Reset and Clock Control - Advanced Peripheral Bus 2 Enable Register

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

RCC-&GT;APB2ENR |= 0x01; // enable clock for Alternate Function

RCC-&GT;APB2ENR |= 1&LT;&LT;5; // enable clock for GPIO D

Remapping the CAN pins.

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.

Alternate Function Input Output Map Register

AFIO-&GT;MAPR &= ~(3&LT;&LT;13); // reset CAN remap


AFIO-&GT;MAPR |= 3&LT;&LT;13; // set CAN remap, use PD0, PD1

Configuring the input-output pins

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:

1. The AF clock to be enabled. -done


2. The clocks to GPIOD to be enabled - done
3. The CAN clock enabled -done
4. The CAN_Rx pin (PD.0) is enabled as either input floating or input pull up.
5. The CAN_Tx pin (PD.1) programmed as AF push pull.
A schematic of the input-output circuit of the ARM microcontroller is given below.

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

Schematic of ARM Input-Output Circuit

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.

STM32F107 General purpose input-output configuration registers

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

General Purpose Input-Output Control Register Low

GPIOD->CRL &= ~(0x0F<<0);


GPIOD->CRL |= (0x08<<0); // CAN RX pin PD.0 input push pull
GPIOD->CRL &= ~(0x0F<<4);
GPIOD->CRL |= (0x0B<<4); //TX pin PD.1 AF output push pull

4. Structure of the CAN registers.

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.
.

typedef struct Offset Reference


{

__IO uint32_t TIR; 0x180/190/1A0 Refer TIxR


__IO uint32_t TDTR; +0x004 Refer TDTxR
__IO uint32_t TDLR; +0x008 Refer TDLxR
__IO uint32_t TDHR; +0x00C Refer TDHxR

} 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

__IO uint32_t MSR; 0x004


__IO uint32_t TSR; 0x008

__IO uint32_t RF0R; 0x00C

__IO uint32_t RF1R; 0x010

__IO uint32_t IER; 0x014 Refer IER

__IO uint32_t ESR; 0x018

__IO uint32_t BTR; 0x01C Refer BTR

uint32_t RESERVED0[88];

CAN_TxMailBox_TypeDef sTxMailBox[3]; 0x180/190/1A0 Refer TxMail

CAN_FIFOMailBox_TypeDef sFIFOMailBox[2]; 0x1B0, 0x1C0

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

__IO uint32_t FMR; 0x200 Refer FMR


__IO uint32_t FM1R; 0x204 Refer filters
uint32_t RESERVED2;
__IO uint32_t FS1R; 0x204 Refer filters
uint32_t RESERVED3;
__IO uint32_t FFA1R; 0x214 Refer filters

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;

C language definitions of CAN registers.

5. Configuring the bxCAN

With this simple example it will only be necessary to initialise the MCR, IER and BTR registers.

Master Control Register

Reset Value: 0x0001 0002: CAN reception/transmission frozen during debug. CAN starts in sleep mode.

Bit 4 NART No automatic retransmission. 0: CAN will retransmit until successful


1: A message will be transmitted once only.

Bit 0 INRQ Initialisation Request 0: Switch hardware into normal mode


1: Initialise CAN hardware.

CAN Master control register CAN_MCR

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.

CAN1->MCR = 1; // init mode


CAN1->MCR |= 1<<4; //no retransmission
other actions
CAN1->MCR &= ~1; // normal operating mode, reset INRQ

Interrupt Enable Register

Reset State 0x0000 0000

BIT 1 FMPIE0 FIFO Message pending interrupt enable 0: No interrupts generated


1: Interrupt generated when message pending in FIFO 0.

CAN Interrupt enable register CAN_IER

For the receive portion of this example an interrupt will be generated when the FIFO buffer is not empty. The code will be:

CAN1->IER = 1<<1; // FIFO 0 msg pending

Bit Timing Register

Reset Value 0x0123 0000. Times SJW = 1, TS2 = 2, TS1 = 3

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

Bits TS2[2:0] Time segment 2 Number of time quanta in segment 2


22:20 At reset TS2=2 giving 2+1 = 3 quanta

Bits TS1[3:0] Time segment 1 Number of time quanta in segment 1


19:16 At reset TS1 = 3 giving 3+1 = 4 quanta
Bits 9:0 BRP[9:0] Baud rate pre-scaler Bits define the length of a time quanta
At reset BRP = 0 giving tq = (0+1)*clock

CAN Bit timing register CAN_BTR

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.

CAN Bit timings

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).

CAN->BTR |= 0xC << 16; //bit segment 1 =13

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

CAN->BTR |= 1 << 20; //bit segment 2 = 2


CAN->BTR |= 3 << 24; //resynchronisation = 4

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:

CAN->BTR |= 9; // tq = 1.25uS with 8MHz clock

Collecting terms:

CAN1-&GT;BTR = 0x031C0009;

6. Transmitting data over CAN

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.

CAN transmit message data path.

The initial step will be to define a structure corresponding to a CAN message.

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 first step will be to initialise the message structure.

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;

void CAN1_Tx_mess( void)


{
char m[8] = "CAN Test";
int i;
GPIOE->BSRR = 1<<9; //LED ON for observation on MSO
CAN_TxMsg.id = Id0; // initialise message to send
for (i = 0; i < 8; i++) CAN_TxMsg.data[i] = m[i];
CAN_TxMsg.len = 8;
CAN_TxMsg.format = EXTENDED_FORMAT;
CAN_TxMsg.type = DATA_FRAME;
CAN1_wrMsg (&CAN_TxMsg); // transmit message
GPIOE->BSRR = 1<<(9+16); // LED OFF
}

.....
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.

CAN Tx mailbox identifier register. CAN_TIxR

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.

Bit 2 IDE Identifier extension 0:Standard identifier


1:Standard identifier
Bit 1 RTR Remote transmission request 0: Data frame
1:Remote frame
Bit 0 TXRQ Transmit mailbox request Set by software to request transmission.
Cleared by hardware when mailbox empty

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

CAN Tx mailbox identifier register. CAN_TIxR

Programming the transmit identifier register will invole 3 steps

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.

Possible code will be:

void CAN1_wrMsg (CAN_msg *msg) {


CAN1->sTxMailBox[0].TIR = (unsigned int)(msg->id << 3) | 4;
if (msg->type == DATA_FRAME)
CAN1->sTxMailBox[0].TIR &= ~(1<<1); //data
else
CAN1->sTxMailBox[0].TIR |= 1<<1; //remote
...other code
CAN1->sTxMailBox[0].TIR |= 1; // transmit message
}

CAN mailbox data low and high registers. CAN_TDLxR and CAN_TDHxR

CAN mailbox data low register. CAN_TDLxR

CAN mailbox data high register. CAN_TDHxR

In the example the message is given as msg-&GT;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

CAN1->sTxMailBox[0].TDLR = (((unsigned int)msg->data[3] << 24) |


((unsigned int)msg->data[2] << 16) |
((unsigned int)msg->data[1] << 8) |
((unsigned int)msg->data[0]) );
CAN1->sTxMailBox[0].TDHR = (((unsigned int)msg->data[7] << 24) |
((unsigned int)msg->data[6] << 16) |
((unsigned int)msg->data[5] << 8) |
((unsigned int)msg->data[4]) );

CAN mailbox data length control and time stamp register. CAN_TDTxR

Bits 3:0 DLC[3:0] Data length Number of bytes in data frame.

CAN mailbox data length control and time stamp register. CAN_TDTxR

In this example the code will be

CAN1->sTxMailBox[0].TDTR &= ~0xf; // Setup length


CAN1->sTxMailBox[0].TDTR |= (msg->len & 0xf);

Collecting code fragments

void CAN1_wrMsg (CAN_msg *msg) {


CAN1->sTxMailBox[0].TIR = (unsigned int)(msg->id << 3) | 4;
if (msg->type == DATA_FRAME) // DATA FRAME
CAN1->sTxMailBox[0].TIR &= ~(1<<1);
else // REMOTE FRAME
CAN1->sTxMailBox[0].TIR |= 1<<1;
CAN1->sTxMailBox[0].TDLR = (((unsigned int)msg->data[3] << 24) |
((unsigned int)msg->data[2] << 16) |
((unsigned int)msg->data[1] << 8) |
((unsigned int)msg->data[0]) );

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

CAN1->sTxMailBox[0].TDHR = (((unsigned int)msg->data[7] << 24) |


((unsigned int)msg->data[6] << 16) |
((unsigned int)msg->data[5] << 8) |
((unsigned int)msg->data[4]) );
CAN1->sTxMailBox[0].TDTR &= ~0xf; // Setup length
CAN1->sTxMailBox[0].TDTR |= (msg->len & 0xf);
CAN1->sTxMailBox[0].TIR |= 1; // transmit message
}
void CAN1_Tx_mess( void)
{
char m[8] = "CAN Test";
int i;
CAN_TxMsg.id = Id0; // initialise message to send
for (i = 0; i < 8; i++) CAN_TxMsg.data[i] = m[i];
CAN_TxMsg.len = 8;
CAN_TxMsg.format = EXTENDED_FORMAT;
CAN_TxMsg.type = DATA_FRAME;
CAN1_wrMsg (&CAN_TxMsg); // transmit message
}

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
}
}

7. Testing the CAN transmitter.

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

Overview of CAN signals

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.

Expanded view of CAN signals

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.

8. The CAN receiver.

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.

CAN received signal path.

As part of the initialisation it will be necessary to configure the filters.

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.

Options with CAN filter bank.

To initialise the filters the FINT bit in the Filter Mask Register must be set then cleared to place the filters into active mode.

CAN Filter Mask Register

Reset value: 0x2A1C0E01

Bits 31:1 Reserved Reserved- must be kept at reset value


Bit 0: FINT Filter initialisation mode. 0: Filters are active
1: Initialisation mode for filters

CAN Filter Mask Register

A possible program stub is:

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 filter structures

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

Bit x of FMB 0: Two registers become an ID plus a mask.


1: Each register is an ID only.

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.

The 32 bit filter layout is as follows:

Bits 31..21 Bits 20..3 Bit 2 BIT 1 Bit 0

STID[10..0]/EXID[28..18] EXID[17..0] IDE RTR 0

Two further actions are required for each filter

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;

CAN1->FA1R &= ~(unsigned int)(1 << CAN_filterIdx); // deactivate filter

// 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

CAN1->sFilterRegister[CAN_filterIdx].FR1 = CAN_msgId; // 32-bit identifier


CAN1->sFilterRegister[CAN_filterIdx].FR2 = CAN_msgId; // 32-bit identifier

CAN1->FFA1R &= ~(unsigned int)(1 << CAN_filterIdx); // assign filter to FIFO 0


CAN1->FA1R |= (unsigned int)(1 << CAN_filterIdx); // activate filter

CAN_filterIdx += 1; // increase filter index


}

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();

10. The CAN receiver code

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.

__Vectors DCD __initial_sp Top of Stack


External Interrupts
DCD CAN1_TX_IRQHandler 19: CAN1 TX
DCD CAN1_RX0_IRQHandler 20: CAN1 RX0
DCD CAN1_RX1_IRQHandler 21: CAN1 RX1
DCD CAN1_SCE_IRQHandler 22: CAN1 SCE
DCD CAN2_RX0_IRQHandler 64: CAN2 RX0
DCD CAN2_RX1_IRQHandler 65: CAN2 RX1
DCD CAN2_SCE_IRQHandler 66: CAN2 SCE

STM32F107 CAN Interrupts - extracted from Keil MDK Start Up Code

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-&GT;ISER[0] handles interrupts 0 through 31. That is when IRQn/32 = 0 Bit in ISER[0] = IRQn % 32
NVIC-&GT;ISER[1] handles interrupts 32 through 63. That is when IRQn/32 = 0 Bit in ISER[1] = IRQn % 32
NVIC-&GT;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

The code will be:

NVIC->ISER[0] |= (1 << 20); // enable CAN1_Rx interrupt

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.

CAN receive FIFO 0 register (CAN_RF0R)

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.

CAN receive FIFO 0 register (CAN_RF0R)

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.

//CAN1 receiver interrupt


void CAN1_RX0_IRQHandler(void) {
GPIOE->BSRR = 1<<10; //LED ON for observation on MSO
if (CAN1->RF0R & 3) { // message pending ?
CAN_rdMsg (&CAN_RxMsg); // read the message
CAN1->RF0R |= 0x20; // Release FIFO 0 output mailbox
}
GPIOE->BSRR = 1<<(10+16); // LED OFF
}

11. Decoding the received data.

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;

CAN receive FIFO mailbox identifier register (CAN_RIxR x=0..1)

The CAN format is contained in bit 2 of the CAN receive FIFO mailbox identifier register (CAN_RIR)

Bits 31..3 STID[10..0]/EXID{28..0] Std or Exd identifier as required.


Bit 2 IDE Identifier extension 0: Standard 1: Extended Identifier

Bit 1 RTR Remote transmission request 0: Data frame 1: Remote frame

CAN receive FIFO mailbox identifier register (CAN_RIxR x=0..1)

The required code to read the format, identifier and type from CAN_RIR will be:

void CAN_rdMsg ( CAN_msg *msg) {


if ((CAN1->sFIFOMailBox[0].RIR & 0x4)==0) { // Standard ID
msg->format = STANDARD_FORMAT;
msg->id = (unsigned int) 0x000007FF & (CAN1->sFIFOMailBox[0].RIR >> 21);

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)

Possible code will be:

msg->len = (unsigned char)0x0000000F & CAN1->sFIFOMailBox[0].RDTR;

CAN receive FIFO mailbox data low and high registers (CAN_RDLxR) (CAN_RDHxR) (x=0..1)

CAN receive FIFO mailbox data low register (CAN_RDLxR) (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

CAN receive FIFO mailbox data high register (CAN_RDLxR) (x=0..1)

The actual data may be read from the FIFO mailbox registers. Possible code will be:

msg->data[0] = (unsigned int)0x000000FF & (CAN1->sFIFOMailBox[0].RDLR);


msg->data[1] = (unsigned int)0x000000FF & (CAN1->sFIFOMailBox[0].RDLR >> 8);
msg->data[2] = (unsigned int)0x000000FF & (CAN1->sFIFOMailBox[0].RDLR >> 16);
msg->data[3] = (unsigned int)0x000000FF & (CAN1->sFIFOMailBox[0].RDLR >> 24);

msg->data[4] = (unsigned int)0x000000FF & (CAN1->sFIFOMailBox[0].RDHR);


msg->data[5] = (unsigned int)0x000000FF & (CAN1->sFIFOMailBox[0].RDHR >> 8);
msg->data[6] = (unsigned int)0x000000FF & (CAN1->sFIFOMailBox[0].RDHR >> 16);
msg->data[7] = (unsigned int)0x000000FF & (CAN1->sFIFOMailBox[0].RDHR >> 24);

12. Testing the CAN receiver.

Connecting the receiver to the talker the following results were obtained.

Firmware reference signals and CAN transmitter and receive signals.

An explanation of the signals is as follows (working from the bottom)

0 Timing spike Generated by software on writing to bxCAN transmitter

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.

2 Talker output signal CAN signal sent by talker to CAN bus


3 Receiver received signal Consists of talker message plus "message" it puts on bus
4 Receiver talk signal An acknowledge bit to acknowledge receipt of talker message.
Note that this bit appears in both received messages (1&3)
5 Timing spike Generated by software when it reads a valid message.

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.

Receiver memory box after CAN activity.

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.

Created by John Kneen RMIT University. Sunday, August 16, 2015

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

ċ CAN_32F107.c (8k) John Kneen, Aug 23, 2015, 8:00 AM v.1 ď

Comments

You do not have permission to add comments.

Sign in | Recent Site Activity | Report Abuse | Print Page | Powered By Google Sites

29 of 29 10/21/2022, 3:10 PM

You might also like