Subversion Repositories canSerial

Rev

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