Subversion Repositories canSerial

Rev

Rev 3 | 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) 2022 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 "display.h"
  26.  
  27. #include "string.h"
  28. #include "base64.h"
  29. #include "libSerial/serial.H"
  30. #include "libSerial/serialUtils.H"
  31. #include "libSmallPrintf/small_printf.h"
  32.  
  33. /* USER CODE END Includes */
  34.  
  35. /* Private typedef -----------------------------------------------------------*/
  36. /* USER CODE BEGIN PTD */
  37.  
  38. typedef enum
  39. {
  40.   FAIL,
  41.   REJECT,
  42.   ACCEPT,
  43.   COMPLETE
  44. } appendStatus;
  45.  
  46. typedef struct
  47. {
  48.   uint8_t payloadBuffer[233];
  49.   uint32_t payloadId;
  50.   uint8_t payloadRemaining;  // number of bytes remaining
  51.   uint8_t payloadTotal;      // number total number of bytes
  52.   uint8_t payloadOffset;     // byte offset
  53.   uint8_t payloadNextSeq;    // next sequence frame expected
  54.   uint32_t payloadTimestamp; // timestamp of reception
  55.   appendStatus status;
  56. } contextType;
  57.  
  58. /* USER CODE END PTD */
  59.  
  60. /* Private define ------------------------------------------------------------*/
  61. /* USER CODE BEGIN PD */
  62. /* USER CODE END PD */
  63.  
  64. /* Private macro -------------------------------------------------------------*/
  65. /* USER CODE BEGIN PM */
  66. #define False (0)
  67. #define True (1)
  68. /* USER CODE END PM */
  69.  
  70. /* Private variables ---------------------------------------------------------*/
  71. CAN_HandleTypeDef hcan;
  72.  
  73. SPI_HandleTypeDef hspi1;
  74.  
  75. UART_HandleTypeDef huart1;
  76.  
  77. /* USER CODE BEGIN PV */
  78.  
  79. /* USER CODE END PV */
  80.  
  81. /* Private function prototypes -----------------------------------------------*/
  82. void SystemClock_Config(void);
  83. static void MX_GPIO_Init(void);
  84. static void MX_CAN_Init(void);
  85. static void MX_USART1_UART_Init(void);
  86. static void MX_SPI1_Init(void);
  87. /* USER CODE BEGIN PFP */
  88.  
  89. /* USER CODE END PFP */
  90.  
  91. /* Private user code ---------------------------------------------------------*/
  92. /* USER CODE BEGIN 0 */
  93.  
  94. #define CONTEXTS 6
  95. contextType contexts[CONTEXTS];
  96.  
  97. CAN_TxHeaderTypeDef TxHeader;
  98. CAN_RxHeaderTypeDef RxHeader;
  99.  
  100. uint8_t TxData[8];
  101. uint8_t RxData[8];
  102.  
  103. // Storage for the data
  104.  
  105. uint32_t TxMailbox;
  106.  
  107. char const version[] = "$PDGY,Mike_James_Converter_#00001_Mode:15\r\n";
  108. char const keepawake[] = "$PDGY,000000,1,,4,%ld.%03ld,,,\r\n";
  109.  
  110. // Allocation of serial buffer sizes and storage
  111. #define TX_BUFFER_SIZE 512
  112. #define RX_BUFFER_SIZE 16
  113. uint8_t tx_buffer[TX_BUFFER_SIZE];
  114. uint8_t rx_buffer[RX_BUFFER_SIZE];
  115.  
  116. // reset a search context
  117. void resetContext(contextType *c)
  118. {
  119.   c->payloadRemaining = 0; // number of bytes remaining
  120.   c->payloadTotal = 0;     // number total number of bytes
  121.   c->payloadOffset = 0;
  122.   c->payloadNextSeq = 0;
  123.   c->payloadTimestamp = 0;
  124.   c->status = FAIL;
  125.   c->payloadId = 0;
  126. }
  127.  
  128. uint8_t singleFrame(uint32_t pgn)
  129. {
  130.  
  131.   switch (pgn)
  132.   {
  133.   case 129029:
  134.   case 129038:
  135.   case 126996:
  136.   case 127489:
  137.     return False;
  138.   default:
  139.     break;
  140.   }
  141.  
  142.   if (pgn >= 130816 && pgn <= 131071)
  143.     return False;
  144.   if (pgn >= 65536 && pgn <= 126975)
  145.     return False;
  146.   return True;
  147. }
  148.  
  149. // called from CAN frame callback
  150. appendStatus append(contextType *c, CAN_RxHeaderTypeDef *packet)
  151. {
  152.   uint32_t extId = RxHeader.ExtId;
  153.  
  154.   if (c->payloadId != 0 && c->payloadId != extId)
  155.     return REJECT;
  156.   uint8_t newId = c->payloadId == 0; // set a flag if this is a newly discovered frame
  157.   c->payloadId = extId;
  158.  
  159.   uint32_t pgn = (c->payloadId >> 8) & ((1 << 18) - 1);
  160.   uint8_t pf = (pgn >> 8) & 0xFF;
  161.  
  162.   if (pf < 240)
  163.   {
  164.     // process PS if in PDU1 , address is low byte
  165.     pgn = pgn & 0x3FF00;
  166.   }
  167.  
  168.   uint8_t packetLen = RxHeader.DLC;
  169.  
  170.   if (singleFrame(pgn))
  171.   {
  172.     c->payloadTimestamp = HAL_GetTick();
  173.     memcpy(c->payloadBuffer, RxData, packetLen);
  174.     c->payloadRemaining = 0;
  175.     c->payloadTotal = packetLen;
  176.     c->status = COMPLETE;
  177.     return c->status; // successfully filled frame
  178.   }
  179.   else
  180.   {
  181.     // sort out fastpacket new ID
  182.     if (newId)
  183.     {
  184.       if ((RxData[0] & 0x1f) != 0)
  185.       {
  186.         resetContext(c);
  187.         return FAIL;
  188.       }
  189.       c->payloadTimestamp = HAL_GetTick();
  190.       c->payloadNextSeq = RxData[0] + 1;
  191.       c->payloadId = extId;
  192.       c->payloadRemaining = RxData[1];
  193.       c->payloadTotal = RxData[1];
  194.       // no data , return
  195.       if (c->payloadTotal == 0)
  196.       {
  197.         resetContext(c);
  198.         return FAIL;
  199.       }
  200.       uint8_t numBytes = packetLen - 2;
  201.       memcpy(c->payloadBuffer, RxData + 2, numBytes);
  202.  
  203.       // CAN frame can be longer than remaining bytes, do not make payloadRemaining wrap around !
  204.       if (numBytes < c->payloadRemaining)
  205.         c->payloadRemaining -= numBytes;
  206.       else
  207.         c->payloadRemaining = 0;
  208.       c->payloadOffset = numBytes;
  209.     }
  210.     else
  211.     {
  212.       if (RxData[0] != c->payloadNextSeq)
  213.       {
  214.         resetContext(c);
  215.         return FAIL;
  216.       }
  217.       // predict next payload sequence
  218.       c->payloadNextSeq++;
  219.       uint8_t numBytes = packetLen - 1;
  220.       memcpy(c->payloadBuffer + c->payloadOffset, RxData + 1, numBytes);
  221.       c->payloadRemaining -= numBytes;
  222.       c->payloadOffset += numBytes;
  223.     }
  224.   }
  225.  
  226.   appendStatus stat = (c->payloadRemaining != 0) ? ACCEPT : COMPLETE;
  227.   c->status = stat;
  228.   return stat;
  229. }
  230.  
  231. void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
  232. {
  233.   HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
  234.   HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData);
  235.  
  236.   int i;
  237.   for (i = 0; i < CONTEXTS; ++i)
  238.   {
  239.     contextType *ctx = &contexts[i];
  240.     appendStatus stat = append(ctx, &RxHeader);
  241.     if (stat == ACCEPT || stat == COMPLETE)
  242.       break; // accepted data, stop loop
  243.   }
  244. }
  245.  
  246. void heartBeat()
  247. {
  248.   char lineBuff[80];
  249.   uint32_t timestamp = HAL_GetTick();
  250.   size_t pos = small_sprintf(lineBuff, keepawake,
  251.                              timestamp / 1000, // seconds
  252.                              timestamp % 1000  // milliseconds
  253.   );
  254.   HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
  255.   if (pos < SerialTransmitSpace(&uc1))
  256.   {
  257.     __disable_irq();
  258.     sendString(&uc1, (char *)lineBuff, pos);
  259.     __enable_irq();
  260.   }
  261. }
  262.  
  263. // utility function to set up the filter mask
  264. void CAN_FilterMaskEXT(CAN_FilterTypeDef *filter_, uint32_t id_, uint32_t mask_)
  265. {
  266.   filter_->FilterIdHigh = id_ >> 13;
  267.   filter_->FilterIdLow = ((id_ & 0x1FFF) << 3) | CAN_ID_EXT;
  268.   filter_->FilterMaskIdHigh = mask_ >> 13;
  269.   filter_->FilterMaskIdLow = ((mask_ & 0x1FFF) << 3) | CAN_ID_EXT;
  270. }
  271.  
  272. void processCmd(char *buff, int len)
  273. {
  274.   buff[len] = 0; // terminate in case of error
  275.   char lineBuff[100];
  276.   int pos = small_sprintf(lineBuff, "$PDGY,ACK,%s\r\n", buff);
  277.   if (pos < SerialTransmitSpace(&uc1))
  278.   {
  279.     __disable_irq();
  280.     sendString(&uc1, (char *)lineBuff, pos);
  281.     __enable_irq();
  282.   }
  283. }
  284.  
  285. /* USER CODE END 0 */
  286.  
  287. /**
  288.  * @brief  The application entry point.
  289.  * @retval int
  290.  */
  291. int main(void)
  292. {
  293.   /* USER CODE BEGIN 1 */
  294.  
  295.   /* USER CODE END 1 */
  296.  
  297.   /* MCU Configuration--------------------------------------------------------*/
  298.  
  299.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  300.   HAL_Init();
  301.  
  302.   /* USER CODE BEGIN Init */
  303.  
  304.   /* USER CODE END Init */
  305.  
  306.   /* Configure the system clock */
  307.   SystemClock_Config();
  308.  
  309.   /* USER CODE BEGIN SysInit */
  310.   cc_init();
  311.  
  312.   /* USER CODE END SysInit */
  313.  
  314.   /* Initialize all configured peripherals */
  315.   MX_GPIO_Init();
  316.   MX_CAN_Init();
  317.   MX_USART1_UART_Init();
  318.   MX_SPI1_Init();
  319.   /* USER CODE BEGIN 2 */
  320.  
  321.   HAL_CAN_Start(&hcan);
  322.  
  323.   init_usart_ctl(&uc1, &huart1,
  324.                  tx_buffer,
  325.                  rx_buffer,
  326.                  TX_BUFFER_SIZE,
  327.                  RX_BUFFER_SIZE);
  328.  
  329.   EnableSerialRxInterrupt(&uc1);
  330.  
  331.   // Activate the notification
  332.   HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
  333.  
  334.   // send out a version string on the serial port
  335.   sendString(&uc1, (char *)version, sizeof(version));
  336.  
  337.   uint32_t sendTime = HAL_GetTick() + 1000;
  338.   char cmdBuff[100];
  339.  
  340.   // serial utils library command editor
  341.   editBuffer cmdEdit;
  342.  
  343.   initReadLine(&cmdEdit, cmdBuff, 100, READLINES_CR);
  344.  
  345.   for (int i = 0; i < CONTEXTS; ++i)
  346.     resetContext(&contexts[i]);
  347.  
  348.   /* USER CODE END 2 */
  349.  
  350.   /* Infinite loop */
  351.   /* USER CODE BEGIN WHILE */
  352.   while (1)
  353.   {
  354.     /* USER CODE END WHILE */
  355.  
  356.     /* USER CODE BEGIN 3 */
  357.  
  358.     editBufferReturn ret = readLine(&uc1, &cmdEdit);
  359.  
  360.     if (ret == EDIT_CR)
  361.     {
  362.       processCmd(cmdBuff, charCount(&cmdEdit));
  363.       resetInput(&cmdEdit);
  364.     }
  365.  
  366.     if (HAL_GetTick() > sendTime)
  367.     {
  368.       sendTime += 1000;
  369.       heartBeat();
  370.       cc_display(2);
  371.     }
  372.  
  373.     for (int i = 0; i < CONTEXTS; ++i)
  374.     {
  375.       contextType *ctx = &contexts[i];
  376.       /// check for too old
  377.       //   if (ctx->status == ACCEPT && ctx->payloadTimestamp < old)
  378.       //   {
  379.       //     resetContext(ctx);
  380.       //     continue;
  381.       //   }
  382.  
  383.       if (ctx->status == COMPLETE)
  384.       {
  385.         __disable_irq();
  386.  
  387.         uint8_t prio = (ctx->payloadId >> 26) & 0x7;
  388.         uint8_t src = ctx->payloadId & 0xFF;
  389.         uint8_t dst = 255;
  390.         // mask out the PGN field as 18 bits.
  391.         uint32_t pgn = (ctx->payloadId >> 8) & ((1 << 18) - 1);
  392.         uint8_t pf = (pgn >> 8) & 0xFF;
  393.  
  394.         if (pf < 240)
  395.         {
  396.           // process PS if in PDU1 , address is low byte
  397.           dst = pgn & 0xFF;
  398.           pgn = pgn & 0x3FF00;
  399.         }
  400.  
  401.         char lineBuff[300];
  402.         size_t pos = small_sprintf(lineBuff, "!PDGY,%ld,%d,%d,%d,%ld.%03ld,",
  403.                                    pgn,  // PGN
  404.                                    prio, // priority
  405.                                    src,  // source address
  406.                                    dst,  // destination address
  407.  
  408.                                    ctx->payloadTimestamp / 1000, // milliseconds
  409.                                    ctx->payloadTimestamp % 1000);
  410.  
  411.         size_t base64_len;
  412.         base64_encode(ctx->payloadBuffer,
  413.                       ctx->payloadTotal,
  414.                       lineBuff + pos,
  415.                       &base64_len);
  416.  
  417.         pos += base64_len;
  418.         lineBuff[pos++] = '\r';
  419.         lineBuff[pos++] = '\n';
  420.         __enable_irq();
  421.  
  422.         // skip sending if this would overrun the buffer
  423.         if (pos < SerialTransmitSpace(&uc1))
  424.           sendString(&uc1, lineBuff, pos);
  425.         __disable_irq();
  426.  
  427.         resetContext(ctx);
  428.         __enable_irq();
  429.       }
  430.     }
  431.   }
  432.   /* USER CODE END 3 */
  433. }
  434.  
  435. /**
  436.  * @brief System Clock Configuration
  437.  * @retval None
  438.  */
  439. void SystemClock_Config(void)
  440. {
  441.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  442.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  443.  
  444.   /** Initializes the RCC Oscillators according to the specified parameters
  445.    * in the RCC_OscInitTypeDef structure.
  446.    */
  447.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  448.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  449.   RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  450.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  451.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  452.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
  453.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  454.   {
  455.     Error_Handler();
  456.   }
  457.  
  458.   /** Initializes the CPU, AHB and APB buses clocks
  459.    */
  460.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  461.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  462.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  463.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  464.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  465.  
  466.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  467.   {
  468.     Error_Handler();
  469.   }
  470. }
  471.  
  472. /**
  473.  * @brief CAN Initialization Function
  474.  * @param None
  475.  * @retval None
  476.  */
  477. static void MX_CAN_Init(void)
  478. {
  479.  
  480.   /* USER CODE BEGIN CAN_Init 0 */
  481.  
  482.   /* USER CODE END CAN_Init 0 */
  483.  
  484.   /* USER CODE BEGIN CAN_Init 1 */
  485.  
  486.   /* USER CODE END CAN_Init 1 */
  487.   hcan.Instance = CAN1;
  488.   hcan.Init.Prescaler = 16;
  489.   hcan.Init.Mode = CAN_MODE_NORMAL;
  490.   hcan.Init.SyncJumpWidth = CAN_SJW_2TQ;
  491.   hcan.Init.TimeSeg1 = CAN_BS1_3TQ;
  492.   hcan.Init.TimeSeg2 = CAN_BS2_4TQ;
  493.   hcan.Init.TimeTriggeredMode = DISABLE;
  494.   hcan.Init.AutoBusOff = DISABLE;
  495.   hcan.Init.AutoWakeUp = DISABLE;
  496.   hcan.Init.AutoRetransmission = ENABLE;
  497.   hcan.Init.ReceiveFifoLocked = DISABLE;
  498.   hcan.Init.TransmitFifoPriority = DISABLE;
  499.   if (HAL_CAN_Init(&hcan) != HAL_OK)
  500.   {
  501.     Error_Handler();
  502.   }
  503.   /* USER CODE BEGIN CAN_Init 2 */
  504.   /* USER CODE BEGIN CAN_Init 2 */
  505.  
  506.   // allow absolutely everything into filter
  507.   CAN_FilterTypeDef filterConfig;
  508.   filterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  509.   filterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  510.   filterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
  511.   filterConfig.FilterActivation = CAN_FILTER_ENABLE;
  512.   filterConfig.FilterBank = 0;
  513.  
  514.   CAN_FilterMaskEXT(&filterConfig, 0, 0);
  515.  
  516.   HAL_CAN_ConfigFilter(&hcan, &filterConfig);
  517.  
  518.   /* USER CODE END CAN_Init 2 */
  519. }
  520.  
  521. /**
  522.  * @brief SPI1 Initialization Function
  523.  * @param None
  524.  * @retval None
  525.  */
  526. static void MX_SPI1_Init(void)
  527. {
  528.  
  529.   /* USER CODE BEGIN SPI1_Init 0 */
  530.  
  531.   /* USER CODE END SPI1_Init 0 */
  532.  
  533.   /* USER CODE BEGIN SPI1_Init 1 */
  534.  
  535.   /* USER CODE END SPI1_Init 1 */
  536.   /* SPI1 parameter configuration*/
  537.   hspi1.Instance = SPI1;
  538.   hspi1.Init.Mode = SPI_MODE_MASTER;
  539.   hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  540.   hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  541.   hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  542.   hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  543.   hspi1.Init.NSS = SPI_NSS_SOFT;
  544.   hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
  545.   hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  546.   hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  547.   hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  548.   hspi1.Init.CRCPolynomial = 10;
  549.   if (HAL_SPI_Init(&hspi1) != HAL_OK)
  550.   {
  551.     Error_Handler();
  552.   }
  553.   /* USER CODE BEGIN SPI1_Init 2 */
  554.  
  555.   /* USER CODE END SPI1_Init 2 */
  556. }
  557.  
  558. /**
  559.  * @brief USART1 Initialization Function
  560.  * @param None
  561.  * @retval None
  562.  */
  563. static void MX_USART1_UART_Init(void)
  564. {
  565.  
  566.   /* USER CODE BEGIN USART1_Init 0 */
  567.  
  568.   /* USER CODE END USART1_Init 0 */
  569.  
  570.   /* USER CODE BEGIN USART1_Init 1 */
  571.  
  572.   /* USER CODE END USART1_Init 1 */
  573.   huart1.Instance = USART1;
  574.   huart1.Init.BaudRate = 460800;
  575.   huart1.Init.WordLength = UART_WORDLENGTH_8B;
  576.   huart1.Init.StopBits = UART_STOPBITS_1;
  577.   huart1.Init.Parity = UART_PARITY_NONE;
  578.   huart1.Init.Mode = UART_MODE_TX_RX;
  579.   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  580.   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  581.   if (HAL_UART_Init(&huart1) != HAL_OK)
  582.   {
  583.     Error_Handler();
  584.   }
  585.   /* USER CODE BEGIN USART1_Init 2 */
  586.  
  587.   /* USER CODE END USART1_Init 2 */
  588. }
  589.  
  590. /**
  591.  * @brief GPIO Initialization Function
  592.  * @param None
  593.  * @retval None
  594.  */
  595. static void MX_GPIO_Init(void)
  596. {
  597.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  598.   /* USER CODE BEGIN MX_GPIO_Init_1 */
  599.   /* USER CODE END MX_GPIO_Init_1 */
  600.  
  601.   /* GPIO Ports Clock Enable */
  602.   __HAL_RCC_GPIOC_CLK_ENABLE();
  603.   __HAL_RCC_GPIOD_CLK_ENABLE();
  604.   __HAL_RCC_GPIOA_CLK_ENABLE();
  605.  
  606.   /*Configure GPIO pin Output Level */
  607.   HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
  608.  
  609.   /*Configure GPIO pin Output Level */
  610.   HAL_GPIO_WritePin(GPIOA, SPI1_CS_Pin | SPI1_CD_Pin | SPI1_RESET_Pin, GPIO_PIN_RESET);
  611.  
  612.   /*Configure GPIO pin : LED_Pin */
  613.   GPIO_InitStruct.Pin = LED_Pin;
  614.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  615.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  616.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  617.   HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);
  618.  
  619.   /*Configure GPIO pins : SPI1_CS_Pin SPI1_CD_Pin SPI1_RESET_Pin */
  620.   GPIO_InitStruct.Pin = SPI1_CS_Pin | SPI1_CD_Pin | SPI1_RESET_Pin;
  621.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  622.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  623.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  624.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  625.  
  626.   /* USER CODE BEGIN MX_GPIO_Init_2 */
  627.   /* USER CODE END MX_GPIO_Init_2 */
  628. }
  629.  
  630. /* USER CODE BEGIN 4 */
  631.  
  632. /* USER CODE END 4 */
  633.  
  634. /**
  635.  * @brief  This function is executed in case of error occurrence.
  636.  * @retval None
  637.  */
  638. void Error_Handler(void)
  639. {
  640.   /* USER CODE BEGIN Error_Handler_Debug */
  641.   /* User can add his own implementation to report the HAL error return state */
  642.  
  643.   /* USER CODE END Error_Handler_Debug */
  644. }
  645.  
  646. #ifdef USE_FULL_ASSERT
  647. /**
  648.  * @brief  Reports the name of the source file and the source line number
  649.  *         where the assert_param error has occurred.
  650.  * @param  file: pointer to the source file name
  651.  * @param  line: assert_param error line source number
  652.  * @retval None
  653.  */
  654. void assert_failed(uint8_t *file, uint32_t line)
  655. {
  656.   /* USER CODE BEGIN 6 */
  657.   /* User can add his own implementation to report the file name and line number,
  658.      tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  659.   /* USER CODE END 6 */
  660. }
  661. #endif /* USE_FULL_ASSERT */
  662.