Subversion Repositories DashDisplay

Rev

Rev 73 | Rev 75 | 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) 2020 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.  
  26. #include "libPLX/plx.h"
  27. #include "libSerial/serial.H"
  28. #include "libSmallPrintf/small_printf.h"
  29. #include "libNMEA/nmea.h"
  30. #include "switches.h"
  31. #include <string.h>
  32.  
  33. /* USER CODE END Includes */
  34.  
  35. /* Private typedef -----------------------------------------------------------*/
  36. /* USER CODE BEGIN PTD */
  37.  
  38. /* USER CODE END PTD */
  39.  
  40. /* Private define ------------------------------------------------------------*/
  41. /* USER CODE BEGIN PD */
  42. /* USER CODE END PD */
  43.  
  44. /* Private macro -------------------------------------------------------------*/
  45. /* USER CODE BEGIN PM */
  46.  
  47. /* USER CODE END PM */
  48.  
  49. /* Private variables ---------------------------------------------------------*/
  50. I2C_HandleTypeDef hi2c1;
  51.  
  52. SPI_HandleTypeDef hspi1;
  53.  
  54. TIM_HandleTypeDef htim2;
  55. TIM_HandleTypeDef htim3;
  56. TIM_HandleTypeDef htim9;
  57.  
  58. UART_HandleTypeDef huart4;
  59. UART_HandleTypeDef huart1;
  60. UART_HandleTypeDef huart2;
  61. UART_HandleTypeDef huart3;
  62.  
  63. /* USER CODE BEGIN PV */
  64. /* Private variables ---------------------------------------------------------*/
  65.  
  66. context_t contexts[MAX_DISPLAYS];
  67.  
  68. ///@brief  timeout when the ignition is switched off
  69. #define IGNITION_OFF_TIMEOUT 30000UL
  70.  
  71. /// @brief 1000mS per logger period, print average per period
  72. #define LOGGER_INTERVAL 500UL
  73.  
  74. /// @brief  about 10 seconds after twiddle, save the dial position.
  75. const int DialTimeout = 100;
  76.  
  77. /// @brief Data storage for readings
  78. info_t Info[MAXRDG];
  79.  
  80. /// @brief Define a null item
  81. const info_t nullInfo = {.Max = 0,
  82.                          .Min = 0xFFF,
  83.                          .sum = 0,
  84.                          .count = 0,
  85.                          .updated = 0,
  86.                          .lastUpdated = 0,
  87.                          .observation.Obs = PLX_MAX_OBS,
  88.                          .observation.Instance = PLX_MAX_INST};
  89.  
  90. /// \brief storage for incoming data
  91. data_t Data;
  92.  
  93. uint32_t Latch_Timer = IGNITION_OFF_TIMEOUT;
  94.  
  95. // location for GPS data
  96. Location loc;
  97.  
  98. /// @brief Time when the logged data will be sent
  99. uint32_t nextTickReload = 0;
  100.  
  101. /* USER CODE END PV */
  102.  
  103. /* Private function prototypes -----------------------------------------------*/
  104. void SystemClock_Config(void);
  105. static void MX_GPIO_Init(void);
  106. static void MX_SPI1_Init(void);
  107. static void MX_USART1_UART_Init(void);
  108. static void MX_USART2_UART_Init(void);
  109. static void MX_USART3_UART_Init(void);
  110. static void MX_TIM3_Init(void);
  111. static void MX_TIM9_Init(void);
  112. static void MX_TIM2_Init(void);
  113. static void MX_UART4_Init(void);
  114. static void MX_I2C1_Init(void);
  115. /* USER CODE BEGIN PFP */
  116.  
  117. // the dial is the switch number we are using.
  118. // suppress is the ItemIndex we wish to suppress on this display
  119. int DisplayCurrent(int dial, int suppress)
  120. {
  121.   return cc_display(dial, suppress);
  122. }
  123.  
  124. /// \note  HC-05 only accepts : 9600,19200,38400,57600,115200,230400,460800 baud
  125. /// \brief Setup Bluetooth module
  126. void initModule(usart_ctl *ctl, uint32_t baudRate)
  127. {
  128.   char initBuf[60];
  129.   // switch to command mode
  130.   HAL_GPIO_WritePin(BT_RESET_GPIO_Port, BT_RESET_Pin, GPIO_PIN_SET);
  131.   HAL_Delay(500);
  132.   // clear the button press
  133.   HAL_GPIO_WritePin(BT_RESET_GPIO_Port, BT_RESET_Pin, GPIO_PIN_RESET);
  134.   HAL_Delay(500);
  135.   setBaud(ctl, 38400);
  136.   int initLen = small_sprintf(initBuf, "AT\nAT+UART?\nAT+UART=%ld,0,0\n", baudRate);
  137.   const char buf[] = "AT+RESET\n";
  138.   sendString(ctl, initBuf, initLen);
  139.   HAL_Delay(500);
  140.   initLen = small_sprintf(initBuf, buf);
  141.   sendString(ctl, initBuf, initLen);
  142.  
  143.   TxWaitEmpty(ctl);
  144.  
  145.   // switch back to normal comms at new baud rate
  146.   setBaud(ctl, baudRate);
  147.   HAL_Delay(100);
  148. }
  149.  
  150. // workspace for RMC data read from GPS module.
  151. volatile uint16_t rmc_length;
  152.  
  153. uint8_t rmc_callback(uint8_t *data, uint16_t length)
  154. {
  155.   // send it back out
  156.   rmc_length = length;
  157.  
  158.   sendString(&uc3, (const char *)data, length);
  159.  
  160.   nextTickReload = HAL_GetTick() + LOGGER_INTERVAL;
  161.  
  162.   return 0;
  163. }
  164.  
  165. // check if bluetooth connected
  166. uint8_t btConnected()
  167. {
  168.   return HAL_GPIO_ReadPin(BT_STATE_GPIO_Port, BT_STATE_Pin) == GPIO_PIN_SET;
  169. }
  170.  
  171. /// @brief return true if this slot is unused
  172. /// @param ptr pointer to the slot to
  173. uint8_t isUnused(int index)
  174. {
  175.   if (index < 0 || index > MAXRDG)
  176.     return false;
  177.  
  178.   return Info[index].observation.Instance == PLX_MAX_INST && Info[index].observation.Obs == PLX_MAX_OBS;
  179. }
  180.  
  181. /// @brief Determine if an entry is currently valid
  182. /// @param index the number of the array entry to display
  183. /// @return true if the entry contains data which is fresh
  184. uint8_t isValid(int index)
  185. {
  186.   if (index < 0 || index > MAXRDG)
  187.     return false;
  188.   if (isUnused(index))
  189.     return false;
  190.  
  191.   uint32_t age = HAL_GetTick() - Info[index].lastUpdated;
  192.  
  193.   if (age > 300)
  194.     return false;
  195.  
  196.   return true;
  197. }
  198.  
  199. /* USER CODE END PFP */
  200.  
  201. /* Private user code ---------------------------------------------------------*/
  202. /* USER CODE BEGIN 0 */
  203.  
  204. /* USER CODE END 0 */
  205.  
  206. /**
  207.  * @brief  The application entry point.
  208.  * @retval int
  209.  */
  210. int main(void)
  211. {
  212.   /* USER CODE BEGIN 1 */
  213.   __HAL_RCC_SPI1_CLK_ENABLE();
  214.   __HAL_RCC_USART1_CLK_ENABLE(); // PLX main port
  215.   __HAL_RCC_USART2_CLK_ENABLE(); // debug port
  216.   __HAL_RCC_USART3_CLK_ENABLE(); // Bluetooth port
  217.   __HAL_RCC_UART4_CLK_ENABLE();  // NMEA0183 port
  218.  
  219.   __HAL_RCC_TIM3_CLK_ENABLE();
  220.  
  221.   __HAL_RCC_TIM9_CLK_ENABLE();
  222.  
  223.   /* USER CODE END 1 */
  224.  
  225.   /* MCU Configuration--------------------------------------------------------*/
  226.  
  227.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  228.   HAL_Init();
  229.  
  230.   /* USER CODE BEGIN Init */
  231.  
  232.   /* USER CODE END Init */
  233.  
  234.   /* Configure the system clock */
  235.   SystemClock_Config();
  236.  
  237.   /* USER CODE BEGIN SysInit */
  238.   // Switch handler called on sysTick interrupt.
  239.   InitSwitches();
  240.  
  241.   /* USER CODE END SysInit */
  242.  
  243.   /* Initialize all configured peripherals */
  244.   MX_GPIO_Init();
  245.   MX_SPI1_Init();
  246.   MX_USART1_UART_Init();
  247.   MX_USART2_UART_Init();
  248.   MX_USART3_UART_Init();
  249.   MX_TIM3_Init();
  250.   MX_TIM9_Init();
  251.   MX_TIM2_Init();
  252.   MX_UART4_Init();
  253.   MX_I2C1_Init();
  254.   /* USER CODE BEGIN 2 */
  255.  
  256.   /* Turn on USART1 IRQ */
  257.   HAL_NVIC_SetPriority(USART1_IRQn, 2, 0);
  258.   HAL_NVIC_EnableIRQ(USART1_IRQn);
  259.  
  260.   /* Turn on USART2 IRQ  */
  261.   HAL_NVIC_SetPriority(USART2_IRQn, 4, 0);
  262.   HAL_NVIC_EnableIRQ(USART2_IRQn);
  263.  
  264.   /* turn on USART3 IRQ */
  265.   HAL_NVIC_SetPriority(USART3_IRQn, 4, 0);
  266.   HAL_NVIC_EnableIRQ(USART3_IRQn);
  267.  
  268.   /* turn on UART4 IRQ */
  269.   HAL_NVIC_SetPriority(UART4_IRQn, 4, 0);
  270.   HAL_NVIC_EnableIRQ(UART4_IRQn);
  271.  
  272.   /* setup the USART control blocks */
  273.   init_usart_ctl(&uc1, &huart1);
  274.   init_usart_ctl(&uc2, &huart2);
  275.   init_usart_ctl(&uc3, &huart3);
  276.   init_usart_ctl(&uc4, &huart4);
  277.  
  278.   EnableSerialRxInterrupt(&uc1);
  279.   EnableSerialRxInterrupt(&uc2);
  280.   EnableSerialRxInterrupt(&uc3);
  281.   EnableSerialRxInterrupt(&uc4);
  282.  
  283.   HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
  284.  
  285.   HAL_TIM_Encoder_Start(&htim9, TIM_CHANNEL_ALL);
  286.  
  287.   initModule(&uc3, 38400);
  288.  
  289.   // Initialise UART for 4800 baud NMEA
  290.   setBaud(&uc2, 4800);
  291.  
  292.   // Initialuse UART4 for 4800 baud NMEA.
  293.   setBaud(&uc4, 4800);
  294.  
  295.   cc_init();
  296.  
  297.   int i;
  298.   for (i = 0; i < 2; i++)
  299.   {
  300.     contexts[i].knobPos = -1; // set the knob position
  301.   }
  302.  
  303.   /* reset the display timeout, latch on power from accessories */
  304.   Latch_Timer = IGNITION_OFF_TIMEOUT;
  305.   HAL_GPIO_WritePin(POWER_LATCH_GPIO_Port, POWER_LATCH_Pin, GPIO_PIN_RESET);
  306.  
  307.   setRmcCallback(&rmc_callback);
  308.  
  309.   // data timeout
  310.   uint32_t timeout = 0; //
  311.  
  312.   // used in NMEA style logging
  313.   uint32_t nextTick = 0;    ///< time to send next
  314.   uint32_t offsetTicks = 0; ///< time to print as offset in mS for each loop
  315.  
  316.   // PLX decoder protocols
  317.   char PLXPacket = 0;
  318.  
  319.   for (i = 0; i < MAXRDG; i++)
  320.   {
  321.     Info[i] = nullInfo;
  322.   }
  323.  
  324.   int PLXPtr = 0;
  325.  
  326.   uint32_t resetCounter = 0; // record time at which both reset buttons were first pressed.
  327.  
  328.   /* USER CODE END 2 */
  329.  
  330.   /* Infinite loop */
  331.   /* USER CODE BEGIN WHILE */
  332.   while (1)
  333.   {
  334.  
  335.     /* while ignition is on, keep resetting power latch timer */
  336.     if (HAL_GPIO_ReadPin(IGNITION_GPIO_Port, IGNITION_Pin) == GPIO_PIN_RESET)
  337.     {
  338.       Latch_Timer = HAL_GetTick() + IGNITION_OFF_TIMEOUT;
  339.     }
  340.     else
  341.     {
  342.       /* if the ignition has been off for a while, then turn off power */
  343.       if (HAL_GetTick() > Latch_Timer)
  344.       {
  345.         HAL_GPIO_WritePin(POWER_LATCH_GPIO_Port, POWER_LATCH_Pin,
  346.                           GPIO_PIN_RESET);
  347.       }
  348.     }
  349.  
  350.     // Handle the bluetooth pairing / reset function by pressing both buttons.
  351.     if ((push_pos[0] == 1) && (push_pos[1] == 1))
  352.     {
  353.       HAL_GPIO_WritePin(BT_BUTTON_GPIO_Port, BT_BUTTON_Pin,
  354.                         GPIO_PIN_RESET);
  355.       if (resetCounter == 0)
  356.         resetCounter = HAL_GetTick();
  357.     }
  358.     else
  359.     {
  360.       HAL_GPIO_WritePin(BT_BUTTON_GPIO_Port, BT_BUTTON_Pin,
  361.                         GPIO_PIN_SET);
  362.  
  363.       if (resetCounter != 0)
  364.       {
  365.         // Held down reset button for 10 seconds, clear NVRAM.
  366.         if ((HAL_GetTick() - resetCounter) > 10000)
  367.         {
  368.           for (i = 0; i < 2; i++)
  369.           {
  370.             contexts[i].knobPos = -1;   // set the knob position
  371.             contexts[i].dial_timer = 1; // timeout immediately when decremented
  372.           }
  373.           erase_nvram();
  374.         }
  375.         resetCounter = 0;
  376.       }
  377.     }
  378.  
  379.     // poll GPS Position/time on UART4
  380.     (void)updateLocation(&loc, &uc4);
  381.     if (loc.valid == 'V')
  382.       memset(loc.time, '-', 6);
  383.  
  384.     // if permitted, log data from RMC packet
  385.     if (btConnected())
  386.     {
  387.       // Any RMC data, send it, reset the logger timeout
  388.  
  389.       // Timeout for data logging regularly
  390.       if (HAL_GetTick() > nextTick)
  391.       {
  392.         nextTick = nextTickReload;
  393.         nextTickReload += LOGGER_INTERVAL;
  394.    
  395.         // Send items  to BT if it is in connected state
  396.         // print timestamp as a $PLTIM record.
  397.         char linebuff[20];
  398.         strftime(linebuff, sizeof(linebuff), "%H%M%S", &loc.tv);
  399.  
  400.         char outbuff[100];
  401.         int cnt = small_sprintf(outbuff, "$PLTIM,%s.%03lu\n", linebuff, offsetTicks);
  402.         sendString(&uc3, outbuff, cnt);
  403.         offsetTicks += LOGGER_INTERVAL;
  404.        
  405.                if (offsetTicks >= (1000))
  406.         {
  407.           offsetTicks = 0;
  408.           loc.tv.tm_sec++;
  409.           if (loc.tv.tm_sec >= 60)
  410.           {
  411.             loc.tv.tm_sec = 0;
  412.             loc.tv.tm_min++;
  413.             if (loc.tv.tm_min >= 60)
  414.             {
  415.               loc.tv.tm_hour++;
  416.               if (loc.tv.tm_hour >= 24)
  417.                 loc.tv.tm_hour = 0;
  418.             }
  419.           }
  420.         }
  421.  
  422.        
  423.        
  424.        
  425.        
  426.        
  427.         for (int i = 0; i < MAXRDG; ++i)
  428.         {
  429.           if (!isValid(i))
  430.             continue;
  431.           // print logger items as $PLLOG record
  432.           int cnt = small_sprintf(outbuff,
  433.                                   "$PLLOG,%d,%d,%ld",
  434.                                   Info[i].observation.Obs,
  435.                                   Info[i].observation.Instance,
  436.                                   Info[i].count == 0 ? 0 : Info[i].sum / Info[i].count);
  437.           Info[i].count = 0;
  438.           Info[i].sum = 0;
  439.  
  440.           // NMEA style checksum
  441.           int ck;
  442.           int sum = 0;
  443.           for (ck = 1; ck < cnt; ck++)
  444.             sum += outbuff[ck];
  445.           cnt += small_sprintf(outbuff + cnt, "*%02X\n",
  446.                                sum & 0xFF);
  447.           sendString(&uc3, outbuff, cnt);
  448.         }
  449.       }
  450.     }
  451.  
  452.     // determine if we are getting any data from the interface
  453.     uint16_t cc = SerialCharsReceived(&uc1);
  454.     int chr;
  455.     if (cc == 0)
  456.     {
  457.       timeout++;
  458.       if (btConnected() && (timeout % 1000 == 0))
  459.       {
  460.         const char msg[] = "Timeout\r\n";
  461.         sendString(&uc3, msg, sizeof(msg));
  462.       }
  463.  
  464.       if (timeout > 60000)
  465.       {
  466.  
  467.         // do turn off screen
  468.       }
  469.       // wait for a bit if nothing came in.
  470.       HAL_Delay(1);
  471.     }
  472.  
  473.     /// process the observation list
  474.     for (chr = 0; chr < cc; chr++)
  475.     {
  476.       char c = GetCharSerial(&uc1);
  477.  
  478.       if (c == PLX_Start) // at any time if the start byte appears, reset the pointers
  479.       {
  480.         PLXPtr = 0; // reset the pointer
  481.         PLXPacket = 1;
  482.         timeout = 0; // Reset the timer
  483.         continue;
  484.       }
  485.       if (c == PLX_Stop)
  486.       {
  487.         if (PLXPacket)
  488.         {
  489.           // we can now decode the selected parameter
  490.           int PLXNewItems = PLXPtr / sizeof(PLX_SensorInfo); // total items in last reading batch
  491.  
  492.           // process items
  493.           for (i = 0; i < PLXNewItems; i++)
  494.           {
  495.             // search to see if the item already has a slot in the Info[] array
  496.             // match the observation and instance: if found, update entry
  497.             enum PLX_Observations observation = ConvPLX(Data.Sensor[i].AddrH,
  498.                                                         Data.Sensor[i].AddrL);
  499.  
  500.             char instance = Data.Sensor[i].Instance;
  501.  
  502.             // validate the current item, discard out of range
  503.  
  504.             if ((instance > PLX_MAX_INST) || (observation > PLX_MAX_OBS))
  505.               continue;
  506.  
  507.             // search for the item in the list
  508.             int j;
  509.             for (j = 0; j < MAXRDG; ++j)
  510.             {
  511.               if ((Info[j].observation.Obs == observation) && (Info[j].observation.Instance == instance))
  512.                 break;
  513.             }
  514.             // fallen off the end of the list of existing items without a match, so j points at next new item
  515.             //
  516.             // Find an unused slot
  517.  
  518.             if (j == MAXRDG)
  519.             {
  520.               int k;
  521.               {
  522.                 for (k = 0; k < MAXRDG; ++k)
  523.                   if (!isValid(k))
  524.                   {
  525.                     j = k; // found a spare slot
  526.                     break;
  527.                   }
  528.               }
  529.               if (k == MAXRDG)
  530.                 continue; // abandon this iteration
  531.             }
  532.  
  533.             // give up if we are going to fall off the end of the array
  534.             if (j > MAXRDG)
  535.               break;
  536.  
  537.             Info[j].observation.Obs = observation;
  538.  
  539.             Info[j].observation.Instance = instance;
  540.             Info[j].data = ConvPLX(Data.Sensor[j].ReadingH,
  541.                                    Data.Sensor[j].ReadingL);
  542.             if (Info[j].data > Info[j].Max)
  543.             {
  544.               Info[j].Max = Info[j].data;
  545.             }
  546.             if (Info[j].data < Info[j].Min)
  547.             {
  548.               Info[j].Min = Info[j].data;
  549.             }
  550.             // take an average
  551.             Info[j].sum += Info[j].data;
  552.             Info[j].count++;
  553.             // note the last update time
  554.             Info[j].lastUpdated = HAL_GetTick();
  555.             Info[j].updated = 1; // it has been updated
  556.           }
  557.           PLXPtr = 0;
  558.           PLXPacket = 0;
  559.  
  560.           // scan through and invalidate all old items
  561.           for (int i = 0; i < MAXRDG; ++i)
  562.           {
  563.             if (!isValid(i))
  564.               Info[i] = nullInfo;
  565.           }
  566.  
  567.           break; // something to process
  568.         }
  569.       }
  570.       if (c > PLX_Stop) // illegal char, restart reading
  571.       {
  572.         PLXPacket = 0;
  573.         PLXPtr = 0;
  574.         continue;
  575.       }
  576.       if (PLXPacket && PLXPtr < sizeof(Data.Bytes))
  577.       {
  578.         Data.Bytes[PLXPtr++] = c;
  579.       }
  580.     }
  581.  
  582.     // handle switch rotation
  583.     for (i = 0; i < MAX_DIALS; ++i)
  584.     {
  585.       int delta = get_dial_diff(i);
  586.       int pos = contexts[i].knobPos;
  587.       if (pos < 0)
  588.         break; // dont process until we have read NVRAM for the first time .
  589.       int start = pos;
  590.       // move in positive direction
  591.       while (delta > 0)
  592.       {
  593.         // skip invalid items, dont count
  594.         if (pos < MAXRDG - 1)
  595.           pos++;
  596.         else
  597.           pos = 0;
  598.  
  599.         if (isValid(pos))
  600.           delta--; // count a valid item
  601.  
  602.         // wrap
  603.         if (pos == start)
  604.           break;
  605.       }
  606.  
  607.       // move in negative direction
  608.       while (delta < 0)
  609.  
  610.       {
  611.         // skip invalid items, dont count
  612.         if (pos > 0)
  613.           pos--;
  614.         else
  615.           pos = MAXRDG - 1;
  616.  
  617.         if (isValid(pos))
  618.           delta++; // count a valid item
  619.  
  620.         // wrap
  621.         if (pos == start)
  622.           break;
  623.       }
  624.  
  625.       contexts[i].knobPos = pos;
  626.       if (pos != start)
  627.         contexts[i].dial_timer = DialTimeout;
  628.     }
  629.  
  630.     int suppress = -1;
  631.     for (i = 0; i < MAX_DISPLAYS; i++)
  632.     { // now to display the information
  633.       suppress = DisplayCurrent(i, suppress);
  634.  
  635.       cc_check_nvram(i);
  636.     }
  637.     /* USER CODE END WHILE */
  638.   }
  639.   /* USER CODE BEGIN 3 */
  640.  
  641.   /* USER CODE END 3 */
  642. }
  643.  
  644. /**
  645.  * @brief System Clock Configuration
  646.  * @retval None
  647.  */
  648. void SystemClock_Config(void)
  649. {
  650.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  651.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  652.  
  653.   /** Configure the main internal regulator output voltage
  654.    */
  655.   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  656.  
  657.   /** Initializes the RCC Oscillators according to the specified parameters
  658.    * in the RCC_OscInitTypeDef structure.
  659.    */
  660.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  661.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  662.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  663.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  664.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12;
  665.   RCC_OscInitStruct.PLL.PLLDIV = RCC_PLL_DIV3;
  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_DIV1;
  677.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  678.  
  679.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  680.   {
  681.     Error_Handler();
  682.   }
  683. }
  684.  
  685. /**
  686.  * @brief I2C1 Initialization Function
  687.  * @param None
  688.  * @retval None
  689.  */
  690. static void MX_I2C1_Init(void)
  691. {
  692.  
  693.   /* USER CODE BEGIN I2C1_Init 0 */
  694.  
  695.   /* USER CODE END I2C1_Init 0 */
  696.  
  697.   /* USER CODE BEGIN I2C1_Init 1 */
  698.  
  699.   /* USER CODE END I2C1_Init 1 */
  700.   hi2c1.Instance = I2C1;
  701.   hi2c1.Init.ClockSpeed = 100000;
  702.   hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  703.   hi2c1.Init.OwnAddress1 = 0;
  704.   hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  705.   hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  706.   hi2c1.Init.OwnAddress2 = 0;
  707.   hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  708.   hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  709.   if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  710.   {
  711.     Error_Handler();
  712.   }
  713.   /* USER CODE BEGIN I2C1_Init 2 */
  714.  
  715.   /* USER CODE END I2C1_Init 2 */
  716. }
  717.  
  718. /**
  719.  * @brief SPI1 Initialization Function
  720.  * @param None
  721.  * @retval None
  722.  */
  723. static void MX_SPI1_Init(void)
  724. {
  725.  
  726.   /* USER CODE BEGIN SPI1_Init 0 */
  727.  
  728.   /* USER CODE END SPI1_Init 0 */
  729.  
  730.   /* USER CODE BEGIN SPI1_Init 1 */
  731.  
  732.   /* USER CODE END SPI1_Init 1 */
  733.   /* SPI1 parameter configuration*/
  734.   hspi1.Instance = SPI1;
  735.   hspi1.Init.Mode = SPI_MODE_MASTER;
  736.   hspi1.Init.Direction = SPI_DIRECTION_1LINE;
  737.   hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  738.   hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
  739.   hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  740.   hspi1.Init.NSS = SPI_NSS_SOFT;
  741.   hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
  742.   hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  743.   hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  744.   hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  745.   hspi1.Init.CRCPolynomial = 10;
  746.   if (HAL_SPI_Init(&hspi1) != HAL_OK)
  747.   {
  748.     Error_Handler();
  749.   }
  750.   /* USER CODE BEGIN SPI1_Init 2 */
  751.  
  752.   /* USER CODE END SPI1_Init 2 */
  753. }
  754.  
  755. /**
  756.  * @brief TIM2 Initialization Function
  757.  * @param None
  758.  * @retval None
  759.  */
  760. static void MX_TIM2_Init(void)
  761. {
  762.  
  763.   /* USER CODE BEGIN TIM2_Init 0 */
  764.  
  765.   /* USER CODE END TIM2_Init 0 */
  766.  
  767.   TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  768.   TIM_MasterConfigTypeDef sMasterConfig = {0};
  769.  
  770.   /* USER CODE BEGIN TIM2_Init 1 */
  771.  
  772.   /* USER CODE END TIM2_Init 1 */
  773.   htim2.Instance = TIM2;
  774.   htim2.Init.Prescaler = 0;
  775.   htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  776.   htim2.Init.Period = 65535;
  777.   htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  778.   htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  779.   if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  780.   {
  781.     Error_Handler();
  782.   }
  783.   sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  784.   if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  785.   {
  786.     Error_Handler();
  787.   }
  788.   sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  789.   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  790.   if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  791.   {
  792.     Error_Handler();
  793.   }
  794.   /* USER CODE BEGIN TIM2_Init 2 */
  795.  
  796.   /* USER CODE END TIM2_Init 2 */
  797. }
  798.  
  799. /**
  800.  * @brief TIM3 Initialization Function
  801.  * @param None
  802.  * @retval None
  803.  */
  804. static void MX_TIM3_Init(void)
  805. {
  806.  
  807.   /* USER CODE BEGIN TIM3_Init 0 */
  808.  
  809.   /* USER CODE END TIM3_Init 0 */
  810.  
  811.   TIM_Encoder_InitTypeDef sConfig = {0};
  812.   TIM_MasterConfigTypeDef sMasterConfig = {0};
  813.  
  814.   /* USER CODE BEGIN TIM3_Init 1 */
  815.  
  816.   /* USER CODE END TIM3_Init 1 */
  817.   htim3.Instance = TIM3;
  818.   htim3.Init.Prescaler = 0;
  819.   htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  820.   htim3.Init.Period = 65535;
  821.   htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  822.   htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  823.   sConfig.EncoderMode = TIM_ENCODERMODE_TI1;
  824.   sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  825.   sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  826.   sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  827.   sConfig.IC1Filter = 15;
  828.   sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  829.   sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  830.   sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  831.   sConfig.IC2Filter = 15;
  832.   if (HAL_TIM_Encoder_Init(&htim3, &sConfig) != HAL_OK)
  833.   {
  834.     Error_Handler();
  835.   }
  836.   sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  837.   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  838.   if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  839.   {
  840.     Error_Handler();
  841.   }
  842.   /* USER CODE BEGIN TIM3_Init 2 */
  843.  
  844.   /* USER CODE END TIM3_Init 2 */
  845. }
  846.  
  847. /**
  848.  * @brief TIM9 Initialization Function
  849.  * @param None
  850.  * @retval None
  851.  */
  852. static void MX_TIM9_Init(void)
  853. {
  854.  
  855.   /* USER CODE BEGIN TIM9_Init 0 */
  856.  
  857.   /* USER CODE END TIM9_Init 0 */
  858.  
  859.   TIM_Encoder_InitTypeDef sConfig = {0};
  860.   TIM_MasterConfigTypeDef sMasterConfig = {0};
  861.  
  862.   /* USER CODE BEGIN TIM9_Init 1 */
  863.  
  864.   /* USER CODE END TIM9_Init 1 */
  865.   htim9.Instance = TIM9;
  866.   htim9.Init.Prescaler = 0;
  867.   htim9.Init.CounterMode = TIM_COUNTERMODE_UP;
  868.   htim9.Init.Period = 65535;
  869.   htim9.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  870.   htim9.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  871.   sConfig.EncoderMode = TIM_ENCODERMODE_TI1;
  872.   sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  873.   sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  874.   sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  875.   sConfig.IC1Filter = 15;
  876.   sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  877.   sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  878.   sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  879.   sConfig.IC2Filter = 0;
  880.   if (HAL_TIM_Encoder_Init(&htim9, &sConfig) != HAL_OK)
  881.   {
  882.     Error_Handler();
  883.   }
  884.   sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  885.   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  886.   if (HAL_TIMEx_MasterConfigSynchronization(&htim9, &sMasterConfig) != HAL_OK)
  887.   {
  888.     Error_Handler();
  889.   }
  890.   /* USER CODE BEGIN TIM9_Init 2 */
  891.  
  892.   /* USER CODE END TIM9_Init 2 */
  893. }
  894.  
  895. /**
  896.  * @brief UART4 Initialization Function
  897.  * @param None
  898.  * @retval None
  899.  */
  900. static void MX_UART4_Init(void)
  901. {
  902.  
  903.   /* USER CODE BEGIN UART4_Init 0 */
  904.  
  905.   /* USER CODE END UART4_Init 0 */
  906.  
  907.   /* USER CODE BEGIN UART4_Init 1 */
  908.  
  909.   /* USER CODE END UART4_Init 1 */
  910.   huart4.Instance = UART4;
  911.   huart4.Init.BaudRate = 4800;
  912.   huart4.Init.WordLength = UART_WORDLENGTH_8B;
  913.   huart4.Init.StopBits = UART_STOPBITS_1;
  914.   huart4.Init.Parity = UART_PARITY_NONE;
  915.   huart4.Init.Mode = UART_MODE_TX_RX;
  916.   huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  917.   huart4.Init.OverSampling = UART_OVERSAMPLING_16;
  918.   if (HAL_UART_Init(&huart4) != HAL_OK)
  919.   {
  920.     Error_Handler();
  921.   }
  922.   /* USER CODE BEGIN UART4_Init 2 */
  923.  
  924.   /* USER CODE END UART4_Init 2 */
  925. }
  926.  
  927. /**
  928.  * @brief USART1 Initialization Function
  929.  * @param None
  930.  * @retval None
  931.  */
  932. static void MX_USART1_UART_Init(void)
  933. {
  934.  
  935.   /* USER CODE BEGIN USART1_Init 0 */
  936.  
  937.   /* USER CODE END USART1_Init 0 */
  938.  
  939.   /* USER CODE BEGIN USART1_Init 1 */
  940.  
  941.   /* USER CODE END USART1_Init 1 */
  942.   huart1.Instance = USART1;
  943.   huart1.Init.BaudRate = 19200;
  944.   huart1.Init.WordLength = UART_WORDLENGTH_8B;
  945.   huart1.Init.StopBits = UART_STOPBITS_1;
  946.   huart1.Init.Parity = UART_PARITY_NONE;
  947.   huart1.Init.Mode = UART_MODE_TX_RX;
  948.   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  949.   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  950.   if (HAL_UART_Init(&huart1) != HAL_OK)
  951.   {
  952.     Error_Handler();
  953.   }
  954.   /* USER CODE BEGIN USART1_Init 2 */
  955.  
  956.   /* USER CODE END USART1_Init 2 */
  957. }
  958.  
  959. /**
  960.  * @brief USART2 Initialization Function
  961.  * @param None
  962.  * @retval None
  963.  */
  964. static void MX_USART2_UART_Init(void)
  965. {
  966.  
  967.   /* USER CODE BEGIN USART2_Init 0 */
  968.  
  969.   /* USER CODE END USART2_Init 0 */
  970.  
  971.   /* USER CODE BEGIN USART2_Init 1 */
  972.  
  973.   /* USER CODE END USART2_Init 1 */
  974.   huart2.Instance = USART2;
  975.   huart2.Init.BaudRate = 115200;
  976.   huart2.Init.WordLength = UART_WORDLENGTH_8B;
  977.   huart2.Init.StopBits = UART_STOPBITS_1;
  978.   huart2.Init.Parity = UART_PARITY_NONE;
  979.   huart2.Init.Mode = UART_MODE_TX_RX;
  980.   huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  981.   huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  982.   if (HAL_UART_Init(&huart2) != HAL_OK)
  983.   {
  984.     Error_Handler();
  985.   }
  986.   /* USER CODE BEGIN USART2_Init 2 */
  987.  
  988.   /* USER CODE END USART2_Init 2 */
  989. }
  990.  
  991. /**
  992.  * @brief USART3 Initialization Function
  993.  * @param None
  994.  * @retval None
  995.  */
  996. static void MX_USART3_UART_Init(void)
  997. {
  998.  
  999.   /* USER CODE BEGIN USART3_Init 0 */
  1000.  
  1001.   /* USER CODE END USART3_Init 0 */
  1002.  
  1003.   /* USER CODE BEGIN USART3_Init 1 */
  1004.  
  1005.   /* USER CODE END USART3_Init 1 */
  1006.   huart3.Instance = USART3;
  1007.   huart3.Init.BaudRate = 19200;
  1008.   huart3.Init.WordLength = UART_WORDLENGTH_8B;
  1009.   huart3.Init.StopBits = UART_STOPBITS_1;
  1010.   huart3.Init.Parity = UART_PARITY_NONE;
  1011.   huart3.Init.Mode = UART_MODE_TX_RX;
  1012.   huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  1013.   huart3.Init.OverSampling = UART_OVERSAMPLING_16;
  1014.   if (HAL_UART_Init(&huart3) != HAL_OK)
  1015.   {
  1016.     Error_Handler();
  1017.   }
  1018.   /* USER CODE BEGIN USART3_Init 2 */
  1019.  
  1020.   /* USER CODE END USART3_Init 2 */
  1021. }
  1022.  
  1023. /**
  1024.  * @brief GPIO Initialization Function
  1025.  * @param None
  1026.  * @retval None
  1027.  */
  1028. static void MX_GPIO_Init(void)
  1029. {
  1030.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  1031.  
  1032.   /* GPIO Ports Clock Enable */
  1033.   __HAL_RCC_GPIOH_CLK_ENABLE();
  1034.   __HAL_RCC_GPIOA_CLK_ENABLE();
  1035.   __HAL_RCC_GPIOC_CLK_ENABLE();
  1036.   __HAL_RCC_GPIOB_CLK_ENABLE();
  1037.  
  1038.   /*Configure GPIO pin Output Level */
  1039.   HAL_GPIO_WritePin(GPIOA, SPI_NSS1_Pin | BT_BUTTON_Pin | BT_RESET_Pin, GPIO_PIN_SET);
  1040.  
  1041.   /*Configure GPIO pin Output Level */
  1042.   HAL_GPIO_WritePin(SPI_CD_GPIO_Port, SPI_CD_Pin, GPIO_PIN_RESET);
  1043.  
  1044.   /*Configure GPIO pin Output Level */
  1045.   HAL_GPIO_WritePin(GPIOC, SPI_RESET_Pin | POWER_LATCH_Pin | USB_PWR_Pin, GPIO_PIN_RESET);
  1046.  
  1047.   /*Configure GPIO pin Output Level */
  1048.   HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_SET);
  1049.  
  1050.   /*Configure GPIO pins : SPI_NSS1_Pin SPI_CD_Pin */
  1051.   GPIO_InitStruct.Pin = SPI_NSS1_Pin | SPI_CD_Pin;
  1052.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  1053.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  1054.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  1055.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  1056.  
  1057.   /*Configure GPIO pins : SPI_RESET_Pin SPI_NSS2_Pin POWER_LATCH_Pin USB_PWR_Pin */
  1058.   GPIO_InitStruct.Pin = SPI_RESET_Pin | SPI_NSS2_Pin | POWER_LATCH_Pin | USB_PWR_Pin;
  1059.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  1060.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  1061.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  1062.   HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  1063.  
  1064.   /*Configure GPIO pins : BT_STATE_Pin SW1_PUSH_Pin SW2_PUSH_Pin */
  1065.   GPIO_InitStruct.Pin = BT_STATE_Pin | SW1_PUSH_Pin | SW2_PUSH_Pin;
  1066.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  1067.   GPIO_InitStruct.Pull = GPIO_PULLUP;
  1068.   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  1069.  
  1070.   /*Configure GPIO pin : IGNITION_Pin */
  1071.   GPIO_InitStruct.Pin = IGNITION_Pin;
  1072.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  1073.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  1074.   HAL_GPIO_Init(IGNITION_GPIO_Port, &GPIO_InitStruct);
  1075.  
  1076.   /*Configure GPIO pin : BT_BUTTON_Pin */
  1077.   GPIO_InitStruct.Pin = BT_BUTTON_Pin;
  1078.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  1079.   GPIO_InitStruct.Pull = GPIO_PULLUP;
  1080.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  1081.   HAL_GPIO_Init(BT_BUTTON_GPIO_Port, &GPIO_InitStruct);
  1082.  
  1083.   /*Configure GPIO pin : BT_RESET_Pin */
  1084.   GPIO_InitStruct.Pin = BT_RESET_Pin;
  1085.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  1086.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  1087.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  1088.   HAL_GPIO_Init(BT_RESET_GPIO_Port, &GPIO_InitStruct);
  1089. }
  1090.  
  1091. /* USER CODE BEGIN 4 */
  1092.  
  1093. /* USER CODE END 4 */
  1094.  
  1095. /**
  1096.  * @brief  This function is executed in case of error occurrence.
  1097.  * @retval None
  1098.  */
  1099. void Error_Handler(void)
  1100. {
  1101.   /* USER CODE BEGIN Error_Handler_Debug */
  1102.   /* User can add his own implementation to report the HAL error return state */
  1103.  
  1104.   /* USER CODE END Error_Handler_Debug */
  1105. }
  1106.  
  1107. #ifdef USE_FULL_ASSERT
  1108. /**
  1109.  * @brief  Reports the name of the source file and the source line number
  1110.  *         where the assert_param error has occurred.
  1111.  * @param  file: pointer to the source file name
  1112.  * @param  line: assert_param error line source number
  1113.  * @retval None
  1114.  */
  1115. void assert_failed(uint8_t *file, uint32_t line)
  1116. {
  1117.   /* USER CODE BEGIN 6 */
  1118.   /* User can add his own implementation to report the file name and line number,
  1119.      tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  1120.   /* USER CODE END 6 */
  1121. }
  1122. #endif /* USE_FULL_ASSERT */
  1123.