cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G0B1KET6 CAN Bus-error

JSVENS3
Visitor

Now I've been sitting here for 2 long day's and still haven't been able to solve the BUS-error problem.

I'm logging with Kvaser USB CAN card so what I want to see right now is some healthy frames coming out from it, but no, only bus-errors, so I thought it was time to ask the community about it.

I'm not a newbie in CAN and I've made an earlier project with STM32F302R8 which worked fine, but with this processor I seem to be stuck.

The main.c attached is only me trying to get the interfaces up and running.

What is strange is also the FDCAN Protocol status which doesn't seem to give me correct info, for example the "Activity status" which seems to be 8.

Are there a friendly soul somewhere that could help me out?

Intention is to get the classic CAN working and then Move over to CANFD. (With a different PC CAN interface of course)

Thank you in advance,

Johan

[FDCAN] Classic 125 kbit/s up (PCLK1=64000000 Hz)

[FDCAN] LEC=7, DLE=7, ACT=8, EP=0, Warn=0, BO=0, RxESI=0, RxBRS=0, RxFD=0, PE=0, TDC=0,


Clock check: SYSCLK=64000000 HCLK=64000000 PCLK1=64000000

 

JSVENS3_0-1762894629986.png

JSVENS3_1-1762894931164.png

 

 

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stm32g0xx_hal.h"
#include "stm32g0xx_hal_fdcan.h"

#define CAN_LOG(fmt, ...)  do { printf(fmt, ##__VA_ARGS__); } while(0)


/* Defer IRQ info to main loop */
static volatile uint8_t  g_flag_rx = 0;
static volatile uint32_t g_rx_id   = 0;
static volatile uint8_t  g_rx_len  = 0;
static volatile uint8_t  g_rx_pay[64];

static volatile uint8_t  g_flag_err = 0;
static volatile uint32_t g_err_hal  = 0;
static volatile uint8_t  g_tec = 0, g_rec = 0;
/* 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;
FDCAN_HandleTypeDef hfdcan1;
SPI_HandleTypeDef   hspi1;
UART_HandleTypeDef  huart2;

/* USER CODE BEGIN PV */
/* --- Minimal CLI state --- */
#define CLI_BUFSZ 64
static volatile uint8_t cli_ch;     // last received char (IT)
static char             cli_buf[CLI_BUFSZ];
static uint8_t          cli_len = 0;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void        SystemClock_Config(void);                // (kept, unused)
static void SystemClock_Config_HSE12_PLL64(void);    // <— used
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_ADC1_Init(void);
static void MX_FDCAN1_Init(void);
static void MX_SPI1_Init(void);
/* USER CODE BEGIN PFP */
static void Menu_Print(void);
static void CLI_Start(void);
static void CLI_ProcessChar(char c);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int __io_putchar(int ch){
  extern UART_HandleTypeDef huart2;
  HAL_UART_Transmit(&huart2,(uint8_t*)&ch,1,10);
  return ch;
}

static void SystemClock_Config_HSE12_PLL64(void)
{
  RCC_OscInitTypeDef osc = {0};
  RCC_ClkInitTypeDef  clk = {0};

  /* Voltage scaling for 64 MHz */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  /* Try HSE crystal first (not BYPASS) */
  osc.OscillatorType      = RCC_OSCILLATORTYPE_HSE;
  osc.HSEState            = RCC_HSE_ON;       /* crystal */
  osc.PLL.PLLState        = RCC_PLL_ON;
  osc.PLL.PLLSource       = RCC_PLLSOURCE_HSE;/* 12 MHz */
  osc.PLL.PLLM            = RCC_PLLM_DIV3;    /* 12/3 = 4 MHz */
  osc.PLL.PLLN            = 32;               /* 4*32 = 128 MHz VCO */
  osc.PLL.PLLR            = RCC_PLLR_DIV2;    /* 128/2 = 64 MHz SYSCLK */
  osc.PLL.PLLQ            = RCC_PLLQ_DIV2;
  osc.PLL.PLLP            = RCC_PLLP_DIV2;

  if (HAL_RCC_OscConfig(&osc) != HAL_OK) {
    /* HSE failed to start → fallback to HSI16@64MHz */
fallback_hsi:
    osc = (RCC_OscInitTypeDef){0};
    osc.OscillatorType      = RCC_OSCILLATORTYPE_HSI;
    osc.HSIState            = RCC_HSI_ON;
    osc.HSIDiv              = RCC_HSI_DIV1;
    osc.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    osc.PLL.PLLState        = RCC_PLL_ON;
    osc.PLL.PLLSource       = RCC_PLLSOURCE_HSI; /* 16 MHz */
    osc.PLL.PLLM            = RCC_PLLM_DIV2;     /* 16/2 = 8 MHz */
    osc.PLL.PLLN            = 16;                /* 8*16 = 128 MHz */
    osc.PLL.PLLR            = RCC_PLLR_DIV2;     /* 64 MHz */
    osc.PLL.PLLQ            = RCC_PLLQ_DIV2;
    osc.PLL.PLLP            = RCC_PLLP_DIV2;
    if (HAL_RCC_OscConfig(&osc) != HAL_OK) Error_Handler();
  } else {
    /* Enable Clock Security System (HSE monitor) */
    HAL_RCC_EnableCSS();
  }

  /* SYSCLK = PLL, AHB=1, APB1=1 */
  clk.ClockType      = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1;
  clk.SYSCLKSource   = RCC_SYSCLKSOURCE_PLLCLK;
  clk.AHBCLKDivider  = RCC_SYSCLK_DIV1;
  clk.APB1CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&clk, FLASH_LATENCY_2) != HAL_OK) {
    /* If switch failed, fallback to HSI plan */
    goto fallback_hsi;
  }
}

/* ===== FDCAN self-test ===== */
static volatile uint32_t g_can_rx_count = 0;

static void CAN_Enable_InternalLoopback(void)
{
  HAL_FDCAN_Stop(&hfdcan1);
  // Keep timings as they are; just switch mode
  hfdcan1.Init.Mode = FDCAN_MODE_INTERNAL_LOOPBACK;
  //if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) { printf("\r\n[CAN] Loopback init error\r\n"); return; }

  // Accept all standard IDs into RX FIFO0
  FDCAN_FilterTypeDef flt = (FDCAN_FilterTypeDef){0};
  flt.IdType       = FDCAN_STANDARD_ID;
  flt.FilterIndex  = 0;
  flt.FilterType   = FDCAN_FILTER_MASK;
  flt.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  flt.FilterID1    = 0x000;
  flt.FilterID2    = 0x000;
  HAL_FDCAN_ConfigFilter(&hfdcan1, &flt);

  // RX new message notifications
  HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);

  //if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK) { printf("\r\n[CAN] Start error\r\n"); return; }
  //printf("\r\n[CAN] INTERNAL LOOPBACK ON\r\n> ");
}

static void CAN_Disable_InternalLoopback_NormalMode(void)
{
  HAL_FDCAN_Stop(&hfdcan1);
  hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
  //if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) { printf("\r\n[CAN] Normal init error\r\n"); return; }

  FDCAN_FilterTypeDef flt = (FDCAN_FilterTypeDef){0};
  flt.IdType       = FDCAN_STANDARD_ID;
  flt.FilterIndex  = 0;
  flt.FilterType   = FDCAN_FILTER_MASK;
  flt.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  flt.FilterID1    = 0x000;
  flt.FilterID2    = 0x000;
  HAL_FDCAN_ConfigFilter(&hfdcan1, &flt);

  HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);

  //if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK) { printf("\r\n[CAN] Start error\r\n"); return; }
  printf("\r\n[CAN] NORMAL MODE (bus) ON\r\n> ");
}

/* send one standard CAN frame with 2 bytes payload */
static void CAN_Send_Test(uint16_t id, uint8_t b0, uint8_t b1)
{
  FDCAN_TxHeaderTypeDef H = {0};
  uint8_t P[2] = { b0, b1 };

  H.Identifier     = id & 0x7FF;
  H.IdType         = FDCAN_STANDARD_ID;
  H.TxFrameType    = FDCAN_DATA_FRAME;
  H.FDFormat       = FDCAN_CLASSIC_CAN;
  H.BitRateSwitch  = FDCAN_BRS_OFF;
  H.DataLength     = FDCAN_DLC_BYTES_2;

  while (!HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1)) { /* wait */ }
  if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &H, P) == HAL_OK)
    printf("[CAN] TX id=0x%03X data=%02X %02X\r\n> ", H.Identifier, P[0], P[1]);
  else
    printf("[CAN] TX error\r\n> ");
}
//#define FDCAN_LOG(msg)  do { printf("FDCAN: %s\r\n", msg); } while (0)
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

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

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_ADC1_Init();
  MX_FDCAN1_Init();
  MX_SPI1_Init();

  /* USER CODE BEGIN 2 */
  /* Give the USB-serial a moment to enumerate / settle */
  HAL_Delay(3000);

  for (int i = 0; i < 6; i++) {           // 3 quick blinks ~600 ms
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
    HAL_Delay(100);
  }

  HAL_Delay(300); // let USB-serial enumerate

  printf("\r\nUSART2 minimal menu @115200 8N1 (PA2/PA3)\r\n");
  Menu_Print();
  CLI_Start();
  printf("\r\nClock check: SYSCLK=%lu  HCLK=%lu  PCLK1=%lu\r\n> ",
         HAL_RCC_GetSysClockFreq(), HAL_RCC_GetHCLKFreq(), HAL_RCC_GetPCLK1Freq());
  /* USER CODE END 2 */

  /* Infinite loop */
  while (1)
  {
    /* USER CODE BEGIN 3 */
    static uint32_t can_tx_last = 0;
    if (HAL_GetTick() - can_tx_last >= 200) {
      can_tx_last = HAL_GetTick();

      FDCAN_TxHeaderTypeDef TxH = {0};
      uint8_t payload[2] = { 0x12, 0x34 };   // example data

      TxH.Identifier          = 0x123;                  // 11-bit ID
      TxH.IdType              = FDCAN_STANDARD_ID;
      TxH.TxFrameType         = FDCAN_DATA_FRAME;
      TxH.FDFormat            = FDCAN_CLASSIC_CAN;      // *** Classic ***
      TxH.BitRateSwitch       = FDCAN_BRS_OFF;          // no BRS in Classic
      TxH.DataLength          = FDCAN_DLC_BYTES_2;      // 2 data bytes
      TxH.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
      TxH.TxEventFifoControl  = FDCAN_NO_TX_EVENTS;     // or FDCAN_STORE_TX_EVENTS
      TxH.MessageMarker       = 0;

      if (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) > 0) {
        (void)HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxH, payload);
      }
    }
    /* USER CODE END 3 */
  }
}

/**
  * @brief ADC1 Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler        = ADC_CLOCK_SYNC_PCLK_DIV2;
  hadc1.Init.Resolution            = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign             = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode          = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection          = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait      = DISABLE;
  hadc1.Init.LowPowerAutoPowerOff  = DISABLE;
  hadc1.Init.ContinuousConvMode    = DISABLE;
  hadc1.Init.NbrOfConversion       = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv      = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun               = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.SamplingTimeCommon1   = ADC_SAMPLETIME_1CYCLE_5;
  hadc1.Init.SamplingTimeCommon2   = ADC_SAMPLETIME_1CYCLE_5;
  hadc1.Init.OversamplingMode      = DISABLE;
  hadc1.Init.TriggerFrequencyMode  = ADC_TRIGGER_FREQ_HIGH;
  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_SAMPLINGTIME_COMMON_1;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); }
}

/**
  * @brief FDCAN1 Initialization Function
  * @PAram None
  * @retval None
  */

static void MX_FDCAN1_Init(void)
{
  /* Ensure FDCAN kernel clock = PCLK1 (64 MHz) */
	RCC_PeriphCLKInitTypeDef periph = {0};
	  periph.PeriphClockSelection = RCC_PERIPHCLK_FDCAN | RCC_PERIPHCLK_USART2;
	  periph.FdcanClockSelection  = RCC_FDCANCLKSOURCE_HSE;     // choose PCLK1 = 64 MHz
	  periph.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;    // keep USART2 on PCLK1
	  if (HAL_RCCEx_PeriphCLKConfig(&periph) != HAL_OK)
	  {
	    Error_Handler();
	  }

  hfdcan1.Instance                    = FDCAN1;
  hfdcan1.Init.ClockDivider           = FDCAN_CLOCK_DIV1;     // kernel = PCLK1
  hfdcan1.Init.FrameFormat            = FDCAN_FRAME_CLASSIC;  // CLASSIC first
  hfdcan1.Init.Mode                   = FDCAN_MODE_NORMAL;    // NORMAL mode
  hfdcan1.Init.AutoRetransmission     = DISABLE;
  hfdcan1.Init.TransmitPause          = DISABLE;
  hfdcan1.Init.ProtocolException      = ENABLE;

  /* 125 kbit/s nominal @ PCLK1=64 MHz:
     Presc=32, TSEG1=13, TSEG2=2, SJW=1  -> 1+13+2 = 16 tq, 64e6/(32*16)=125k */
  hfdcan1.Init.NominalPrescaler       = 32;
  hfdcan1.Init.NominalTimeSeg1        = 13;
  hfdcan1.Init.NominalTimeSeg2        = 2;
  hfdcan1.Init.NominalSyncJumpWidth   = 1;

  /* Data phase (not used in Classic) – mirror nominal to keep HAL happy */
  hfdcan1.Init.DataPrescaler          = 32;
  hfdcan1.Init.DataTimeSeg1           = 13;
  hfdcan1.Init.DataTimeSeg2           = 2;
  hfdcan1.Init.DataSyncJumpWidth      = 1;

  hfdcan1.Init.StdFiltersNbr          = 1;
  hfdcan1.Init.ExtFiltersNbr          = 0;
  hfdcan1.Init.TxFifoQueueMode        = FDCAN_TX_FIFO_OPERATION;



  if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) { Error_Handler(); }

  /* Accept ALL standard IDs into RX FIFO0 */
  FDCAN_FilterTypeDef flt = {0};
  flt.IdType       = FDCAN_STANDARD_ID;
  flt.FilterIndex  = 0;
  flt.FilterType   = FDCAN_FILTER_MASK;
  flt.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  flt.FilterID1    = 0x000;
  flt.FilterID2    = 0x000;   // mask=0 -> accept all
  if (HAL_FDCAN_ConfigFilter(&hfdcan1, &flt) != HAL_OK) { Error_Handler(); }

  /* Only RX-new-message for bring-up; add error IRQ later if needed */
  if (HAL_FDCAN_ActivateNotification(&hfdcan1,
        FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK) { Error_Handler(); }

  /* NVIC (shared with TIM16/TIM17 on G0) */
  HAL_NVIC_SetPriority(TIM16_FDCAN_IT0_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(TIM16_FDCAN_IT0_IRQn);
  HAL_NVIC_SetPriority(TIM17_FDCAN_IT1_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(TIM17_FDCAN_IT1_IRQn);

  if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK) {
      Error_Handler();
  }
  FDCAN_ProtocolStatusTypeDef ps;
#define FDCAN_ACTIVITY_SYNCH   0
#define FDCAN_ACTIVITY_IDLE    1
#define FDCAN_ACTIVITY_TX      2
#define FDCAN_ACTIVITY_RX      3
  uint32_t t0 = HAL_GetTick();
  do {
    HAL_FDCAN_GetProtocolStatus(&hfdcan1, &ps);
    if (ps.BusOff) break;                   // give up if bus-off
  } while (ps.Activity == FDCAN_ACTIVITY_SYNCH &&
           (HAL_GetTick() - t0) < 10);      // wait up to ~10 ms

  /* --- Print protocol status --- */
 // FDCAN_ProtocolStatusTypeDef ps;
  HAL_FDCAN_GetProtocolStatus(&hfdcan1, &ps);
  printf("[FDCAN] LEC=%lu, DLE=%lu, ACT=%lu, EP=%lu, Warn=%lu, BO=%lu, RxESI=%lu, RxBRS=%lu, RxFD=%lu, PE=%lu, TDC=%lu,\r\n> ",
         (unsigned long)ps.LastErrorCode,
         (unsigned long)ps.DataLastErrorCode,
		 (unsigned long)ps.Activity,
		 (unsigned long)ps.ErrorPassive,
		 (unsigned long)ps.Warning,
		 (unsigned long)ps.BusOff,
		 (unsigned long)ps.RxESIflag,
		 (unsigned long)ps.RxBRSflag,
		 (unsigned long)ps.RxFDFflag,
		 (unsigned long)ps.ProtocolException,
         (unsigned long)ps.TDCvalue);


  CAN_LOG("\r\n[FDCAN] Classic 125 kbit/s up (PCLK1=%lu Hz)\r\n> ",
          (unsigned long)HAL_RCC_GetPCLK1Freq());
}
/**
  * @brief SPI1 Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_SPI1_Init(void)
{
  /* SPI1 parameter configuration*/
  hspi1.Instance               = SPI1;
  hspi1.Init.Mode              = SPI_MODE_MASTER;
  hspi1.Init.Direction         = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize          = SPI_DATASIZE_4BIT;
  hspi1.Init.CLKPolarity       = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase          = SPI_PHASE_1EDGE;
  hspi1.Init.NSS               = SPI_NSS_HARD_OUTPUT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit          = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode            = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial     = 7;
  hspi1.Init.CRCLength         = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode          = SPI_NSS_PULSE_ENABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK) { Error_Handler(); }
}

/**
  * @brief USART2 Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{
  /* Use APB1 as UART2 kernel clock */
  RCC_PeriphCLKInitTypeDef periph = {0};
  periph.PeriphClockSelection = RCC_PERIPHCLK_USART2;
  periph.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&periph) != HAL_OK) Error_Handler();

  huart2.Instance                    = USART2;
  huart2.Init.BaudRate               = 115200;
  huart2.Init.WordLength             = UART_WORDLENGTH_8B;
  huart2.Init.StopBits               = UART_STOPBITS_1;
  huart2.Init.Parity                 = UART_PARITY_NONE;
  huart2.Init.Mode                   = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl              = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling           = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling         = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.Init.ClockPrescaler         = UART_PRESCALER_DIV1;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK) { Error_Handler(); }

  if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK) { Error_Handler(); }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK) { Error_Handler(); }
  if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK) { Error_Handler(); }

  HAL_NVIC_SetPriority(USART2_LPUART2_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(USART2_LPUART2_IRQn);
}

/**
  * @brief GPIO Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /* LED PB8 */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
  GPIO_InitStruct.Pin   = GPIO_PIN_8;
  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);

  /* --------- FDCAN1 pins: PA11=RX, PA12=TX (AF3) --------- */
  GPIO_InitTypeDef GPIO_InitStructF = {0};
  GPIO_InitStructF.Pin       = GPIO_PIN_11 | GPIO_PIN_12;
  GPIO_InitStructF.Mode      = GPIO_MODE_AF_PP;
  GPIO_InitStructF.Pull      = GPIO_NOPULL;               // usually no pull
  GPIO_InitStructF.Speed     = GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStructF.Alternate = GPIO_AF3_FDCAN1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStructF);
}

/* USER CODE BEGIN 4 */

/* Print the menu */
static void Menu_Print(void){
  printf("\r\n=== UART Menu ===\r\n");
  printf(" 1) Say hello\r\n");
  printf(" 2) Set number (1..6)\r\n");
  printf(" s) Show status\r\n");
  printf(" h) Help / show menu\r\n> ");
}

/* Start CLI reception (enable RX interrupt) */
static void CLI_Start(void){
  HAL_UART_Receive_IT(&huart2,(uint8_t*)&cli_ch,1);
  printf("\r\nCLI ready. Type 'h' for help.\r\n");
  printf("> ");
}

/* Process a single char (line editing + commands) */
static void CLI_ProcessChar(char c){
  /* simple line edit: CR/LF submits, backspace supported */
  if (c == '\r' || c == '\n'){
    cli_buf[cli_len] = 0;

    if (cli_len == 0) { printf("\r\n> "); return; }

    /* commands */
    if (!strcmp(cli_buf,"1")){
      printf("\r\nHello from STM32!\r\n");
    } else if (!strcmp(cli_buf,"2")){
      printf("\r\nEnter number 1..6: ");
      /* read a quick single line synchronously for demo */
      char tmp[8]={0}; uint8_t i=0,ch=0;
      do {
        if (HAL_UART_Receive(&huart2,&ch,1,HAL_MAX_DELAY)==HAL_OK){
          if (ch=='\r' || c=='\n') break;
          if (i<sizeof(tmp)-1){ tmp[i++]=(char)ch; HAL_UART_Transmit(&huart2,&ch,1,10); }
        }
      } while (1);
      int n = atoi(tmp);
      if (n>=1 && n<=6) printf("\r\nOK, number set to %d\r\n", n);
      else             printf("\r\nERR: out of range\r\n");
    } else if (!strcmp(cli_buf,"s") || !strcmp(cli_buf,"S")){
      printf("\r\nStatus: USART2 OK, baud per init.\r\n");
    } else if (!strcmp(cli_buf,"h") || !strcmp(cli_buf,"H")){
      Menu_Print();
      cli_len = 0;
      return;
    } else {
      printf("\r\nUnknown. Type 'h'.\r\n");
    }

    /* reset line buffer */
    cli_len = 0;
    printf("> ");
    return;
  }

  /* Backspace handling */
  if (c == 0x08 || c == 0x7F){
    if (cli_len){
      cli_len--;
      const char bs[3] = {0x08,' ',0x08};
      HAL_UART_Transmit(&huart2,(uint8_t*)bs,3,10);
    }
    return;
  }

  /* regular char */
  if (cli_len < (CLI_BUFSZ-1)){
    cli_buf[cli_len++] = c;
    HAL_UART_Transmit(&huart2,(uint8_t*)&c,1,10); // echo
  }
}

/* RX interrupt callback: feed the CLI */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *hu){
  if (hu->Instance == USART2){
    uint8_t c = cli_ch;
    CLI_ProcessChar((char)c);
    HAL_UART_Receive_IT(&huart2,(uint8_t*)&cli_ch,1);
  }
}

/* USER CODE BEGIN 4 - FDCAN callbacks */
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *h, uint32_t it)
{
  if ((h != &hfdcan1) || !(it & FDCAN_IT_RX_FIFO0_NEW_MESSAGE)) return;

  FDCAN_RxHeaderTypeDef RxH;
  uint8_t P[64];
  if (HAL_FDCAN_GetRxMessage(h, FDCAN_RX_FIFO0, &RxH, P) == HAL_OK) {
    uint32_t len = (RxH.DataLength >> 16); if (len > 64) len = 64;
    g_rx_id  = RxH.Identifier & 0x7FF;
    g_rx_len = (uint8_t)len;
    for (uint8_t i=0;i<g_rx_len;i++) g_rx_pay[i] = P[i];
    g_flag_rx = 1;            // signal main loop to print
  }
}

void HAL_FDCAN_ErrorCallback(FDCAN_HandleTypeDef *h)
{
  if (h != &hfdcan1) return;
  FDCAN_ErrorCountersTypeDef ec;
  HAL_FDCAN_GetErrorCounters(h, &ec);
  g_tec = ec.TxErrorCnt;
  g_rec = ec.RxErrorCnt;
  g_err_hal = HAL_FDCAN_GetError(h);
  g_flag_err = 1;             // signal main loop to print
}
/* USER CODE END 4 - FDCAN callbacks */
/* USER CODE END 4 */

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

#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 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) */
}
#endif /* USE_FULL_ASSERT */

 

0 REPLIES 0