Skip to main content
Explorer
November 30, 2024
Solved

CAN TX pin always high in NORMAL mode

  • November 30, 2024
  • 3 replies
  • 1238 views

I'm trying to set up CAN in the Nucleo STM32H723 eval kit, I can see the message written to the CAN RAM, but I dont see any activity on the TX pin using an oscilloscope. The CAN is configured in NORMAL_MODE, I have testes before with EXTERNAL_LOOPBACK and I can receive messages on the same board, but I want to transmit it to the bus.

For now I only have the TX and RX pins, PD1 and PD0, respectively, they aren't connected to anything, not even a transceiver, nor terminating resistors but I assume I should still see something in the TX pin when I'm transmitting.

The code is the following:

 

/* Includes ------------------------------------------------------------------*/
#include "main.h"

FDCAN_HandleTypeDef hfdcan1;

// FDCAN1 Defines
FDCAN_TxHeaderTypeDef TxHeader1;
FDCAN_RxHeaderTypeDef RxHeader1;
uint8_t TxData1[8] = {
		85,85,85,85,
		85,85,85,85
};
uint8_t RxData1[8];

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

 /* USER CODE BEGIN 1 */
	// Configure TX Header for FDCAN1
	TxHeader1.Identifier = 0x55;
	TxHeader1.IdType = FDCAN_STANDARD_ID;
	TxHeader1.TxFrameType = FDCAN_DATA_FRAME;
	TxHeader1.DataLength = FDCAN_DLC_BYTES_8;
	TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
	TxHeader1.BitRateSwitch = FDCAN_BRS_OFF;
	TxHeader1.FDFormat = FDCAN_FD_CAN;
	TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
	TxHeader1.MessageMarker = 0;
 /* 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_FDCAN1_Init();
 /* USER CODE BEGIN 2 */


 if(HAL_FDCAN_Start(&hfdcan1)!= HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE END 2 */

 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	 if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, TxData1)!= HAL_OK)
	 {
	 Error_Handler();
	 }

	 HAL_Delay (1000);
 /* USER CODE END WHILE */

 /* USER CODE BEGIN 3 */
 }
 /* USER CODE END 3 */
}

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

 /** Supply configuration update enable
 */
 HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

 /** Configure the main internal regulator output voltage
 */
 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

 while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

 /** Initializes the RCC Oscillators according to the specified parameters
 * in the RCC_OscInitTypeDef structure.
 */
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
 RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
 RCC_OscInitStruct.PLL.PLLM = 4;
 RCC_OscInitStruct.PLL.PLLN = 275;
 RCC_OscInitStruct.PLL.PLLP = 1;
 RCC_OscInitStruct.PLL.PLLQ = 4;
 RCC_OscInitStruct.PLL.PLLR = 2;
 RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;
 RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
 RCC_OscInitStruct.PLL.PLLFRACN = 0;
 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_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
 RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
 RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
 RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
 RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
 RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
 {
 Error_Handler();
 }
}

/**
 * @brief FDCAN1 Initialization Function
 * @PAram None
 * @retval None
 */
static void MX_FDCAN1_Init(void)
{

 /* USER CODE BEGIN FDCAN1_Init 0 */

 /* USER CODE END FDCAN1_Init 0 */

 /* USER CODE BEGIN FDCAN1_Init 1 */

 /* USER CODE END FDCAN1_Init 1 */
 hfdcan1.Instance = FDCAN1;
 hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
 hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
 hfdcan1.Init.AutoRetransmission = DISABLE;
 hfdcan1.Init.TransmitPause = DISABLE;
 hfdcan1.Init.ProtocolException = DISABLE;
 hfdcan1.Init.NominalPrescaler = 11;
 hfdcan1.Init.NominalSyncJumpWidth = 1;
 hfdcan1.Init.NominalTimeSeg1 = 17;
 hfdcan1.Init.NominalTimeSeg2 = 7;
 hfdcan1.Init.DataPrescaler = 25;
 hfdcan1.Init.DataSyncJumpWidth = 1;
 hfdcan1.Init.DataTimeSeg1 = 5;
 hfdcan1.Init.DataTimeSeg2 = 3;
 hfdcan1.Init.MessageRAMOffset = 0;
 hfdcan1.Init.StdFiltersNbr = 0;
 hfdcan1.Init.ExtFiltersNbr = 0;
 hfdcan1.Init.RxFifo0ElmtsNbr = 1;
 hfdcan1.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
 hfdcan1.Init.RxFifo1ElmtsNbr = 0;
 hfdcan1.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8;
 hfdcan1.Init.RxBuffersNbr = 0;
 hfdcan1.Init.RxBufferSize = FDCAN_DATA_BYTES_8;
 hfdcan1.Init.TxEventsNbr = 0;
 hfdcan1.Init.TxBuffersNbr = 0;
 hfdcan1.Init.TxFifoQueueElmtsNbr = 1;
 hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
 hfdcan1.Init.TxElmtSize = FDCAN_DATA_BYTES_8;
 if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN FDCAN1_Init 2 */

 /* USER CODE END FDCAN1_Init 2 */

}

 

and HAL_FDCAN_Init itself calls, which configures the TX and RX pins, PD1 and PD0 respectively. 

void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* hfdcan)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
 if(hfdcan->Instance==FDCAN1)
 {
 /* USER CODE BEGIN FDCAN1_MspInit 0 */

 /* USER CODE END FDCAN1_MspInit 0 */

 /** Initializes the peripherals clock
 */
 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
 PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL;
 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
 {
 Error_Handler();
 }

 /* Peripheral clock enable */
 __HAL_RCC_FDCAN_CLK_ENABLE();

 __HAL_RCC_GPIOD_CLK_ENABLE();
 /**FDCAN1 GPIO Configuration
 PD0 ------> FDCAN1_RX
 PD1 ------> FDCAN1_TX
 */
 GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
 HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

 /* USER CODE BEGIN FDCAN1_MspInit 1 */

 /* USER CODE END FDCAN1_MspInit 1 */

 }

}

Note the use of 85 to see it clearly on the oscillsocope, but I am not getting anything on the TX line.
How is the message sent after it is written to RAM?
Thanks.

 

    This topic has been closed for replies.
    Best answer by mƎALLEm

    Hello @MudKIP ,

    You cannot use CAN in Normal mode without establishing a complete CAN bus i.e. at least two CAN nodes as shown in the following figure:

    CAN_bus_structure.png

    CAN is not UART or SPI so you can simply run a  transmit program and watch what happening on Tx pin!

    CAN has an acknowledgement mechanism that needs to the receiver to send an acknowledgement bit to the sender so the latter knows that the frame received well. That's why the Loopback mode is there to test CAN without a CAN bus. In the loopback mode, the acknowledgement is sent internally.

    So for normal mode as shown by the figure above, you need two nodes, each node has a controller + CAN transceiver. Otherwise it will never work.

    Hope that answers your question.

    3 replies

    Graduate II
    December 1, 2024

    CAN checks for echo of the transmitted bit to check for collision. If you connect it to bus via CAN transreceiver and another active CAN node, you may observe the transmitted frames. 

    mƎALLEmAnswer
    Technical Moderator
    December 2, 2024

    Hello @MudKIP ,

    You cannot use CAN in Normal mode without establishing a complete CAN bus i.e. at least two CAN nodes as shown in the following figure:

    CAN_bus_structure.png

    CAN is not UART or SPI so you can simply run a  transmit program and watch what happening on Tx pin!

    CAN has an acknowledgement mechanism that needs to the receiver to send an acknowledgement bit to the sender so the latter knows that the frame received well. That's why the Loopback mode is there to test CAN without a CAN bus. In the loopback mode, the acknowledgement is sent internally.

    So for normal mode as shown by the figure above, you need two nodes, each node has a controller + CAN transceiver. Otherwise it will never work.

    Hope that answers your question.

    MudKIPAuthor
    Explorer
    December 8, 2024

    Thanks, I solved it, I configured it in External loopback mode and was able to get stuff on the TX lines. However there were more issues regarding the transceiver soldering and CAN bus. 

    basically the problem was that there was no CAN bus because the transceiver was not leaving the bus open, thanks for letting me know that there needs to be a connections established, otherwise the TX pin will not transmit anything.