You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					381 lines
				
				16 KiB
			
		
		
			
		
	
	
					381 lines
				
				16 KiB
			| 
								 
											2 years ago
										 
									 | 
							
								#include <stdint.h>
							 | 
						||
| 
								 | 
							
								#include <stdbool.h>
							 | 
						||
| 
								 | 
							
								#include "libc.h"
							 | 
						||
| 
								 | 
							
								#include "stm32f4xx_hal.h"
							 | 
						||
| 
								 | 
							
								#include "defines.h"
							 | 
						||
| 
								 | 
							
								#include "config.h"
							 | 
						||
| 
								 | 
							
								#include "setup.h"
							 | 
						||
| 
								 | 
							
								#include "util.h"
							 | 
						||
| 
								 | 
							
								#include "bldc/BLDC_controller.h"      /* BLDC's header file */
							 | 
						||
| 
								 | 
							
								#include "bldc/rtwtypes.h"
							 | 
						||
| 
								 | 
							
								#include "version.h"
							 | 
						||
| 
								 | 
							
								#include "obj/gitversion.h"
							 | 
						||
| 
								 | 
							
								#include "comms.h"
							 | 
						||
| 
								 | 
							
								#include "drivers/clock.h"
							 | 
						||
| 
								 | 
							
								#include "early_init.h"
							 | 
						||
| 
								 | 
							
								#include "drivers/i2c_soft.h"
							 | 
						||
| 
								 | 
							
								#include "drivers/angle_sensor.h"
							 | 
						||
| 
								 | 
							
								#include "boards.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// Global variables set externally
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								extern TIM_HandleTypeDef htim_left;
							 | 
						||
| 
								 | 
							
								extern TIM_HandleTypeDef htim_right;
							 | 
						||
| 
								 | 
							
								extern ADC_HandleTypeDef hadc;
							 | 
						||
| 
								 | 
							
								extern volatile adc_buf_t adc_buffer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Matlab defines - from auto-code generation
							 | 
						||
| 
								 | 
							
								//---------------
							 | 
						||
| 
								 | 
							
								extern P    rtP_Left;                   /* Block parameters (auto storage) */
							 | 
						||
| 
								 | 
							
								extern P    rtP_Right;                  /* Block parameters (auto storage) */
							 | 
						||
| 
								 | 
							
								extern ExtY rtY_Left;                   /* External outputs */
							 | 
						||
| 
								 | 
							
								extern ExtY rtY_Right;                  /* External outputs */
							 | 
						||
| 
								 | 
							
								extern ExtU rtU_Left;                   /* External inputs */
							 | 
						||
| 
								 | 
							
								extern ExtU rtU_Right;                  /* External inputs */
							 | 
						||
| 
								 | 
							
								//---------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// TODO: remove both, unneeded. Also func in util.c too
							 | 
						||
| 
								 | 
							
								extern int16_t speedAvg;                // Average measured speed
							 | 
						||
| 
								 | 
							
								extern int16_t speedAvgAbs;             // Average measured speed in absolute
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern volatile int pwml;               // global variable for pwm left. -1000 to 1000
							 | 
						||
| 
								 | 
							
								extern volatile int pwmr;               // global variable for pwm right. -1000 to 1000
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern uint8_t enable_motors;                  // global variable for motor enable
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern int16_t batVoltage;              // global variable for battery voltage
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern int32_t motPosL;
							 | 
						||
| 
								 | 
							
								extern int32_t motPosR;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern board_t board;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// Global variables set here in main.c
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								extern volatile uint32_t buzzerTimer;
							 | 
						||
| 
								 | 
							
								volatile uint32_t torque_cmd_timeout = 0U;
							 | 
						||
| 
								 | 
							
								volatile uint32_t ignition_off_counter = 0U;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uint16_t cnt_press = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int16_t batVoltageCalib;         // global variable for calibrated battery voltage
							 | 
						||
| 
								 | 
							
								int16_t board_temp_deg_c;        // global variable for calibrated temperature in degrees Celsius
							 | 
						||
| 
								 | 
							
								volatile int16_t cmdL;                    // global variable for Left Command
							 | 
						||
| 
								 | 
							
								volatile int16_t cmdR;                    // global variable for Right Command
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uint8_t hw_type;                 // type of the board detected(0 - base, 3 - knee)
							 | 
						||
| 
								 | 
							
								uint8_t ignition = 0;            // global variable for ignition on SBU2 line
							 | 
						||
| 
								 | 
							
								uint8_t charger_connected = 0;   // status of the charger port
							 | 
						||
| 
								 | 
							
								uint8_t pkt_idx = 0;             // For CAN msg counter
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// Local variables
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								static uint32_t tick_prev = 0U;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static uint32_t main_loop_1Hz = 0U;
							 | 
						||
| 
								 | 
							
								static uint32_t main_loop_1Hz_runtime = 0U;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static uint32_t main_loop_10Hz = 0U;
							 | 
						||
| 
								 | 
							
								static uint32_t main_loop_10Hz_runtime = 0U;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static uint32_t main_loop_100Hz = 0U;
							 | 
						||
| 
								 | 
							
								static uint32_t main_loop_100Hz_runtime = 0U;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void __initialize_hardware_early(void) {
							 | 
						||
| 
								 | 
							
								  early_initialization();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int main(void) {
							 | 
						||
| 
								 | 
							
								  HAL_Init();
							 | 
						||
| 
								 | 
							
								  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
							 | 
						||
| 
								 | 
							
								  HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0);
							 | 
						||
| 
								 | 
							
								  HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0);
							 | 
						||
| 
								 | 
							
								  HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0);
							 | 
						||
| 
								 | 
							
								  HAL_NVIC_SetPriority(SVCall_IRQn, 0, 0);
							 | 
						||
| 
								 | 
							
								  HAL_NVIC_SetPriority(DebugMonitor_IRQn, 0, 0);
							 | 
						||
| 
								 | 
							
								  HAL_NVIC_SetPriority(PendSV_IRQn, 0, 0);
							 | 
						||
| 
								 | 
							
								  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  SystemClock_Config();
							 | 
						||
| 
								 | 
							
								  MX_GPIO_Clocks_Init();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  __HAL_RCC_DMA2_CLK_DISABLE();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  board_detect();
							 | 
						||
| 
								 | 
							
								  MX_GPIO_Common_Init();
							 | 
						||
| 
								 | 
							
								  MX_TIM_Init();
							 | 
						||
| 
								 | 
							
								  MX_ADC_Init();
							 | 
						||
| 
								 | 
							
								  BLDC_Init();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  HAL_ADC_Start(&hadc);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (hw_type == HW_TYPE_BASE) {
							 | 
						||
| 
								 | 
							
								    out_enable(POWERSWITCH, true);
							 | 
						||
| 
								 | 
							
								    out_enable(IGNITION, ignition);
							 | 
						||
| 
								 | 
							
								    out_enable(TRANSCEIVER, true);
							 | 
						||
| 
								 | 
							
								    // Loop until button is released, only for base board
							 | 
						||
| 
								 | 
							
								    while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); }
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    out_enable(POWERSWITCH, false);
							 | 
						||
| 
								 | 
							
								    ignition = 1;
							 | 
						||
| 
								 | 
							
								    knee_detected = 1;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  // Reset LEDs on startup
							 | 
						||
| 
								 | 
							
								  out_enable(LED_RED, false);
							 | 
						||
| 
								 | 
							
								  out_enable(LED_GREEN, false);
							 | 
						||
| 
								 | 
							
								  out_enable(LED_BLUE, false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  llcan_set_speed(board.CAN, 5000, false, false);
							 | 
						||
| 
								 | 
							
								  llcan_init(board.CAN);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  SW_I2C_init();
							 | 
						||
| 
								 | 
							
								  IMU_soft_init();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  poweronMelody();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  int32_t board_temp_adcFixdt = adc_buffer.temp << 16;  // Fixed-point filter output initialized with current ADC converted to fixed-point
							 | 
						||
| 
								 | 
							
								  int16_t board_temp_adcFilt  = adc_buffer.temp;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  uint16_t sensor_angle[2] = { 0 };
							 | 
						||
| 
								 | 
							
								  uint16_t hall_angle_offset[2] = { 0 };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  uint16_t unknown_imu_data[6] = { 0 };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (hw_type == HW_TYPE_KNEE) {
							 | 
						||
| 
								 | 
							
								    angle_sensor_read(sensor_angle); // Initial data to set offsets between angle sensor and hall sensor
							 | 
						||
| 
								 | 
							
								    hall_angle_offset[0] = (sensor_angle[0] * ANGLE_TO_DEGREES);
							 | 
						||
| 
								 | 
							
								    hall_angle_offset[1] = (sensor_angle[1] * ANGLE_TO_DEGREES);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while(1) {
							 | 
						||
| 
								 | 
							
								    if ((HAL_GetTick() - tick_prev) >= 1) { // 1kHz loop
							 | 
						||
| 
								 | 
							
								      // runs at 100Hz
							 | 
						||
| 
								 | 
							
								      if ((HAL_GetTick() - (main_loop_100Hz - main_loop_100Hz_runtime)) >= 10) {
							 | 
						||
| 
								 | 
							
								        main_loop_100Hz_runtime = HAL_GetTick();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        calcAvgSpeed();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (ignition == 0) {
							 | 
						||
| 
								 | 
							
								          cmdL = cmdR = 0;
							 | 
						||
| 
								 | 
							
								          enable_motors = 0;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (!enable_motors || (torque_cmd_timeout > 10)) {
							 | 
						||
| 
								 | 
							
								          cmdL = cmdR = 0;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (ignition == 1 && enable_motors == 0 && (!rtY_Left.z_errCode && !rtY_Right.z_errCode) && (ABS(cmdL) < 50 && ABS(cmdR) < 50)) {
							 | 
						||
| 
								 | 
							
								          beepShort(6); // make 2 beeps indicating the motor enable
							 | 
						||
| 
								 | 
							
								          beepShort(4);
							 | 
						||
| 
								 | 
							
								          HAL_Delay(100);
							 | 
						||
| 
								 | 
							
								          cmdL = cmdR = 0;
							 | 
						||
| 
								 | 
							
								          enable_motors = 1; // enable motors
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (hw_type == HW_TYPE_KNEE) {
							 | 
						||
| 
								 | 
							
								          // Safety to stop operation if angle sensor reading failed TODO: adjust sensivity and add lowpass to angle sensor?
							 | 
						||
| 
								 | 
							
								          fault_status.left_angle = (ABS((hall_angle_offset[0] + ((motPosL / 15 / GEARBOX_RATIO_LEFT) % 360)) - (sensor_angle[0] * ANGLE_TO_DEGREES)) > 5);
							 | 
						||
| 
								 | 
							
								          fault_status.right_angle = (ABS((hall_angle_offset[1] + ((motPosR / 15 / GEARBOX_RATIO_RIGHT) % 360)) - (sensor_angle[1] * ANGLE_TO_DEGREES)) > 5);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          if (fault_status.left_angle || fault_status.right_angle) {
							 | 
						||
| 
								 | 
							
								            cmdL = cmdR = 0;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          // Safety to stop movement when reaching dead angles, around 20 and 340 degrees
							 | 
						||
| 
								 | 
							
								          if (((sensor_angle[0] < 900) && (cmdL < 0)) || ((sensor_angle[0] > 15500) && (cmdL > 0))) {
							 | 
						||
| 
								 | 
							
								            cmdL = 0;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          if (((sensor_angle[1] < 900) && (cmdR < 0)) || ((sensor_angle[1] > 15500) && (cmdR > 0))) {
							 | 
						||
| 
								 | 
							
								            cmdR = 0;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (ABS(cmdL) < 10) {
							 | 
						||
| 
								 | 
							
								          rtP_Left.n_cruiseMotTgt   = 0;
							 | 
						||
| 
								 | 
							
								          rtP_Left.b_cruiseCtrlEna  = 1;
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          rtP_Left.b_cruiseCtrlEna  = 0;
							 | 
						||
| 
								 | 
							
								          if (hw_type == HW_TYPE_KNEE) {
							 | 
						||
| 
								 | 
							
								            pwml = -CLAMP((int)cmdL, -TRQ_LIMIT_LEFT, TRQ_LIMIT_LEFT);
							 | 
						||
| 
								 | 
							
								          } else {
							 | 
						||
| 
								 | 
							
								            pwml = CLAMP((int)cmdL, -TORQUE_BASE_MAX, TORQUE_BASE_MAX);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (ABS(cmdR) < 10) {
							 | 
						||
| 
								 | 
							
								          rtP_Right.n_cruiseMotTgt  = 0;
							 | 
						||
| 
								 | 
							
								          rtP_Right.b_cruiseCtrlEna = 1;
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          rtP_Right.b_cruiseCtrlEna = 0;
							 | 
						||
| 
								 | 
							
								          if (hw_type == HW_TYPE_KNEE) {
							 | 
						||
| 
								 | 
							
								            pwmr = -CLAMP((int)cmdR, -TRQ_LIMIT_RIGHT, TRQ_LIMIT_RIGHT);
							 | 
						||
| 
								 | 
							
								          } else {
							 | 
						||
| 
								 | 
							
								            pwmr = -CLAMP((int)cmdR, -TORQUE_BASE_MAX, TORQUE_BASE_MAX);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (ignition_off_counter <= IGNITION_OFF_DELAY) {
							 | 
						||
| 
								 | 
							
								          // MOTORS_DATA: speed_L(2), speed_R(2), counter(1), checksum(1)
							 | 
						||
| 
								 | 
							
								          uint8_t dat[8];
							 | 
						||
| 
								 | 
							
								          uint16_t speedL = rtY_Left.n_mot;
							 | 
						||
| 
								 | 
							
								          uint16_t speedR = -(rtY_Right.n_mot); // Invert speed sign for the right wheel
							 | 
						||
| 
								 | 
							
								          dat[0] = (speedL >> 8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[1] = speedL & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[2] = (speedR >> 8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[3] = speedR & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[4] = 0;
							 | 
						||
| 
								 | 
							
								          dat[5] = 0;
							 | 
						||
| 
								 | 
							
								          dat[6] = pkt_idx;
							 | 
						||
| 
								 | 
							
								          dat[7] = crc_checksum(dat, 7, crc_poly);
							 | 
						||
| 
								 | 
							
								          can_send_msg((0x201U + board.can_addr_offset), ((dat[7] << 24U) | (dat[6] << 16U) | (dat[5]<< 8U) | dat[4]), ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 8U);
							 | 
						||
| 
								 | 
							
								          ++pkt_idx;
							 | 
						||
| 
								 | 
							
								          pkt_idx &= 0xFU;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          //MOTORS_CURRENT: left_pha_ab(2), left_pha_bc(2), right_pha_ab(2), right_pha_bc(2)
							 | 
						||
| 
								 | 
							
								          dat[0] = (rtU_Left.i_phaAB >> 8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[1] = rtU_Left.i_phaAB & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[2] = (rtU_Left.i_phaBC >> 8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[3] = rtU_Left.i_phaBC & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[4] = (rtU_Right.i_phaAB >> 8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[5] = rtU_Right.i_phaAB & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[6] = (rtU_Right.i_phaBC >> 8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[7] = rtU_Right.i_phaBC & 0xFFU;
							 | 
						||
| 
								 | 
							
								          can_send_msg((0x204U + board.can_addr_offset), ((dat[7] << 24U) | (dat[6] << 16U) | (dat[5] << 8U) | dat[4]), ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 8U);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          uint16_t left_hall_angle;
							 | 
						||
| 
								 | 
							
								          uint16_t right_hall_angle;
							 | 
						||
| 
								 | 
							
								          if (hw_type == HW_TYPE_KNEE) {
							 | 
						||
| 
								 | 
							
								            angle_sensor_read(sensor_angle);
							 | 
						||
| 
								 | 
							
								            left_hall_angle = hall_angle_offset[0] + ((motPosL / 15 / GEARBOX_RATIO_LEFT) % 360);
							 | 
						||
| 
								 | 
							
								            right_hall_angle = hall_angle_offset[1] + ((motPosR / 15 / GEARBOX_RATIO_RIGHT) % 360);
							 | 
						||
| 
								 | 
							
								          } else {
							 | 
						||
| 
								 | 
							
								            left_hall_angle = motPosL / 15;
							 | 
						||
| 
								 | 
							
								            right_hall_angle = -motPosR / 15;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          //MOTORS_ANGLE: left angle sensor(2), right angle sensor(2), left hall angle(2), right hall angle(2)
							 | 
						||
| 
								 | 
							
								          dat[0] = (sensor_angle[0]>>8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[1] = sensor_angle[0] & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[2] = (sensor_angle[1]>>8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[3] = sensor_angle[1] & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[4] = (left_hall_angle>>8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[5] = left_hall_angle & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[6] = (right_hall_angle>>8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[7] = right_hall_angle & 0xFFU;
							 | 
						||
| 
								 | 
							
								          can_send_msg((0x205U + board.can_addr_offset), ((dat[7] << 24U) | (dat[6] << 16U) | (dat[5] << 8U) | dat[4]), ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 8U);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          IMU_soft_sensor_read(unknown_imu_data);
							 | 
						||
| 
								 | 
							
								          //BOARD_IMU_RAW1: FIXME: add comment after discovering data, looks like magnetometer
							 | 
						||
| 
								 | 
							
								          dat[0] = (unknown_imu_data[0]>>8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[1] = unknown_imu_data[0] & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[2] = (unknown_imu_data[1]>>8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[3] = unknown_imu_data[1] & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[4] = (unknown_imu_data[2]>>8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[5] = unknown_imu_data[2] & 0xFFU;
							 | 
						||
| 
								 | 
							
								          can_send_msg((0x206U + board.can_addr_offset), ((dat[5] << 8U) | dat[4]), ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 6U);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          //BOARD_IMU_RAW2: FIXME: add comment after discovering data, looks like acceleration?
							 | 
						||
| 
								 | 
							
								          dat[0] = (unknown_imu_data[3]>>8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[1] = unknown_imu_data[3] & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[2] = (unknown_imu_data[4]>>8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[3] = unknown_imu_data[4] & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[4] = (unknown_imu_data[5]>>8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								          dat[5] = unknown_imu_data[5] & 0xFFU;
							 | 
						||
| 
								 | 
							
								          can_send_msg((0x207U + board.can_addr_offset), ((dat[5] << 8U) | dat[4]), ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 6U);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        torque_cmd_timeout = (torque_cmd_timeout < MAX_uint32_T) ? (torque_cmd_timeout+1) : 0;
							 | 
						||
| 
								 | 
							
								        main_loop_100Hz_runtime = HAL_GetTick() - main_loop_100Hz_runtime;
							 | 
						||
| 
								 | 
							
								        main_loop_100Hz = HAL_GetTick();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // runs at 10Hz
							 | 
						||
| 
								 | 
							
								       if ((HAL_GetTick() - (main_loop_10Hz - main_loop_10Hz_runtime)) >= 100) {
							 | 
						||
| 
								 | 
							
								        main_loop_10Hz_runtime = HAL_GetTick();
							 | 
						||
| 
								 | 
							
								        if (ignition_off_counter <= IGNITION_OFF_DELAY) {
							 | 
						||
| 
								 | 
							
								          // VAR_VALUES: fault_status(0:4), enable_motors(0:1), ignition(0:1), left motor error(1), right motor error(1)
							 | 
						||
| 
								 | 
							
								          uint8_t dat[2];
							 | 
						||
| 
								 | 
							
								          dat[0] = ((fault_status.right_angle << 5U) | (fault_status.right_i2c << 4U) | (fault_status.left_angle << 3U) | (fault_status.left_i2c << 2U) | (enable_motors << 1U) | ignition);
							 | 
						||
| 
								 | 
							
								          dat[1] = rtY_Left.z_errCode;
							 | 
						||
| 
								 | 
							
								          dat[2] = rtY_Right.z_errCode;
							 | 
						||
| 
								 | 
							
								          can_send_msg((0x202U + board.can_addr_offset), 0x0U, ((dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 3U);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        out_enable(LED_GREEN, ignition);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        main_loop_10Hz_runtime = HAL_GetTick() - main_loop_10Hz_runtime;
							 | 
						||
| 
								 | 
							
								        main_loop_10Hz = HAL_GetTick();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // runs at 1Hz
							 | 
						||
| 
								 | 
							
								      if ((HAL_GetTick() - (main_loop_1Hz - main_loop_1Hz_runtime)) >= 1000) {
							 | 
						||
| 
								 | 
							
								        main_loop_1Hz_runtime = HAL_GetTick();
							 | 
						||
| 
								 | 
							
								         // ####### CALC BOARD TEMPERATURE #######
							 | 
						||
| 
								 | 
							
								        filtLowPass32(adc_buffer.temp, TEMP_FILT_COEF, &board_temp_adcFixdt);
							 | 
						||
| 
								 | 
							
								        board_temp_adcFilt  = (int16_t)(board_temp_adcFixdt >> 16);  // convert fixed-point to integer
							 | 
						||
| 
								 | 
							
								        board_temp_deg_c    = (TEMP_CAL_HIGH_DEG_C - TEMP_CAL_LOW_DEG_C) * (board_temp_adcFilt - TEMP_CAL_LOW_ADC) / (TEMP_CAL_HIGH_ADC - TEMP_CAL_LOW_ADC) + TEMP_CAL_LOW_DEG_C;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // ####### CALC CALIBRATED BATTERY VOLTAGE #######
							 | 
						||
| 
								 | 
							
								        batVoltageCalib = batVoltage * BAT_CALIB_REAL_VOLTAGE / BAT_CALIB_ADC;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        charger_connected = !HAL_GPIO_ReadPin(CHARGER_PORT, CHARGER_PIN);
							 | 
						||
| 
								 | 
							
								        uint8_t battery_percent = 100 - (((420 * BAT_CELLS) - batVoltageCalib) / BAT_CELLS / VOLTS_PER_PERCENT / 100); // Battery % left
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // BODY_DATA: MCU temp(2), battery voltage(2), battery_percent(0:7), charger_connected(0:1)
							 | 
						||
| 
								 | 
							
								        uint8_t dat[4];
							 | 
						||
| 
								 | 
							
								        dat[0] = board_temp_deg_c & 0xFFU;
							 | 
						||
| 
								 | 
							
								        dat[1] = (batVoltageCalib >> 8U) & 0xFFU;
							 | 
						||
| 
								 | 
							
								        dat[2] = batVoltageCalib & 0xFFU;
							 | 
						||
| 
								 | 
							
								        dat[3] = (((battery_percent & 0x7FU) << 1U) | charger_connected);
							 | 
						||
| 
								 | 
							
								        can_send_msg((0x203U + board.can_addr_offset), 0x0U, ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 4U);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        out_enable(LED_BLUE, false); // Reset LED after CAN RX
							 | 
						||
| 
								 | 
							
								        out_enable(LED_GREEN, true); // Always use LED to show that body is on
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if ((hw_type == HW_TYPE_BASE) && ignition) {
							 | 
						||
| 
								 | 
							
								          ignition_off_counter = 0;
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          ignition_off_counter = (ignition_off_counter < MAX_uint32_T) ? (ignition_off_counter+1) : 0;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if ((TEMP_POWEROFF_ENABLE && board_temp_deg_c >= TEMP_POWEROFF && speedAvgAbs < 20) || (batVoltage < BAT_DEAD && speedAvgAbs < 20)) {  // poweroff before mainboard burns OR low bat 3
							 | 
						||
| 
								 | 
							
								          poweroff();
							 | 
						||
| 
								 | 
							
								        } else if (rtY_Left.z_errCode || rtY_Right.z_errCode) { // 1 beep (low pitch): Motor error, disable motors
							 | 
						||
| 
								 | 
							
								          enable_motors = 0;
							 | 
						||
| 
								 | 
							
								          beepCount(1, 24, 1);
							 | 
						||
| 
								 | 
							
								        } else if (fault_status.left_angle || fault_status.left_i2c || fault_status.right_angle || fault_status.right_i2c) { // 2 beeps (low pitch): Motor error, disable motors
							 | 
						||
| 
								 | 
							
								          beepCount(2, 24, 1);
							 | 
						||
| 
								 | 
							
								        } else if (TEMP_WARNING_ENABLE && board_temp_deg_c >= TEMP_WARNING) { // 5 beeps (low pitch): Mainboard temperature warning
							 | 
						||
| 
								 | 
							
								          beepCount(5, 24, 1);
							 | 
						||
| 
								 | 
							
								        } else if (batVoltage < BAT_LVL1) { // 1 beep fast (medium pitch): Low bat 1
							 | 
						||
| 
								 | 
							
								          beepCount(0, 10, 6);
							 | 
						||
| 
								 | 
							
								          out_enable(LED_RED, true);
							 | 
						||
| 
								 | 
							
								        } else if (batVoltage < BAT_LVL2) { // 1 beep slow (medium pitch): Low bat 2
							 | 
						||
| 
								 | 
							
								          beepCount(0, 10, 30);
							 | 
						||
| 
								 | 
							
								        } else {  // do not beep
							 | 
						||
| 
								 | 
							
								          beepCount(0, 0, 0);
							 | 
						||
| 
								 | 
							
								          out_enable(LED_RED, false);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        main_loop_1Hz_runtime = HAL_GetTick() - main_loop_1Hz_runtime;
							 | 
						||
| 
								 | 
							
								        main_loop_1Hz = HAL_GetTick();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (hw_type == HW_TYPE_BASE) {
							 | 
						||
| 
								 | 
							
								        if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) {
							 | 
						||
| 
								 | 
							
								          cnt_press += 1;
							 | 
						||
| 
								 | 
							
								          if (cnt_press == (2 * 1008)) {
							 | 
						||
| 
								 | 
							
								            poweroff();
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        } else if (cnt_press >= 10) {
							 | 
						||
| 
								 | 
							
								          ignition = !ignition;
							 | 
						||
| 
								 | 
							
								          out_enable(IGNITION, ignition);
							 | 
						||
| 
								 | 
							
								          beepShort(5);
							 | 
						||
| 
								 | 
							
								          cnt_press = 0;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      process_can();
							 | 
						||
| 
								 | 
							
								      tick_prev = HAL_GetTick();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |