0% found this document useful (0 votes)
3 views13 pages

Expt 8 CAN Bus

The experiment aimed to implement the Controller Area Network (CAN) communication stack on an STM32 microcontroller to facilitate communication between Electronic Control Units (ECUs). Using STM32CubeIDE, the microcontroller was successfully configured to transmit and receive CAN messages, demonstrating its capability for robust communication. The results confirmed that messages adhered to the CAN protocol, showcasing the ease of integration within embedded systems.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views13 pages

Expt 8 CAN Bus

The experiment aimed to implement the Controller Area Network (CAN) communication stack on an STM32 microcontroller to facilitate communication between Electronic Control Units (ECUs). Using STM32CubeIDE, the microcontroller was successfully configured to transmit and receive CAN messages, demonstrating its capability for robust communication. The results confirmed that messages adhered to the CAN protocol, showcasing the ease of integration within embedded systems.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 13

Aim: The objective of this experiment is to implement the Controller Area Network (CAN)

communication stack on an STM32 microcontroller to enable communication between ECUs


(Electronic Control Units) using CAN protocol.

Apparatus and Tools Required


Software
 STM32CubeIDE (for development and debugging)
 Bus Master
Hardware
 STM32 Development Board
 CAN Innomaker
 Jumper wires for hardware connections

Theory
The Controller Area Network (CAN) is a robust communication protocol designed to
facilitate communication between microcontrollers and devices in embedded systems,
especially in automotive and industrial applications. CAN is a multi-master, message-
oriented protocol with high immunity to electrical interference.
STM32 microcontrollers have integrated CAN controllers which allow for the
implementation of CAN communication without needing external CAN controllers. Using
STM32CubeIDE, we can configure the microcontroller’s CAN peripheral and write software
to send and receive CAN messages.
Key Concepts in CAN Communication:
 Message Frames: Data is transmitted in frames. The most common frame types are
Data Frames, Remote Frames, Error Frames, and Overload Frames.
 Identifiers: Each message in CAN is identified by a unique identifier (standard 11-bit
or extended 29-bit).
 Data Length Code (DLC): Specifies the number of data bytes in the message.
 Bitrate: Speed of communication, commonly 125 kbps, 500 kbps, or 1 Mbps.
 Error Handling: CAN provides error detection mechanisms and automatic error
handling.

Fig1: Schematic circuit diagram


Fig 2. Connection Details

1. Connect the CAN transceivers to the STM32 microcontrollers:


o TX Pin of STM32 to TXD of CAN transceiver.
o RX Pin of STM32 to RXD of CAN transceiver.
o CAN_H and CAN_L lines connected between all nodes.
2. Place 120Ω resistors at both ends of the CAN bus.
3. Provide a 5V power supply.

Procedure
 Code Generation and STM32CubeIDE
1. Generate the initialization code open it in STM32CubeIDE.
2. Configure CAN Initialization:
o In main.c, STM32CubeIDE will generate initialization code for the CAN
peripheral. You can add further code to handle the CAN communication.
 Implementing CAN Transmission and Reception
1. CAN Transmission:
o Set up a CAN message structure (CAN_TxHeaderTypeDef and uint8_t
TxData[8]) and configure the transmission parameters such as the message
identifier (CAN_ID), data length, and priority.
o Use HAL_CAN_AddTxMessage function to send data through the CAN bus.

Messages to be transmitted from STM32:

Setting Up Baud Rate: 500KBPS


Output on Bus Master:
Main Code for CAN transceiver:
/* USER CODE BEGIN Header */
/**

***************************************************************************
***
* @file : main.c
* @brief : Main program body

***************************************************************************
***
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*

***************************************************************************
***
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/


/* USER CODE BEGIN Includes */
#include "ancit_can_cyclic_generated.h"
#include "ancit_can_generated.h"
#include "ancit_globals.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/


/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/


/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/


/* USER CODE BEGIN PM */

/* USER CODE END PM */


/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;

CAN_HandleTypeDef hcan;

I2C_HandleTypeDef hi2c1;

TIM_HandleTypeDef htim2;

/* USER CODE BEGIN PV */


global_vars_struct_t gVars;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/


void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_CAN_Init(void);
static void MX_I2C1_Init(void);
static void MX_TIM2_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/


/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */


/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */


MX_GPIO_Init();
MX_ADC1_Init();
MX_CAN_Init();
MX_I2C1_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
/*ANCIT Peripheral Init Code Starts*/
ancit_can_onstart();
HAL_TIM_Base_Start_IT(&htim2);
ancit_can_cyclic_tx_init();
/*ANCIT Peripheral Init Code Ends*/
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */


/*ANCIT Peripheral Main Code Starts*/
ancit_can_main();
ancit_can_cyclic_tx_main();
/*ANCIT Peripheral Main Code Ends*/}
/* USER CODE END 3 */
}

/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

/** Initializes the RCC Oscillators according to the specified parameters


* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}

/** Initializes the CPU, AHB and APB buses clocks


*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|
RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)


{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}

/**
* @brief ADC1 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC1_Init(void)
{

/* USER CODE BEGIN ADC1_Init 0 */

/* USER CODE END ADC1_Init 0 */

ADC_ChannelConfTypeDef sConfig = {0};

/* USER CODE BEGIN ADC1_Init 1 */

/* USER CODE END ADC1_Init 1 */

/** Common config


*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}

/** Configure Regular Channel


*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */

/* USER CODE END ADC1_Init 2 */

/**
* @brief CAN Initialization Function
* @param None
* @retval None
*/
static void MX_CAN_Init(void)
{

/* USER CODE BEGIN CAN_Init 0 */

/* USER CODE END CAN_Init 0 */

/* USER CODE BEGIN CAN_Init 1 */

/* USER CODE END CAN_Init 1 */


hcan.Instance = CAN1;
hcan.Init.Prescaler = 18;
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan.Init.TimeSeg1 = CAN_BS1_2TQ;
hcan.Init.TimeSeg2 = CAN_BS2_1TQ;
hcan.Init.TimeTriggeredMode = DISABLE;
hcan.Init.AutoBusOff = DISABLE;
hcan.Init.AutoWakeUp = DISABLE;
hcan.Init.AutoRetransmission = DISABLE;
hcan.Init.ReceiveFifoLocked = DISABLE;
hcan.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN CAN_Init 2 */

/* USER CODE END CAN_Init 2 */

/**
* @brief I2C1 Initialization Function
* @param None
* @retval None
*/
static void MX_I2C1_Init(void)
{

/* USER CODE BEGIN I2C1_Init 0 */

/* USER CODE END I2C1_Init 0 */

/* USER CODE BEGIN I2C1_Init 1 */

/* USER CODE END I2C1_Init 1 */


hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */

/* USER CODE END I2C1_Init 2 */

/**
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{

/* USER CODE BEGIN TIM2_Init 0 */

/* USER CODE END TIM2_Init 0 */

TIM_ClockConfigTypeDef sClockSourceConfig = {0};


TIM_MasterConfigTypeDef sMasterConfig = {0};

/* USER CODE BEGIN TIM2_Init 1 */

/* USER CODE END TIM2_Init 1 */


htim2.Instance = TIM2;
htim2.Init.Prescaler = 360-1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 100-1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */

/* USER CODE END TIM2_Init 2 */

/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

/* GPIO Ports Clock Enable */


__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();

/*Configure GPIO pin Output Level */


HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);

/*Configure GPIO pin Output Level */


HAL_GPIO_WritePin(GPIOB, LED1_Pin|LED2_Pin, GPIO_PIN_RESET);

/*Configure GPIO pin : PA1 */


GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/*Configure GPIO pin : SW2_Pin */


GPIO_InitStruct.Pin = SW2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(SW2_GPIO_Port, &GPIO_InitStruct);

/*Configure GPIO pin : SW1_Pin */


GPIO_InitStruct.Pin = SW1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(SW1_GPIO_Port, &GPIO_InitStruct);

/*Configure GPIO pins : LED1_Pin LED2_Pin */


GPIO_InitStruct.Pin = LED1_Pin|LED2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

/* USER CODE BEGIN MX_GPIO_Init_2 */


/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

Result:

The STM32 successfully transmits and receives CAN messages, as verified by the CAN
Analyzer or another ECU on the CAN bus. Messages are correctly formatted and adhere to
the CAN protocol (correct IDs, DLC, data content, etc.).

Conclusion
In this experiment, we successfully implemented a CAN communication stack on the STM32
microcontroller using STM32CubeIDE. The STM32 was able to transmit and receive
messages over the CAN bus, demonstrating the microcontroller’s capability to handle robust,
high-speed communication. The experiment highlighted the ease of configuring the CAN
peripheral and integrating communication within an embedded system environment.

You might also like