Subversion Repositories EngineBay2

Rev

Rev 46 | Rev 48 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /* USER CODE BEGIN Header */
  2. /**
  3.  ******************************************************************************
  4.  * @file           : main.c
  5.  * @brief          : Main program body
  6.  ******************************************************************************
  7.  * @attention
  8.  *
  9.  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  10.  * All rights reserved.</center></h2>
  11.  *
  12.  * This software component is licensed by ST under BSD 3-Clause license,
  13.  * the "License"; You may not use this file except in compliance with the
  14.  * License. You may obtain a copy of the License at:
  15.  *                        opensource.org/licenses/BSD-3-Clause
  16.  *
  17.  ******************************************************************************
  18.  */
  19. /* USER CODE END Header */
  20. /* Includes ------------------------------------------------------------------*/
  21. #include "main.h"
  22.  
  23. /* Private includes ----------------------------------------------------------*/
  24. /* USER CODE BEGIN Includes */
  25. #include "libSerial/serial.h"
  26. #include "libPLX/plx.h"
  27. #include "misc.h"
  28.  
  29. /* USER CODE END Includes */
  30.  
  31. /* Private typedef -----------------------------------------------------------*/
  32. /* USER CODE BEGIN PTD */
  33.  
  34. /* USER CODE END PTD */
  35.  
  36. /* Private define ------------------------------------------------------------*/
  37. /* USER CODE BEGIN PD */
  38. /* USER CODE END PD */
  39.  
  40. /* Private macro -------------------------------------------------------------*/
  41. /* USER CODE BEGIN PM */
  42. #define ADC_CHANNELS 7
  43.  
  44. #define ADC_MAP_CHAN 2
  45.  
  46. #define ADC_PRESSURE_CHAN 3
  47.  
  48. #define ADC_REF_CHAN 5
  49.  
  50. #define ADC_TEMP_CHAN 6
  51.  
  52. // with a dwell angle of 45 degrees , 4 cylinders and a maximum RPM of 5000
  53. // freq = 5000/60 * 2 = 166Hz.
  54. // the TIM2 counter counts in 10uS increments,
  55. // Need to accumulate low level for a 400th of a second before accepting it as a pulse
  56. #define ACCUM_MAX (RPM_COUNT_RATE / 400)
  57.  
  58. #define GLITCH_MAX (RPM_COUNT_RATE / 2000)
  59.  
  60. #define RPM_AVERAGE 4
  61.  
  62. // wait for about 1 second to decide whether or not starter is on
  63.  
  64. #define STARTER_LIMIT 10
  65.  
  66. /* USER CODE END PM */
  67.  
  68. /* Private variables ---------------------------------------------------------*/
  69. ADC_HandleTypeDef hadc1;
  70. DMA_HandleTypeDef hdma_adc1;
  71.  
  72. CAN_HandleTypeDef hcan;
  73.  
  74. SPI_HandleTypeDef hspi1;
  75.  
  76. TIM_HandleTypeDef htim2;
  77. TIM_HandleTypeDef htim3;
  78. TIM_HandleTypeDef htim4;
  79.  
  80. UART_HandleTypeDef huart1;
  81.  
  82. /* USER CODE BEGIN PV */
  83.  
  84. volatile char TimerFlag = 0;
  85.  
  86. volatile char NoSerialInCTR = 0; // Missing characters coming in on USART1
  87. volatile char NoSerialIn = 0;
  88.  
  89. // scale for filtered samples
  90. #define Scale 1024.0
  91.  
  92. // storage for ADC
  93. uint16_t ADC_Samples[ADC_CHANNELS] = {[0 ... ADC_CHANNELS - 1] = 0};
  94.  
  95. uint32_t FILT_Samples[ADC_CHANNELS] = {[0 ... ADC_CHANNELS - 1] = 0}; // filtered ADC samples * Scale
  96.  
  97. #define NOM_VREF 3.3
  98. // initial ADC vref
  99. float adc_vref = NOM_VREF;
  100.  
  101. // internal bandgap voltage reference
  102. const float STM32REF = 1.2; // 1.2V typical
  103.  
  104. // scale factor initially assuming
  105. float ADC_Scale = 1 / (Scale * 4096) * NOM_VREF;
  106.  
  107. // Rev counter processing from original RevCounter Project
  108. uint16_t RPM_Diff = 0;
  109. uint16_t RPM_Count_Latch = 0;
  110. // accumulators
  111. uint16_t RPM_Pulsecount = 0;
  112. unsigned int RPM_FilteredWidth = 0;
  113.  
  114. // last time we detected end of dwell i.e. ignition pulse
  115. uint16_t last_dwell_end = 0;
  116. uint16_t RPM_Period[RPM_AVERAGE];
  117. unsigned int RPM_Period_Ptr = 0;
  118.  
  119. unsigned int Coded_RPM = 0;
  120. unsigned int Coded_CHT = 0;
  121.  
  122. uint32_t PowerTempTimer;
  123.  
  124. uint16_t Starter_Debounce = 0;
  125.  
  126. /* USER CODE END PV */
  127.  
  128. /* Private function prototypes -----------------------------------------------*/
  129. void SystemClock_Config(void);
  130. static void MX_GPIO_Init(void);
  131. static void MX_DMA_Init(void);
  132. static void MX_ADC1_Init(void);
  133. static void MX_CAN_Init(void);
  134. static void MX_SPI1_Init(void);
  135. static void MX_TIM2_Init(void);
  136. static void MX_TIM3_Init(void);
  137. static void MX_TIM4_Init(void);
  138. static void MX_USART1_UART_Init(void);
  139. /* USER CODE BEGIN PFP */
  140.  
  141. /* USER CODE END PFP */
  142.  
  143. /* Private user code ---------------------------------------------------------*/
  144. /* USER CODE BEGIN 0 */
  145.  
  146. void plx_sendword(int x)
  147. {
  148.   PutCharSerial(&uc1, ((x) >> 6) & 0x3F);
  149.   PutCharSerial(&uc1, (x)&0x3F);
  150. }
  151.  
  152. void filter_ADC_samples()
  153. {
  154.   int i;
  155.   for (i = 0; i < ADC_CHANNELS; i++)
  156.   {
  157.     FILT_Samples[i] += (ADC_Samples[i] * Scale - FILT_Samples[i]) / 2;
  158.   }
  159. }
  160.  
  161. /****!
  162.  * @brief this reads the reference voltage within the STM32L151
  163.  * Powers up reference voltage and temperature sensor, waits 3mS  and takes reading
  164.  * Requires that the ADC be powered up
  165.  */
  166.  
  167. void CalibrateADC(void)
  168. {
  169.   float adc_val = FILT_Samples[ADC_REF_CHAN]; // as set up in device config
  170.  
  171.   float adc_vref = STM32REF * (4096.0 * Scale) / adc_val; // the estimate for checking
  172.  
  173.   ADC_Scale = 1 / (Scale * 4096) * adc_vref;
  174. }
  175.  
  176. void ProcessRPM(int instance)
  177. {
  178.   // compute the timer values
  179.   // snapshot timers
  180.   unsigned short RPM_Pulsewidth;
  181.   // current RPM pulse next slot index
  182.   unsigned short RPM_Count_Val;
  183.  
  184.   // accumulator for pulse widths
  185.   static unsigned short RPM_Accumulator = ACCUM_MAX;
  186.   // Next state of pulse high/low
  187.   static unsigned char RPM_State = 1;
  188.   // Current state of pulse high/low
  189.   static unsigned char RPM_State_Curr = 1;
  190.  
  191.   __disable_irq(); // copy the counter value
  192.   RPM_Count_Val = RPM_Count;
  193.   __enable_irq();
  194.   // do calculations
  195.  
  196.   // if there is only one entry, cannot get difference
  197.   if (RPM_Count_Latch != RPM_Count_Val)
  198.   {
  199.     while (1)
  200.     {
  201.       unsigned int base_time;
  202.       unsigned int new_time;
  203.       // if we are at N-1, stop.
  204.       unsigned int next_count = (RPM_Count_Latch + 1) % RPM_SAMPLES;
  205.       if (next_count == RPM_Count_Val)
  206.       {
  207.         break; // completed loop
  208.       }
  209.       char pulse_level = (RPM_Time[RPM_Count_Latch] & RPM_FLAG) ? 1 : 0;
  210.       base_time = RPM_Time[RPM_Count_Latch] & ~RPM_FLAG;
  211.       new_time = RPM_Time[next_count] & ~RPM_FLAG;
  212.       RPM_Count_Latch = next_count;
  213.  
  214.       RPM_Pulsewidth = new_time - base_time;
  215.  
  216.       if (pulse_level == 0 && (RPM_Pulsewidth > ACCUM_MAX))
  217.         RPM_State = 1;
  218.       if (pulse_level == 1)
  219.         RPM_State = 0;  
  220. #if 0
  221.       RPM_State_Curr = RPM_State;
  222.       // Count up/down
  223.       if (pulse_level == 0)
  224.       {
  225.         if (RPM_Pulsewidth > RPM_Accumulator) // going to cross zero
  226.         {
  227.           RPM_State = 0;
  228.           RPM_Accumulator = 0;
  229.         }
  230.         else
  231.         {
  232.           RPM_Accumulator -=  RPM_Pulsewidth;
  233.         }
  234.       }
  235.       else
  236.       {
  237.         if (RPM_Accumulator + RPM_Pulsewidth > ACCUM_MAX)
  238.         {
  239.           RPM_State = 1;
  240.           RPM_Accumulator = ACCUM_MAX;
  241.         }
  242.         else
  243.         {
  244.           RPM_Accumulator += RPM_Pulsewidth;
  245.         }
  246.       }
  247. #endif
  248.       // low pulse has reached at least minimum width, count it.
  249.       if ((RPM_State == 1) && (RPM_State_Curr == 0))
  250.       {
  251.         RPM_Diff = new_time - last_dwell_end;
  252.  
  253.         RPM_Period[RPM_Period_Ptr] = RPM_Diff;
  254.         RPM_Period_Ptr = (RPM_Period_Ptr + 1) % RPM_AVERAGE;
  255.         if (RPM_Pulsecount < RPM_AVERAGE)
  256.           RPM_Pulsecount++; // count one pulse
  257.         last_dwell_end = new_time;
  258.       }
  259.       RPM_State_Curr = RPM_State;
  260.     }
  261.   }
  262.  
  263.   if (RPM_Pulsecount == RPM_AVERAGE)
  264.   {
  265.     // now have time for N pulses in clocks
  266.     // need to scale by 19.55: one unit is 19.55 RPM
  267.     // 1Hz is 30 RPM
  268.     int i;
  269.     RPM_FilteredWidth = 0;
  270.     for (i = 0; i < RPM_AVERAGE; i++)
  271.       RPM_FilteredWidth += RPM_Period[i];
  272.  
  273.     Coded_RPM = (Scale * 30.0 * RPM_AVERAGE * RPM_COUNT_RATE) / (19.55 * RPM_FilteredWidth);
  274.  
  275. #if !defined MY_DEBUG
  276.     // reset here unless we want to debug
  277.     RPM_Pulsecount = 0;
  278. #endif
  279.   }
  280.  
  281.   // send the current RPM *calculation
  282.   plx_sendword(PLX_RPM);
  283.   PutCharSerial(&uc1, instance);
  284.   plx_sendword(Coded_RPM / Scale);
  285. }
  286.  
  287. // this uses a MAX6675 which is a simple 16 bit read
  288. // SPI is configured for 8 bits so I can use an OLED display if I need it
  289. // must wait > 0.22 seconds between conversion attempts as this is the measurement time
  290. //
  291.  
  292. FunctionalState CHT_Enable = ENABLE;
  293.  
  294. #define CORR 3
  295.  
  296. uint16_t Temp_Observations[NUM_SPI_TEMP_SENS] = {[0 ... NUM_SPI_TEMP_SENS - 1] = 0};
  297.  
  298. /// \param item The array index to send
  299. /// \param instance The instance to send over the bus
  300. /// \param type the code to use for this observation
  301. void ProcessTemp(char item, int instance, enum PLX_Observations type)
  302. {
  303.   if (item > NUM_SPI_TEMP_SENS)
  304.     return;
  305.   plx_sendword(type);
  306.   PutCharSerial(&uc1, instance);
  307.   plx_sendword(Temp_Observations[(int)item]);
  308. }
  309.  
  310. /// \brief Reset the temperature chip select system
  311. void resetTempCS(void)
  312. {
  313.   HAL_GPIO_WritePin(SPI_CS_D_GPIO_Port, SPI_CS_D_Pin, GPIO_PIN_SET);
  314.   HAL_GPIO_WritePin(SPI_CS_Clk_GPIO_Port, SPI_CS_Clk_Pin,
  315.                     GPIO_PIN_SET);
  316.  
  317.   for (int i = 0; i < 8; i++)
  318.   {
  319.     HAL_GPIO_WritePin(SPI_CS_Clk_GPIO_Port, SPI_CS_Clk_Pin,
  320.                       GPIO_PIN_RESET);
  321.     HAL_GPIO_WritePin(SPI_CS_Clk_GPIO_Port, SPI_CS_Clk_Pin,
  322.                       GPIO_PIN_SET);
  323.   }
  324.  
  325.   // prepare for selecting next pin
  326.   HAL_GPIO_WritePin(SPI_CS_D_GPIO_Port, SPI_CS_D_Pin, GPIO_PIN_RESET);
  327. }
  328.  
  329. void nextTempCS(void)
  330. {
  331.   HAL_GPIO_WritePin(SPI_CS_Clk_GPIO_Port, SPI_CS_Clk_Pin,
  332.                     GPIO_PIN_RESET);
  333.   HAL_GPIO_WritePin(SPI_CS_Clk_GPIO_Port, SPI_CS_Clk_Pin,
  334.                     GPIO_PIN_SET);
  335.   HAL_GPIO_WritePin(SPI_CS_D_GPIO_Port, SPI_CS_D_Pin, GPIO_PIN_SET);
  336. }
  337.  
  338. void EnableTempSensors(FunctionalState state)
  339.  
  340. {
  341.   GPIO_InitTypeDef GPIO_InitStruct;
  342.  
  343.   CHT_Enable = state;
  344.  
  345.   /* enable SPI in live mode : assume it and its GPIOs are already initialised in SPI mode */
  346.   if (state == ENABLE)
  347.   {
  348.     HAL_GPIO_WritePin(ENA_AUX_5V_GPIO_Port, ENA_AUX_5V_Pin, GPIO_PIN_SET);
  349.  
  350.     resetTempCS();
  351.  
  352.     /* put the SPI pins back into SPI AF mode */
  353.     GPIO_InitStruct.Pin = SPI1_MOSI_Pin | SPI1_MISO_Pin | SPI1_SCK_Pin;
  354.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  355.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  356.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  357.     HAL_GPIO_Init(SPI1_SCK_GPIO_Port, &GPIO_InitStruct);
  358.   }
  359.   else
  360.   {
  361.     /*  Power down the SPI interface taking signals all low */
  362.     HAL_GPIO_WritePin(ENA_AUX_5V_GPIO_Port, ENA_AUX_5V_Pin, GPIO_PIN_RESET);
  363.  
  364.     HAL_GPIO_WritePin(SPI1_SCK_GPIO_Port,
  365.                       SPI1_MOSI_Pin | SPI1_MISO_Pin | SPI1_SCK_Pin,
  366.                       GPIO_PIN_RESET);
  367.  
  368.     /* put the SPI pins back into GPIO mode */
  369.     GPIO_InitStruct.Pin = SPI1_MOSI_Pin | SPI1_MISO_Pin | SPI1_SCK_Pin;
  370.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  371.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  372.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  373.     HAL_GPIO_Init(SPI1_SCK_GPIO_Port, &GPIO_InitStruct);
  374.   }
  375. }
  376.  
  377. // 1023 is 20.00 volts.
  378. void ProcessBatteryVoltage(int instance)
  379. {
  380.   float reading = FILT_Samples[instance] * ADC_Scale;
  381.   reading = reading * 7.8125; // real voltage
  382.   reading = reading * 51.15;  // PLC scaling =  1023/20
  383.  
  384.   plx_sendword(PLX_Volts);
  385.   PutCharSerial(&uc1, instance);
  386.   plx_sendword((uint16_t)reading);
  387. }
  388.  
  389. void ProcessCPUTemperature(int instance)
  390. {
  391.   // this is defined in the STM32F103 reference manual . #
  392.   // V25 = 1.43 volts
  393.   // Avg_slope = 4.3mV /degree C
  394.   // temperature = {(V25 - VSENSE) / Avg_Slope} + 25
  395.  
  396.   /* get the ADC reading corresponding to ADC channel 16 after turning on the ADC */
  397.  
  398.   float temp_val = FILT_Samples[ADC_TEMP_CHAN] * ADC_Scale;
  399.   /* renormalise temperature value to account for different ADC Vref  : normalise to that which we would get for a 3000mV reference */
  400.   temp_val = (1.43 - temp_val) / 4.3e-3 + 25;
  401.  
  402.   int32_t result = temp_val;
  403.  
  404.   //  int32_t result = 800 * ((int32_t) temp_val - TS_CAL30);
  405.   //  result = result / (TS_CAL110 - TS_CAL30) + 300;
  406.  
  407.   plx_sendword(PLX_FluidTemp);
  408.   PutCharSerial(&uc1, instance);
  409.   plx_sendword(result);
  410. }
  411.  
  412. // the MAP sensor is giving us a reading of
  413. // 4.6 volts for 1019mB or 2.27 volts at the ADC input (resistive divider by 2.016)
  414. // I believe the sensor reads  4.5V at 1000kPa and 0.5V at  0kPa
  415. // Calibration is a bit off
  416. // Real   Displayed
  417. // 989    968
  418. // 994.1    986
  419. // 992.3  984
  420.  
  421. void ProcessMAP(int instance)
  422. {
  423.   // Using ADC_Samples[3] as the MAP input
  424.   float reading = FILT_Samples[ADC_MAP_CHAN] * ADC_Scale;
  425.   reading = reading * 2.016; // real voltage
  426.   // values computed from slope / intercept of map.ods
  427.   // reading = (reading) * 56.23 + 743.2; // do not assume 0.5 volt offset : reading from 0 to 4.5 instead of 0.5 to 4.5
  428.   // using a pressure gauge.
  429.   reading = (reading)*150 + 326;
  430.  
  431.   plx_sendword(PLX_MAP);
  432.   PutCharSerial(&uc1, instance);
  433.   plx_sendword((uint16_t)reading);
  434. }
  435.  
  436. // the Oil pressi sensor is giving us a reading of
  437. // 4.5 volts for 100 PSI or  2.25 volts at the ADC input (resistive divider by 2.016)
  438. // I believe the sensor reads  4.5V at 100PSI and 0.5V at  0PSI
  439. // an observation of 1024 is 200PSI, so observation of 512 is 100 PSI.
  440.  
  441. void ProcessOilPress(int instance)
  442. {
  443.   // Using ADC_Samples[2] as the MAP input
  444.   float reading = FILT_Samples[ADC_PRESSURE_CHAN] * ADC_Scale;
  445.   reading = reading * 2.00;            // real voltage
  446.   reading = (reading - 0.5) * 512 / 4; // this is 1023 * 100/200
  447.  
  448.   plx_sendword(PLX_FluidPressure);
  449.   PutCharSerial(&uc1, instance);
  450.   plx_sendword((uint16_t)reading);
  451. }
  452.  
  453. void ProcessTiming(int instance)
  454. {
  455.   plx_sendword(PLX_Timing);
  456.   PutCharSerial(&uc1, instance);
  457.   plx_sendword(64 - 15); // make it negative
  458. }
  459.  
  460. /* USER CODE END 0 */
  461.  
  462. /**
  463.  * @brief  The application entry point.
  464.  * @retval int
  465.  */
  466. int main(void)
  467. {
  468.   /* USER CODE BEGIN 1 */
  469.  
  470.   /* USER CODE END 1 */
  471.  
  472.   /* MCU Configuration--------------------------------------------------------*/
  473.  
  474.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  475.   HAL_Init();
  476.  
  477.   /* USER CODE BEGIN Init */
  478.  
  479.   /* USER CODE END Init */
  480.  
  481.   /* Configure the system clock */
  482.   SystemClock_Config();
  483.  
  484.   /* USER CODE BEGIN SysInit */
  485.  
  486.   /* USER CODE END SysInit */
  487.  
  488.   /* Initialize all configured peripherals */
  489.   MX_GPIO_Init();
  490.   MX_DMA_Init();
  491.   MX_ADC1_Init();
  492.   MX_CAN_Init();
  493.   MX_SPI1_Init();
  494.   MX_TIM2_Init();
  495.   MX_TIM3_Init();
  496.   MX_TIM4_Init();
  497.   MX_USART1_UART_Init();
  498.   /* USER CODE BEGIN 2 */
  499.   HAL_MspInit();
  500.  
  501.   // Not using HAL USART code
  502.   __HAL_RCC_USART1_CLK_ENABLE(); // PLX comms port
  503.   /* setup the USART control blocks */
  504.   init_usart_ctl(&uc1, &huart1);
  505.  
  506.   EnableSerialRxInterrupt(&uc1);
  507.  
  508.   HAL_SPI_MspInit(&hspi1);
  509.  
  510.   HAL_ADC_MspInit(&hadc1);
  511.  
  512.   HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_Samples, ADC_CHANNELS);
  513.  
  514.   HAL_ADC_Start_IT(&hadc1);
  515.  
  516.   HAL_TIM_Base_MspInit(&htim4);
  517.   HAL_TIM_Base_Start_IT(&htim4);
  518.  
  519.   // initialise all the STMCubeMX stuff
  520.   HAL_TIM_Base_MspInit(&htim2);
  521.   // Start the counter
  522.   HAL_TIM_Base_Start(&htim2);
  523.   // Start the input capture and the rising edge interrupt
  524.   HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
  525.   // Start the input capture and the falling edge interrupt
  526.   HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
  527.  
  528.   HAL_TIM_Base_MspInit(&htim3);
  529.   __HAL_TIM_ENABLE_IT(&htim3, TIM_IT_UPDATE);
  530.   uint32_t Ticks = HAL_GetTick() + 100;
  531.   int CalCounter = 0;
  532.  
  533.   PowerTempTimer = HAL_GetTick() + 1000; /* wait 10 seconds before powering up the CHT sensor */
  534.  
  535.   ResetRxBuffer(&uc1);
  536.   /* USER CODE END 2 */
  537.  
  538.   /* Infinite loop */
  539.   /* USER CODE BEGIN WHILE */
  540.   while (1)
  541.   {
  542.     /* USER CODE END WHILE */
  543.  
  544.     /* USER CODE BEGIN 3 */
  545.  
  546.     if (HAL_GetTick() > Ticks)
  547.     {
  548.       Ticks += 100;
  549.       filter_ADC_samples();
  550.       // delay to calibrate ADC
  551.       if (CalCounter < 1000)
  552.       {
  553.         CalCounter += 100;
  554.       }
  555.  
  556.       if (CalCounter == 900)
  557.       {
  558.         CalibrateADC();
  559.       }
  560.     }
  561.     /* when the starter motor is on then power down the CHT sensors as they seem to fail */
  562.  
  563.     if (HAL_GPIO_ReadPin(STARTER_ON_GPIO_Port, STARTER_ON_Pin) == GPIO_PIN_RESET)
  564.     {
  565.       if (Starter_Debounce < STARTER_LIMIT)
  566.       {
  567.         Starter_Debounce++;
  568.       }
  569.     }
  570.     else
  571.     {
  572.       if (Starter_Debounce > 0)
  573.       {
  574.         Starter_Debounce--;
  575.       }
  576.     }
  577.  
  578.     if (Starter_Debounce == STARTER_LIMIT)
  579.     {
  580.       EnableTempSensors(DISABLE);
  581.       PowerTempTimer = HAL_GetTick() + 1000;
  582.     }
  583.     else
  584.     /* if the PowerTempTimer is set then wait for it to timeout, then power up CHT */
  585.     {
  586.       if ((PowerTempTimer > 0) && (HAL_GetTick() > PowerTempTimer))
  587.       {
  588.         EnableTempSensors(ENABLE);
  589.         PowerTempTimer = 0;
  590.       }
  591.     }
  592.  
  593.     // check to see if we have any incoming data, copy and append if so, if no data then create our own frames.
  594.     int c;
  595.     char send = 0;
  596.  
  597.     // poll the  input for a stop bit or timeout
  598.     if (PollSerial(&uc1))
  599.     {
  600.       resetSerialTimeout();
  601.       c = GetCharSerial(&uc1);
  602.       if (c != PLX_Stop)
  603.       {
  604.         PutCharSerial(&uc1, c); // echo all but the stop bit
  605.       }
  606.       else
  607.       {           // must be a stop character
  608.         send = 1; // start our sending process.
  609.       }
  610.     }
  611.  
  612.     // sort out auto-sending
  613.     if (TimerFlag)
  614.     {
  615.       TimerFlag = 0;
  616.       if (NoSerialIn)
  617.       {
  618.         PutCharSerial(&uc1, PLX_Start);
  619.         send = 1;
  620.       }
  621.     }
  622.     if (send)
  623.     {
  624.       send = 0;
  625.  
  626.       // send the observations
  627.       ProcessRPM(0);
  628.       ProcessTemp(0, 0, PLX_X_CHT);
  629.       ProcessTemp(1, 1, PLX_X_CHT);
  630.       ProcessTemp(2, 0, PLX_AIT);
  631.       ProcessTemp(3, 1, PLX_AIT);
  632.       ProcessBatteryVoltage(0); // Batt 1
  633.       ProcessBatteryVoltage(1); // Batt 2
  634.       ProcessCPUTemperature(0); //  built in temperature sensor
  635.  
  636.       ProcessMAP(0);
  637.       ProcessOilPress(0);
  638.  
  639.       PutCharSerial(&uc1, PLX_Stop);
  640.     }
  641.   }
  642.  
  643.   /* USER CODE END 3 */
  644. }
  645.  
  646. /**
  647.  * @brief System Clock Configuration
  648.  * @retval None
  649.  */
  650. void SystemClock_Config(void)
  651. {
  652.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  653.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  654.   RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  655.  
  656.   /** Initializes the RCC Oscillators according to the specified parameters
  657.    * in the RCC_OscInitTypeDef structure.
  658.    */
  659.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  660.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  661.   RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  662.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  663.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  664.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  665.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  666.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  667.   {
  668.     Error_Handler();
  669.   }
  670.  
  671.   /** Initializes the CPU, AHB and APB buses clocks
  672.    */
  673.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  674.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  675.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  676.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  677.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  678.  
  679.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  680.   {
  681.     Error_Handler();
  682.   }
  683.   PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  684.   PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  685.   if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  686.   {
  687.     Error_Handler();
  688.   }
  689. }
  690.  
  691. /**
  692.  * @brief ADC1 Initialization Function
  693.  * @param None
  694.  * @retval None
  695.  */
  696. static void MX_ADC1_Init(void)
  697. {
  698.  
  699.   /* USER CODE BEGIN ADC1_Init 0 */
  700.  
  701.   /* USER CODE END ADC1_Init 0 */
  702.  
  703.   ADC_ChannelConfTypeDef sConfig = {0};
  704.  
  705.   /* USER CODE BEGIN ADC1_Init 1 */
  706.  
  707.   /* USER CODE END ADC1_Init 1 */
  708.  
  709.   /** Common config
  710.    */
  711.   hadc1.Instance = ADC1;
  712.   hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  713.   hadc1.Init.ContinuousConvMode = DISABLE;
  714.   hadc1.Init.DiscontinuousConvMode = DISABLE;
  715.   hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO;
  716.   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  717.   hadc1.Init.NbrOfConversion = 7;
  718.   if (HAL_ADC_Init(&hadc1) != HAL_OK)
  719.   {
  720.     Error_Handler();
  721.   }
  722.  
  723.   /** Configure Regular Channel
  724.    */
  725.   sConfig.Channel = ADC_CHANNEL_0;
  726.   sConfig.Rank = ADC_REGULAR_RANK_1;
  727.   sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
  728.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  729.   {
  730.     Error_Handler();
  731.   }
  732.  
  733.   /** Configure Regular Channel
  734.    */
  735.   sConfig.Channel = ADC_CHANNEL_1;
  736.   sConfig.Rank = ADC_REGULAR_RANK_2;
  737.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  738.   {
  739.     Error_Handler();
  740.   }
  741.  
  742.   /** Configure Regular Channel
  743.    */
  744.   sConfig.Channel = ADC_CHANNEL_2;
  745.   sConfig.Rank = ADC_REGULAR_RANK_3;
  746.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  747.   {
  748.     Error_Handler();
  749.   }
  750.  
  751.   /** Configure Regular Channel
  752.    */
  753.   sConfig.Channel = ADC_CHANNEL_3;
  754.   sConfig.Rank = ADC_REGULAR_RANK_4;
  755.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  756.   {
  757.     Error_Handler();
  758.   }
  759.  
  760.   /** Configure Regular Channel
  761.    */
  762.   sConfig.Channel = ADC_CHANNEL_4;
  763.   sConfig.Rank = ADC_REGULAR_RANK_5;
  764.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  765.   {
  766.     Error_Handler();
  767.   }
  768.  
  769.   /** Configure Regular Channel
  770.    */
  771.   sConfig.Channel = ADC_CHANNEL_VREFINT;
  772.   sConfig.Rank = ADC_REGULAR_RANK_6;
  773.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  774.   {
  775.     Error_Handler();
  776.   }
  777.  
  778.   /** Configure Regular Channel
  779.    */
  780.   sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
  781.   sConfig.Rank = ADC_REGULAR_RANK_7;
  782.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  783.   {
  784.     Error_Handler();
  785.   }
  786.   /* USER CODE BEGIN ADC1_Init 2 */
  787.  
  788.   /* USER CODE END ADC1_Init 2 */
  789. }
  790.  
  791. /**
  792.  * @brief CAN Initialization Function
  793.  * @param None
  794.  * @retval None
  795.  */
  796. static void MX_CAN_Init(void)
  797. {
  798.  
  799.   /* USER CODE BEGIN CAN_Init 0 */
  800.  
  801.   /* USER CODE END CAN_Init 0 */
  802.  
  803.   /* USER CODE BEGIN CAN_Init 1 */
  804.  
  805.   /* USER CODE END CAN_Init 1 */
  806.   hcan.Instance = CAN1;
  807.   hcan.Init.Prescaler = 16;
  808.   hcan.Init.Mode = CAN_MODE_NORMAL;
  809.   hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  810.   hcan.Init.TimeSeg1 = CAN_BS1_1TQ;
  811.   hcan.Init.TimeSeg2 = CAN_BS2_1TQ;
  812.   hcan.Init.TimeTriggeredMode = DISABLE;
  813.   hcan.Init.AutoBusOff = DISABLE;
  814.   hcan.Init.AutoWakeUp = DISABLE;
  815.   hcan.Init.AutoRetransmission = DISABLE;
  816.   hcan.Init.ReceiveFifoLocked = DISABLE;
  817.   hcan.Init.TransmitFifoPriority = DISABLE;
  818.   if (HAL_CAN_Init(&hcan) != HAL_OK)
  819.   {
  820.     Error_Handler();
  821.   }
  822.   /* USER CODE BEGIN CAN_Init 2 */
  823.  
  824.   /* USER CODE END CAN_Init 2 */
  825. }
  826.  
  827. /**
  828.  * @brief SPI1 Initialization Function
  829.  * @param None
  830.  * @retval None
  831.  */
  832. static void MX_SPI1_Init(void)
  833. {
  834.  
  835.   /* USER CODE BEGIN SPI1_Init 0 */
  836.  
  837.   /* USER CODE END SPI1_Init 0 */
  838.  
  839.   /* USER CODE BEGIN SPI1_Init 1 */
  840.  
  841.   /* USER CODE END SPI1_Init 1 */
  842.   /* SPI1 parameter configuration*/
  843.   hspi1.Instance = SPI1;
  844.   hspi1.Init.Mode = SPI_MODE_MASTER;
  845.   hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  846.   hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  847.   hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  848.   hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  849.   hspi1.Init.NSS = SPI_NSS_SOFT;
  850.   hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
  851.   hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  852.   hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  853.   hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  854.   hspi1.Init.CRCPolynomial = 10;
  855.   if (HAL_SPI_Init(&hspi1) != HAL_OK)
  856.   {
  857.     Error_Handler();
  858.   }
  859.   /* USER CODE BEGIN SPI1_Init 2 */
  860.  
  861.   /* USER CODE END SPI1_Init 2 */
  862. }
  863.  
  864. /**
  865.  * @brief TIM2 Initialization Function
  866.  * @param None
  867.  * @retval None
  868.  */
  869. static void MX_TIM2_Init(void)
  870. {
  871.  
  872.   /* USER CODE BEGIN TIM2_Init 0 */
  873.  
  874.   /* USER CODE END TIM2_Init 0 */
  875.  
  876.   TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  877.   TIM_MasterConfigTypeDef sMasterConfig = {0};
  878.   TIM_IC_InitTypeDef sConfigIC = {0};
  879.  
  880.   /* USER CODE BEGIN TIM2_Init 1 */
  881.  
  882.   /* USER CODE END TIM2_Init 1 */
  883.   htim2.Instance = TIM2;
  884.   htim2.Init.Prescaler = 719;
  885.   htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  886.   htim2.Init.Period = 65535;
  887.   htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  888.   htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  889.   if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  890.   {
  891.     Error_Handler();
  892.   }
  893.   sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  894.   if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  895.   {
  896.     Error_Handler();
  897.   }
  898.   if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
  899.   {
  900.     Error_Handler();
  901.   }
  902.   sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  903.   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  904.   if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  905.   {
  906.     Error_Handler();
  907.   }
  908.   sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  909.   sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  910.   sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  911.   sConfigIC.ICFilter = 15;
  912.   if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  913.   {
  914.     Error_Handler();
  915.   }
  916.   sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
  917.   sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;
  918.   sConfigIC.ICFilter = 0;
  919.   if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
  920.   {
  921.     Error_Handler();
  922.   }
  923.   /* USER CODE BEGIN TIM2_Init 2 */
  924.  
  925.   /* USER CODE END TIM2_Init 2 */
  926. }
  927.  
  928. /**
  929.  * @brief TIM3 Initialization Function
  930.  * @param None
  931.  * @retval None
  932.  */
  933. static void MX_TIM3_Init(void)
  934. {
  935.  
  936.   /* USER CODE BEGIN TIM3_Init 0 */
  937.  
  938.   /* USER CODE END TIM3_Init 0 */
  939.  
  940.   TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  941.   TIM_MasterConfigTypeDef sMasterConfig = {0};
  942.   TIM_OC_InitTypeDef sConfigOC = {0};
  943.  
  944.   /* USER CODE BEGIN TIM3_Init 1 */
  945.  
  946.   /* USER CODE END TIM3_Init 1 */
  947.   htim3.Instance = TIM3;
  948.   htim3.Init.Prescaler = 719;
  949.   htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  950.   htim3.Init.Period = 199;
  951.   htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  952.   htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  953.   if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  954.   {
  955.     Error_Handler();
  956.   }
  957.   sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  958.   if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  959.   {
  960.     Error_Handler();
  961.   }
  962.   if (HAL_TIM_OC_Init(&htim3) != HAL_OK)
  963.   {
  964.     Error_Handler();
  965.   }
  966.   if (HAL_TIM_OnePulse_Init(&htim3, TIM_OPMODE_SINGLE) != HAL_OK)
  967.   {
  968.     Error_Handler();
  969.   }
  970.   sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1;
  971.   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  972.   if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  973.   {
  974.     Error_Handler();
  975.   }
  976.   sConfigOC.OCMode = TIM_OCMODE_TIMING;
  977.   sConfigOC.Pulse = 198;
  978.   sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  979.   sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  980.   if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  981.   {
  982.     Error_Handler();
  983.   }
  984.   /* USER CODE BEGIN TIM3_Init 2 */
  985.  
  986.   /* USER CODE END TIM3_Init 2 */
  987. }
  988.  
  989. /**
  990.  * @brief TIM4 Initialization Function
  991.  * @param None
  992.  * @retval None
  993.  */
  994. static void MX_TIM4_Init(void)
  995. {
  996.  
  997.   /* USER CODE BEGIN TIM4_Init 0 */
  998.  
  999.   /* USER CODE END TIM4_Init 0 */
  1000.  
  1001.   TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  1002.   TIM_MasterConfigTypeDef sMasterConfig = {0};
  1003.  
  1004.   /* USER CODE BEGIN TIM4_Init 1 */
  1005.  
  1006.   /* USER CODE END TIM4_Init 1 */
  1007.   htim4.Instance = TIM4;
  1008.   htim4.Init.Prescaler = 719;
  1009.   htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  1010.   htim4.Init.Period = 9999;
  1011.   htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  1012.   htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  1013.   if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  1014.   {
  1015.     Error_Handler();
  1016.   }
  1017.   sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  1018.   if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  1019.   {
  1020.     Error_Handler();
  1021.   }
  1022.   sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  1023.   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  1024.   if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  1025.   {
  1026.     Error_Handler();
  1027.   }
  1028.   /* USER CODE BEGIN TIM4_Init 2 */
  1029.  
  1030.   /* USER CODE END TIM4_Init 2 */
  1031. }
  1032.  
  1033. /**
  1034.  * @brief USART1 Initialization Function
  1035.  * @param None
  1036.  * @retval None
  1037.  */
  1038. static void MX_USART1_UART_Init(void)
  1039. {
  1040.  
  1041.   /* USER CODE BEGIN USART1_Init 0 */
  1042.  
  1043.   /* USER CODE END USART1_Init 0 */
  1044.  
  1045.   /* USER CODE BEGIN USART1_Init 1 */
  1046.  
  1047.   /* USER CODE END USART1_Init 1 */
  1048.   huart1.Instance = USART1;
  1049.   huart1.Init.BaudRate = 19200;
  1050.   huart1.Init.WordLength = UART_WORDLENGTH_8B;
  1051.   huart1.Init.StopBits = UART_STOPBITS_1;
  1052.   huart1.Init.Parity = UART_PARITY_NONE;
  1053.   huart1.Init.Mode = UART_MODE_TX_RX;
  1054.   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  1055.   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  1056.   if (HAL_UART_Init(&huart1) != HAL_OK)
  1057.   {
  1058.     Error_Handler();
  1059.   }
  1060.   /* USER CODE BEGIN USART1_Init 2 */
  1061.  
  1062.   /* USER CODE END USART1_Init 2 */
  1063. }
  1064.  
  1065. /**
  1066.  * Enable DMA controller clock
  1067.  */
  1068. static void MX_DMA_Init(void)
  1069. {
  1070.  
  1071.   /* DMA controller clock enable */
  1072.   __HAL_RCC_DMA1_CLK_ENABLE();
  1073.  
  1074.   /* DMA interrupt init */
  1075.   /* DMA1_Channel1_IRQn interrupt configuration */
  1076.   HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  1077.   HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
  1078. }
  1079.  
  1080. /**
  1081.  * @brief GPIO Initialization Function
  1082.  * @param None
  1083.  * @retval None
  1084.  */
  1085. static void MX_GPIO_Init(void)
  1086. {
  1087.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  1088.  
  1089.   /* GPIO Ports Clock Enable */
  1090.   __HAL_RCC_GPIOC_CLK_ENABLE();
  1091.   __HAL_RCC_GPIOD_CLK_ENABLE();
  1092.   __HAL_RCC_GPIOA_CLK_ENABLE();
  1093.   __HAL_RCC_GPIOB_CLK_ENABLE();
  1094.  
  1095.   /*Configure GPIO pin Output Level */
  1096.   HAL_GPIO_WritePin(LED_Blink_GPIO_Port, LED_Blink_Pin, GPIO_PIN_RESET);
  1097.  
  1098.   /*Configure GPIO pin Output Level */
  1099.   HAL_GPIO_WritePin(GPIOB, SPI_CS_Clk_Pin | SPI_CS_D_Pin | ENA_AUX_5V_Pin, GPIO_PIN_RESET);
  1100.  
  1101.   /*Configure GPIO pin : LED_Blink_Pin */
  1102.   GPIO_InitStruct.Pin = LED_Blink_Pin;
  1103.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  1104.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  1105.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  1106.   HAL_GPIO_Init(LED_Blink_GPIO_Port, &GPIO_InitStruct);
  1107.  
  1108.   /*Configure GPIO pins : SPI_CS_Clk_Pin SPI_CS_D_Pin ENA_AUX_5V_Pin */
  1109.   GPIO_InitStruct.Pin = SPI_CS_Clk_Pin | SPI_CS_D_Pin | ENA_AUX_5V_Pin;
  1110.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  1111.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  1112.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  1113.   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  1114.  
  1115.   /*Configure GPIO pin : STARTER_ON_Pin */
  1116.   GPIO_InitStruct.Pin = STARTER_ON_Pin;
  1117.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  1118.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  1119.   HAL_GPIO_Init(STARTER_ON_GPIO_Port, &GPIO_InitStruct);
  1120. }
  1121.  
  1122. /* USER CODE BEGIN 4 */
  1123.  
  1124. /* USER CODE END 4 */
  1125.  
  1126. /**
  1127.  * @brief  This function is executed in case of error occurrence.
  1128.  * @retval None
  1129.  */
  1130. void Error_Handler(void)
  1131. {
  1132.   /* USER CODE BEGIN Error_Handler_Debug */
  1133.   /* User can add his own implementation to report the HAL error return state */
  1134.  
  1135.   /* USER CODE END Error_Handler_Debug */
  1136. }
  1137.  
  1138. #ifdef USE_FULL_ASSERT
  1139. /**
  1140.  * @brief  Reports the name of the source file and the source line number
  1141.  *         where the assert_param error has occurred.
  1142.  * @param  file: pointer to the source file name
  1143.  * @param  line: assert_param error line source number
  1144.  * @retval None
  1145.  */
  1146. void assert_failed(uint8_t *file, uint32_t line)
  1147. {
  1148.   /* USER CODE BEGIN 6 */
  1149.   /* User can add his own implementation to report the file name and line number,
  1150.      tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  1151.   /* USER CODE END 6 */
  1152. }
  1153. #endif /* USE_FULL_ASSERT */
  1154.