/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2022 FaSTTUBe / Oskar W. * All rights reserved. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include #include /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* * VAL_ 1040 Mission_selection * 1 "MissionSelection_acceleration" * 2 "MissionSelection_skidpad" * 3 "MissionSelection_trackdrive" * 4 "MissionSelection_braketest" * 5 "MissionSelection_inspection" * 6 "MissionSelection_autocross" * 7 "MissionSelection_manual"; */ typedef enum { M_NONE = 0, M_ACCEL = 1, M_SKIDPAD = 2, M_TRACKDRIVE = 3, M_EBSTEST = 4, M_INSPECTION = 5, M_AUTOX = 6, M_MANUAL = 7 } mission_t; /* * BO_ 15 SDCL_rx: 3 ABX * SG_ as_close_sdc : 0|1@1+ (1,0) [0|1] "" SDCL * SG_ sdcl_heartbeat : 1|1@1+ (1,0) [0|1] "" SDCL * SG_ asb_error : 2|1@1+ (1,0) [0|1] "" SDCL * SG_ as_mission : 4|3@1+ (1,0) [0|7] "" SDCL */ typedef union { uint8_t raw[8]; // Must be 8 bytes because HAL always writes 8 bytes struct { // BITFIELDS ARE LSB FIRST! bool as_close_sdc : 1; bool heartbeat : 1; bool asb_error : 1; unsigned int _padding1 : 1; mission_t as_mission : 3; unsigned int _padding2 : 1; } __attribute__((packed)) signals; } rx_data_t; /* * BO_ 16 SDCL_tx: 4 SDCL * SG_ asms_state : 0|1@1+ (1,0) [0|1] "" ABX * SG_ sdc_state_1 : 1|1@1+ (1,0) [0|1] "" ABX * SG_ sdc_state_2 : 2|1@1+ (1,0) [0|1] "" ABX * SG_ sdc_state_3 : 3|1@1+ (1,0) [0|1] "" ABX * SG_ heartbeat_ok : 4|1@1+ (1,0) [0|1] "" ABX * SG_ sdcl_sdc_ready : 5|1@1+ (1,0) [0|1] "" ABX * SG_ ts_start_muxed : 6|1@1+ (1,0) [0|1] "" ABX * SG_ latch_init_open : 8|1@1+ (1,0) [0|1] "" ABX * SG_ latch_closed : 9|1@1+ (1,0) [0|1] "" ABX * SG_ latch_reopened : 10|1@1+ (1,0) [0|1] "" ABX * SG_ as_mission : 11|3@1+ (1,0) [0|7] "" ABX */ typedef union { uint8_t raw[2]; struct { // BITFIELDS ARE LSB FIRST! bool asms_state : 1; bool sdc_state_1 : 1; bool sdc_state_2 : 1; bool sdc_state_3 : 1; bool heartbeat_ok : 1; bool sdc_ready : 1; bool ts_start_muxed : 1; unsigned int _padding1 : 1; // -- byte border bool latch_init_open : 1; bool latch_closed : 1; bool latch_reopened : 1; mission_t as_mission : 3; unsigned int _padding2 : 2; } __attribute__((packed)) signals; } tx_data_t; /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define CAN_ID_RX 0x00F #define CAN_ID_TX 0x010 // Defined in DBC? #define TX_UPDATE_PERIOD 100 #define AMI_GPIO_Port GPIOB //#define WATCHDOG_UCC #define WATCHDOG_STM /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ CAN_HandleTypeDef hcan; IWDG_HandleTypeDef hiwdg; /* USER CODE BEGIN PV */ // Mission Maps: NONE ACCEL SKIDPAD TRACKDRIVE EBSTEST INSPECTION AUTOX MANUAL const uint16_t mission2led[] = {0 , AMI_ACCEL_Pin , AMI_SKIDPAD_Pin , AMI_TRACKDRIVE_Pin, AMI_EBSTEST_Pin , AMI_INSPECTION_Pin, AMI_AUTOX_Pin , AMI_MANUAL_Pin}; const mission_t mission2next[] = {M_MANUAL , M_SKIDPAD , M_AUTOX , M_EBSTEST , M_INSPECTION , M_MANUAL , M_TRACKDRIVE , M_ACCEL }; mission_t mission = M_NONE; #ifdef WATCHDOG_STM bool pHeartbeat = false; bool WD_OK = false; bool WD_initialized = false; #endif /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_CAN_Init(void); static void MX_IWDG_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ void setMissionLED(mission_t mission, GPIO_PinState state) { if (mission != M_NONE) HAL_GPIO_WritePin(AMI_GPIO_Port, mission2led[mission], state); } /* 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 */ MX_GPIO_Init(); MX_CAN_Init(); #if false /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_CAN_Init(); MX_IWDG_Init(); /* USER CODE BEGIN 2 */ #endif // Ensure we start with SDC disabled HAL_GPIO_WritePin(Watchdog_GPIO_Port, Watchdog_Pin, GPIO_PIN_RESET); if (HAL_CAN_Start(&hcan) != HAL_OK) Error_Handler(); CAN_FilterTypeDef canfilterconfig; canfilterconfig.FilterActivation = CAN_FILTER_ENABLE; canfilterconfig.FilterBank = 0; canfilterconfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; canfilterconfig.FilterIdHigh = CAN_ID_RX << (16 - 11); canfilterconfig.FilterIdLow = 0; canfilterconfig.FilterMaskIdHigh = 0x7FF << (16 - 11); canfilterconfig.FilterMaskIdLow = 0; canfilterconfig.FilterMode = CAN_FILTERMODE_IDMASK; canfilterconfig.FilterScale = CAN_FILTERSCALE_32BIT; canfilterconfig.SlaveStartFilterBank = 14; if (HAL_CAN_ConfigFilter(&hcan, &canfilterconfig) != HAL_OK) { Error_Handler(); } if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) Error_Handler(); CAN_TxHeaderTypeDef txHeader; uint32_t txMailbox; tx_data_t txData; memset(&txData, 0, sizeof(tx_data_t)); // Prep the tx frame txHeader.IDE = CAN_ID_STD; txHeader.StdId = CAN_ID_TX; txHeader.RTR = CAN_RTR_DATA; txHeader.DLC = 2; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ bool pAMC = false; mission_t new_mission = mission; // By default, don't change mission // Important to prevent bus error state while ABX is starting up HAL_Delay(1000); MX_IWDG_Init(); WD_initialized = true; while (true) { bool TS_activate_MUXed = HAL_GPIO_ReadPin(TS_activate_MUXed_GPIO_Port, TS_activate_MUXed_Pin) == GPIO_PIN_RESET; bool ASMS = HAL_GPIO_ReadPin(ASMS_GPIO_Port, ASMS_Pin) == GPIO_PIN_RESET; #ifdef WATCHDOG_UCC bool WD_OK = HAL_GPIO_ReadPin(WD_OK_GPIO_Port, WD_OK_Pin) == GPIO_PIN_RESET; #endif bool SDC_is_ready = HAL_GPIO_ReadPin(SDC_is_ready_GPIO_Port, SDC_is_ready_Pin) == GPIO_PIN_SET; bool SDC_in_3V3 = HAL_GPIO_ReadPin(SDC_in_3V3_GPIO_Port, SDC_in_3V3_Pin) == GPIO_PIN_SET; bool LV_SENSE_1 = HAL_GPIO_ReadPin(LV_SENSE_1_GPIO_Port, LV_SENSE_1_Pin) == GPIO_PIN_SET; bool LV_SENSE_2 = HAL_GPIO_ReadPin(LV_SENSE_2_GPIO_Port, LV_SENSE_2_Pin) == GPIO_PIN_SET; bool INITIAL_OPEN = HAL_GPIO_ReadPin(INITIAL_OPEN_GPIO_Port, INITIAL_OPEN_Pin) == GPIO_PIN_RESET; bool CLOSED = HAL_GPIO_ReadPin(CLOSED_GPIO_Port, CLOSED_Pin) == GPIO_PIN_RESET; bool REOPENED = HAL_GPIO_ReadPin(REOPENED_GPIO_Port, REOPENED_Pin) == GPIO_PIN_RESET; bool AMC = HAL_GPIO_ReadPin(AMC_GPIO_Port, AMC_Pin) == GPIO_PIN_SET; // On signal edge. Debouncing usually not needed at these polling rates (10Hz) if (AMC < pAMC) { // Reset LED to indicate transaction / mission change in progress setMissionLED(mission, GPIO_PIN_RESET); new_mission = mission2next[mission]; // New LED will be set once response from ABX is received } txData = (tx_data_t) { .signals = { .asms_state = ASMS, .sdc_state_1 = LV_SENSE_1, .sdc_state_2 = LV_SENSE_2, .sdc_state_3 = SDC_in_3V3, .heartbeat_ok = WD_OK, .sdc_ready = SDC_is_ready, .ts_start_muxed = TS_activate_MUXed, .latch_init_open = INITIAL_OPEN, .latch_closed = CLOSED, .latch_reopened = REOPENED, .as_mission = new_mission } }; if (HAL_CAN_AddTxMessage(&hcan, &txHeader, txData.raw, &txMailbox) != HAL_OK) Error_Handler(); // Store previous button value to detect signal edges pAMC = AMC; HAL_Delay(TX_UPDATE_PERIOD); /* 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}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.LSIState = RCC_LSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; 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_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } /** * @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 = CAN; hcan.Init.Prescaler = 1; hcan.Init.Mode = CAN_MODE_NORMAL; hcan.Init.SyncJumpWidth = CAN_SJW_1TQ; hcan.Init.TimeSeg1 = CAN_BS1_13TQ; hcan.Init.TimeSeg2 = CAN_BS2_2TQ; hcan.Init.TimeTriggeredMode = DISABLE; hcan.Init.AutoBusOff = ENABLE; hcan.Init.AutoWakeUp = ENABLE; hcan.Init.AutoRetransmission = ENABLE; 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 IWDG Initialization Function * @param None * @retval None */ static void MX_IWDG_Init(void) { /* USER CODE BEGIN IWDG_Init 0 */ /* USER CODE END IWDG_Init 0 */ /* USER CODE BEGIN IWDG_Init 1 */ /* USER CODE END IWDG_Init 1 */ hiwdg.Instance = IWDG; hiwdg.Init.Prescaler = IWDG_PRESCALER_4; hiwdg.Init.Window = 1000; hiwdg.Init.Reload = 1000; if (HAL_IWDG_Init(&hiwdg) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN IWDG_Init 2 */ /* USER CODE END IWDG_Init 2 */ } /** * @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(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOB, AMI_EBSTEST_Pin|AMI_INSPECTION_Pin|ASB_Error_Pin|AMI_TRACKDRIVE_Pin |AMI_AUTOX_Pin|AMI_SKIDPAD_Pin|AMI_ACCEL_Pin|AMI_MANUAL_Pin, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOA, AS_close_SDC_Pin|Watchdog_Pin, GPIO_PIN_RESET); /*Configure GPIO pins : TS_activate_MUXed_Pin ASMS_Pin INITIAL_OPEN_Pin CLOSED_Pin REOPENED_Pin WD_OK_Pin SDC_is_ready_Pin SDC_in_3V3_Pin AMC_Pin */ GPIO_InitStruct.Pin = TS_activate_MUXed_Pin|ASMS_Pin|INITIAL_OPEN_Pin|CLOSED_Pin |REOPENED_Pin|WD_OK_Pin|SDC_is_ready_Pin|SDC_in_3V3_Pin |AMC_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /*Configure GPIO pins : LV_SENSE_1_Pin LV_SENSE_2_Pin */ GPIO_InitStruct.Pin = LV_SENSE_1_Pin|LV_SENSE_2_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /*Configure GPIO pins : AMI_EBSTEST_Pin AMI_INSPECTION_Pin ASB_Error_Pin AMI_TRACKDRIVE_Pin AMI_AUTOX_Pin AMI_SKIDPAD_Pin AMI_ACCEL_Pin AMI_MANUAL_Pin */ GPIO_InitStruct.Pin = AMI_EBSTEST_Pin|AMI_INSPECTION_Pin|ASB_Error_Pin|AMI_TRACKDRIVE_Pin |AMI_AUTOX_Pin|AMI_SKIDPAD_Pin|AMI_ACCEL_Pin|AMI_MANUAL_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); /*Configure GPIO pins : AS_close_SDC_Pin Watchdog_Pin */ GPIO_InitStruct.Pin = AS_close_SDC_Pin|Watchdog_Pin; 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); } /* USER CODE BEGIN 4 */ // CAN RX interrupt handler void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { CAN_RxHeaderTypeDef rxHeader; rx_data_t rxData; // Read frame from HW into buffer if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, rxData.raw) != HAL_OK) Error_Handler(); // Discard if it's not for us (shouldn't happen thanks to filter, but just to be sure) if (rxHeader.StdId != CAN_ID_RX) return; HAL_GPIO_WritePin(ASB_Error_GPIO_Port, ASB_Error_Pin, rxData.signals.asb_error); HAL_GPIO_WritePin(AS_close_SDC_GPIO_Port, AS_close_SDC_Pin, rxData.signals.as_close_sdc); #ifdef WATCHDOG_STM if (rxData.signals.heartbeat != pHeartbeat) { if (WD_initialized) HAL_IWDG_Refresh(&hiwdg); WD_OK = true; HAL_GPIO_WritePin(Watchdog_GPIO_Port, Watchdog_Pin, GPIO_PIN_SET); } pHeartbeat = rxData.signals.heartbeat; #endif #ifdef WATCHDOG_UCC HAL_GPIO_WritePin(Watchdog_GPIO_Port, Watchdog_Pin, rxData.signals.heartbeat); #endif // Reset old mission LED setMissionLED(mission, GPIO_PIN_RESET); mission = rxData.signals.as_mission; setMissionLED(mission, GPIO_PIN_SET); } /* 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 */