source: trunk/firmware/CubeMX/Src/main.c@ 1

Last change on this file since 1 was 1, checked in by f.jahn, 3 years ago
File size: 117.6 KB
Line 
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#include "adc.h"
23#include "crc.h"
24#include "dac.h"
25#include "dma.h"
26#include "iwdg.h"
27#include "tim.h"
28#include "usart.h"
29#include "gpio.h"
30
31/* Private includes ----------------------------------------------------------*/
32/* USER CODE BEGIN Includes */
33
34#include <stdio.h>
35#include <math.h>
36
37#include "log.h"
38#include "sysdata.h"
39#include "modbus.h"
40#include "SEGGER_RTT.h"
41#include "feeprom.h"
42#include "tast.h"
43#include "string.h"
44#include "precharge.h"
45
46/* USER CODE END Includes */
47
48/* Private typedef -----------------------------------------------------------*/
49/* USER CODE BEGIN PTD */
50
51typedef enum LOGIC {LOGIC_POSITIV, LOGIC_NEGATIV} logic_t;
52
53/* USER CODE END PTD */
54
55/* Private define ------------------------------------------------------------*/
56/* USER CODE BEGIN PD */
57
58#define TAG "MAIN"
59
60/* USER CODE END PD */
61
62/* Private macro -------------------------------------------------------------*/
63/* USER CODE BEGIN PM */
64
65/* USER CODE END PM */
66
67/* Private variables ---------------------------------------------------------*/
68
69/* USER CODE BEGIN PV */
70
71#ifdef USE_RAM_FUNC
72uint8_t vectorTableInRAM[192] __attribute__ ((aligned (256)));
73#endif
74
75 modbus_t modbusData;
76 sys_data_t sys_data;
77volatile uint16_t ADC_values[ADC_CHANNELS];
78volatile int32_t rawMOSFETsVoltageDrop;
79volatile int32_t rawContactVoltageDropPlus;
80volatile int32_t rawContactVoltageDropMinus;
81 int command_parser_is_enabled;
82volatile int overcurrent_shutdown_is_active = 0;
83volatile int overload_shutdown_is_active = 0;
84 int low_bat_shutdown_is_active = 0;
85 int temperature_shutdown_is_active = 0;
86 int mosfets_voltagedrop_shutdown_is_active = 0;
87 void (*MOSFETS_Management)(void); // Function pointer that is called in ADC interrupt, depending on the states of LVP&OVP
88 void (*LVP_OVP[LVP_OVP_EVENT_NUM])(void); // Function pointers array that contains "what to do" functions for every combination of LVP&OVP
89 void (*AUTO_Mode)(uint32_t, int); // Function pointer that contains function that is executed when gSwitch is in AUTO mode (depends on DIP switches)
90 logic_t LVP_OVP_logic = LOGIC_NEGATIV; // Default logic is negative
91 int manual_overdrive_is_enabled;
92 uint32_t swdioConnection = UINT32_MAX; // Special variable that contains non-zero number, if SWD-debugger is connected to target
93 void (*InternalGreenLED_Management)(void); // Function pointer that controls Green LED
94 void (*InternalBlueLED_Management)(void); // Function pointer that controls Blue LED
95 void (*InternalRedLED_Management)(void); // Function pointer that controls internal Red LED
96 void (*ExternalGreenLED_Management)(void); // Function pointer that controls external Green LED, which is located inside of the button
97 void (*ExternalRedLED_Management)(void); // Function pointer that controls external Red LED, which is located inside of the button
98 int RS485ActiveMode = 1; // RS485 transsiver is active
99 int auto_recover_from_temp_shutdown_is_enabled; // Automatic reconnect after overtemperature disconnect
100 //uint16_t i_samples[I_RMS_SAMPLES_COUNT] __attribute__((aligned(4)));
101 //uint16_t d_samples[I_RMS_SAMPLES_COUNT];
102 //uint16_t u_samples[I_RMS_SAMPLES_COUNT];
103//volatile int32_t i_samples_counter = 0;
104 uint16_t savedLockKey;
105volatile uint32_t overcurrent_shutdown_time = 0xFFFFE0C0;
106volatile uint32_t overload_shutdown_time = 0xFFFFE0C0;
107 void (*Callibration)(void);
108 //void (*Callibration_2)(void);
109 //void (*ActuelKeyManagement)(void);
110 uint16_t keyAccepted = 0;
111 uint16_t savedLockKey;
112 int statDataChanged = 0;
113volatile uint32_t maxIntegral = UINT32_MAX;
114 void (*InrushCurrentManagement)(void);
115
116//#include "raccess.c"
117extern accessMode_t accessModeTable[ MAX_ADRESS+1 ];
118
119/* USER CODE END PV */
120
121/* Private function prototypes -----------------------------------------------*/
122void SystemClock_Config(void);
123/* USER CODE BEGIN PFP */
124void SYSDATA_Init(void);
125void StartUpSequence(void);
126#ifdef USE_RAM_FUNC
127void CopyingVectorTableToRAM(void);
128#endif
129void DoNothing();
130void OpenBothMOSFETSVeryFast(void);
131void CloseBothMOSFETSVeryFast(void);
132void OVP_not_present__LVP_not_present(void);
133void OVP_present__LVP_not_present(void);
134void OVP_not_present__LVP_present(void);
135void OVP_present__LVP_present(void);
136void ADC_OVP_not_present__LVP_not_present(void);
137void ADC_OVP_present__LVP_not_present(void);
138void ADC_OVP_not_present__LVP_present(void);
139void ADC_OVP_present__LVP_present(void);
140void ShowSlaveAddressOnLED(uint16_t address, GPIO_TypeDef *port, uint16_t pin);
141inline __attribute__((always_inline)) void MODBUS_Management(void);
142void DEBUG_print(uint32_t ticks);
143void HeavyCalculations(uint32_t ticks);
144void Keys_Management(void);
145void AUTO_LVP_OVP_Management(uint32_t ticks, int reset);
146void AUTO_LVP_Management(uint32_t ticks, int reset);
147void AUTO_OVP_Management(uint32_t ticks, int reset);
148void DIP_Switches(void);
149void OVP_ignored__LVP_not_present(void);
150void OVP_ignored__LVP_present(void);
151void ADC_OVP_ignored__LVP_not_present(void);
152void ADC_OVP_ignored__LVP_present(void);
153void OVP_not_present__LVP_ignored(void);
154void OVP_present__LVP_ignored(void);
155void ADC_OVP_not_present__LVP_ignored(void);
156void ADC_OVP_present__LVP_ignored(void);
157void ADC_Close_Both_MOSFETs(void);
158void ADC_Open_Both_MOSFETs(void);
159void SystemClock_Decrease(void);
160void EnterPowerSavingMode(void);
161void ExitPowerSavingMode(void);
162void StartOffMode(int reset);
163void LEDs_Management(void);
164void BlueLEDShortBlinking(void);
165void TurnBlueLEDOn(void);
166void TurnExternalGreenLEDOn(void);
167void TurnExternalGreenLEDOff(void);
168//void ExternalRedLEDShortBlinking(void);
169//void ExternalRedLEDVeryShortBlinking(void);
170void ExternalGreenLEDShortBlinking(void);
171void OVP_Management_NoAutoreconnect(uint32_t new_time, int reset);
172void OVP_present__LVP_ignored_NoAutoreconnect(void);
173void LVP_Management_NoAutoreconnect(uint32_t new_time, int reset);
174void OVP_ignored__LVP_present_NoAutoreconnect(void);
175void LVP_OVP_Management_NoAutoreconnect(uint32_t new_time, int reset);
176void ShortCutCheck(void);
177void TrueRMSCurrentCalculation(void);
178void TrueRMSCurrentOfflineCalculation(void);
179void CurrentOfflineCalculation(void);
180void CallibrateVoltageDropABMiddlePointOffset(void);
181void CallibrateControlCurrentVoltageDropOnContactBB(void);
182void CallibrateCurrentSensorZeroOffsetOnContactBB(void);
183void ABVoltageDropCalculation(void);
184inline __attribute__((always_inline)) void OpenBothMOSFETS(void);
185inline __attribute__((always_inline)) void CloseBothMOSFETS(void);
186void InrushCurrentDetected(void);
187void ExternalRedLED1ShortOnThenLongPauseBlinking(void);
188void ExternalRedLED2ShortOnThenLongPauseBlinking(void);
189void ExternalRedLED3ShortOnThenLongPauseBlinking(void);
190void ExternalRedLED4ShortOnThenLongPauseBlinking(void);
191void ExternalRedLED5ShortOnThenLongPauseBlinking(void);
192void ExternalRedLED6ShortOnThenLongPauseBlinking(void);
193void ExternalRedLED2ShortOnThen2LongOnThenLongPauseBlinking(void);
194void RS485DisableButtonManagement(uint32_t new_time);
195
196/* USER CODE END PFP */
197
198/* Private user code ---------------------------------------------------------*/
199/* USER CODE BEGIN 0 */
200
201/* USER CODE END 0 */
202
203/**
204 * @brief The application entry point.
205 * @retval int
206 */
207int main(void)
208{
209 /* USER CODE BEGIN 1 */
210#ifdef DEBUG
211 __HAL_RCC_DBGMCU_CLK_ENABLE();
212 DBG->APBFZ1 |= (DBG_APB_FZ1_DBG_TIM2_STOP | DBG_APB_FZ1_DBG_TIM6_STOP | DBG_APB_FZ1_DBG_TIM7_STOP);
213 DBG->APBFZ2 |= (DBG_APB_FZ2_DBG_TIM14_STOP | DBG_APB_FZ2_DBG_TIM15_STOP | DBG_APB_FZ2_DBG_TIM16_STOP | DBG_APB_FZ2_DBG_TIM17_STOP);
214#endif
215 command_parser_is_enabled = 1;
216 uint32_t new_time;
217 uint32_t old_time = 0;
218 //uint32_t MIN_MAX_CALCULATION_DELAY = 3000;
219 uint32_t stat_last_time_checked = 0;
220 /* USER CODE END 1 */
221
222 /* MCU Configuration--------------------------------------------------------*/
223
224 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
225 HAL_Init();
226
227 /* USER CODE BEGIN Init */
228
229 /* USER CODE END Init */
230
231 /* Configure the system clock */
232 SystemClock_Config();
233
234 /* USER CODE BEGIN SysInit */
235#define MX_IWDG_Init DoNothing // This line helps to eliminate early start of WatchDog timer and keep code reconfigurable by CubeMx
236 /* USER CODE END SysInit */
237
238 /* Initialize all configured peripherals */
239 MX_GPIO_Init();
240 MX_DMA_Init();
241 MX_ADC1_Init();
242 MX_USART1_UART_Init();
243 MX_CRC_Init();
244 MX_DAC1_Init();
245 MX_TIM17_Init();
246 MX_IWDG_Init();
247 MX_TIM16_Init();
248 MX_TIM14_Init();
249 MX_TIM7_Init();
250 MX_TIM6_Init();
251 MX_TIM2_Init();
252 MX_TIM15_Init();
253 /* USER CODE BEGIN 2 */
254#undef MX_IWDG_Init // Removing previous definition, that helped not to start a watchdog
255
256//#ifdef DEBUG
257 //RCC->APBENR1 |= RCC_APBENR1_DBGEN;
258 //DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM7_STOP | DBG_APB_FZ1_DBG_TIM2_STOP | DBG_APB_FZ1_DBG_TIM6_STOP;
259 //DBG->APBFZ2 |= DBG_APB_FZ2_DBG_TIM14_STOP | DBG_APB_FZ2_DBG_TIM16_STOP | DBG_APB_FZ2_DBG_TIM17_STOP;
260//#endif
261
262 SYSDATA_Init();
263
264 if (HAL_TIM_Base_Start(&htim2) != HAL_OK) LOG_E(TAG, "Cannot start TIMER2!");
265
266 SEGGER_RTT_printf(0, RTT_CTRL_CLEAR);
267 LOG_I(TAG, "Program started.");
268 switch(DBG->IDCODE & 0xFFF)
269 {
270 case 0x467: LOG_I(TAG, "Device ID: STM32G0B1 or STM32G0C1"); break;
271 case 0x460: LOG_I(TAG, "Device ID: STM32G071 or STM32G081"); break;
272 case 0x456: LOG_I(TAG, "Device ID: STM32G051 or STM32G061"); break;
273 case 0x466: LOG_I(TAG, "Device ID: STM32G031 or STM32G041"); break;
274 default: LOG_I(TAG, "Device ID: unknown");
275 }
276 SEGGER_RTT_printf(0, "%s: Revision number: 0x%4X\n", TAG, DBG->IDCODE>>16);
277 SEGGER_RTT_printf(0, "Free space for cofiguration in fake EEPROM: %u bytes\n", FEEPROM_ConfigFreeBytes());
278 SEGGER_RTT_printf(0, "Free space for statistics in fake EEPROM: %u bytes\n", FEEPROM_StatFreeBytes());
279 SEGGER_RTT_printf(0, "MAX_POSSIBLE_DIFF_TO_MEASURE: %u\n", MAX_POSSIBLE_DIFF_TO_MEASURE);
280 SEGGER_RTT_printf(0, "CPU Freq: %u Hz\n", HAL_RCC_GetSysClockFreq());
281
282 if (HAL_RCC_GetSysClockFreq() < 64000000)
283 {
284 LOG_E(TAG, "CPU speed is not 64MHz!");
285 LOG_E(TAG, "Trying to restart.");
286 HAL_NVIC_SystemReset();
287 }
288
289 StartUpSequence();
290
291#ifdef USE_RAM_FUNC
292 CopyingVectorTableToRAM();
293#endif
294
295 if(FEEPROM_isFirstStart())
296 {
297 LOG_W(TAG, "First start! Writing default configuration!");
298 FEEPROM_fullRestore(/*&sys_data*/);
299 FEEPROM_ResetLogData();
300 }
301
302 // Fetching configuration from FLASH
303 if (FEEPROM_readConfig(&sys_data)) LOG_E(TAG, "Cannot read configuration from FLASH memory!");
304 if (FEEPROM_ReadLogData(&sys_data)) LOG_E(TAG, "Cannot read statistcal data from FLASH memory!");
305
306 sys_data.s.startup_cnt++; // Start-up counter
307 statDataChanged = 1;
308 maxIntegral = sys_data.s.inrush_max_current_in_adc * sys_data.s.inrush_curr_integral_steps;
309 sys_data.s.copper_v_drop_adc_limit = (sys_data.s.copper_v_drop_adc * 110) / 100;
310
311 ShowSlaveAddressOnLED(sys_data.s.slave_address, LED_ERROR_GPIO_Port, LED_ERROR_Pin);
312
313 // Modbus Initialisierung
314 if (sys_data.s.parity_mode == 'e') mbInit(&modbusData, sys_data.s.baudrate, MODBUS_UART_PARITY_EVEN, &huart1, accessModeTable, &keyAccepted);
315 else if (sys_data.s.parity_mode == 'o') mbInit(&modbusData, sys_data.s.baudrate, MODBUS_UART_PARITY_ODD, &huart1, accessModeTable, &keyAccepted);
316 else mbInit(&modbusData, sys_data.s.baudrate, MODBUS_UART_PARITY_NONE, &huart1, accessModeTable, &keyAccepted);
317
318 // ADC self-calibration
319 if (HAL_ADC_Stop(&hadc1) == HAL_OK) // Stopping ADC
320 {
321 if (HAL_ADCEx_Calibration_Start (&hadc1) == HAL_OK)
322 {
323 uint32_t calibration_value = HAL_ADCEx_Calibration_GetValue(&hadc1);
324 SEGGER_RTT_printf(0, "%s%s: ADC Calibration value: %u\n", RTT_CTRL_TEXT_BRIGHT_GREEN,TAG, calibration_value | 0x3F);
325 }
326 else LOG_E(TAG, "ADC calibration error!");
327 }
328 else LOG_E(TAG, "Cannot stop ADC!");
329
330 // DAC calibration
331 uint32_t calib_1 = HAL_DACEx_GetTrimOffset(&hdac1, MOSFET_CHANNEL_A);
332 uint32_t calib_2 = HAL_DACEx_GetTrimOffset(&hdac1, MOSFET_CHANNEL_B);
333 SEGGER_RTT_printf(0, "%s: DAC Calibration value for channel 1: %u\n", TAG, calib_1);
334 SEGGER_RTT_printf(0, "%s: DAC Calibration value for channel 2: %u\n", TAG, calib_2);
335
336 // Before ADC start we must initialize our MOSFETs management function pointer
337 StartOffMode(1);
338
339 //MOSFETS_Management = &ADC_Open_Both_MOSFETs; // & is optional, but it clearly refers to pointer initialization
340 //sys_data.s.user_button_mode = SWITCH_OFF; // Initial state of the switch
341 if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_values, ADC_CHANNELS) != HAL_OK) LOG_E(TAG, "Cannot start ADC in DMA mode!");
342
343 DMA1_Channel1->CCR &= ~DMA_CCR_HTIE; // Disabling Half-Transfer interrupt, because we don't need it
344
345 // Starting DAC
346 HAL_DAC_Start(&hdac1, MOSFET_CHANNEL_A);
347 HAL_DAC_Start(&hdac1, MOSFET_CHANNEL_B);
348 // Setting new values
349 HAL_DAC_SetValue(&hdac1, MOSFET_CHANNEL_A, DAC_ALIGN_12B_R, DAC_0V);
350 HAL_DAC_SetValue(&hdac1, MOSFET_CHANNEL_B, DAC_ALIGN_12B_R, DAC_0V);
351
352 /* USER CODE END 2 */
353
354 /* Infinite loop */
355 /* USER CODE BEGIN WHILE */
356
357 DIP_Switches();
358
359 // Initializing independant watchdog timer (cannot be disabled)
360 //MX_IWDG_Init();
361
362 // Due to the fact, that gSwitch always start in OFF state, after start-up
363 // we can enter low power mode, because nothing dangerous happens in OFF mode
364 //EnterPowerSavingMode();
365
366 InternalGreenLED_Management = &DoNothing;
367 InternalBlueLED_Management = &BlueLEDShortBlinking;
368 InternalRedLED_Management = &DoNothing;
369 ExternalGreenLED_Management = &DoNothing;
370 ExternalRedLED_Management = &DoNothing;
371 Callibration = &DoNothing;
372 InrushCurrentManagement = &InrushCurrentDetected;
373
374 while (1) // Main loop
375 {
376 ABVoltageDropCalculation();
377
378 //TIM2->CNT = 0;
379 //CurrentOfflineCalculation();
380 //TrueRMSCurrentOfflineCalculation(); // Max execution time is
381 //SEGGER_RTT_printf(0, "Function <TrueRMSCurrentCalculation> lasts %u cycles\n", TIM2->CNT);
382
383 MODBUS_Management(); // This function does not rely on time event
384
385 Keys_Management();
386
387 new_time = HAL_GetTick(); // Saving current time
388 if (new_time == old_time) continue; // If tick value hasn't changed since last time, then it is useless to check the rest of conditions below
389 old_time = new_time; // Saving current time value
390
391 //HAL_IWDG_Refresh(&hiwdg); // 0.5s RESET
392
393 Callibration();
394
395 LEDs_Management();
396
397 // Printing DEBUG messages
398 // If SWD connector is not connected, we do not waste time for printing
399 swdioConnection <<= 1; // Preparing space for 1 bit
400 swdioConnection |= HAL_GPIO_ReadPin(SWCLK_Port, SWCLK_Pin); // Sampling SWCLK pin
401 if (swdioConnection) DEBUG_print(new_time); // If debugger is connected, then we show debug messages
402
403 // Some not extremely urgent values calculations
404 HeavyCalculations(new_time); // Max execution time is 74µs
405
406 RS485DisableButtonManagement(new_time);
407
408 //Speicher Log Daten maximal jede Stunde, aber auch nur dann, wenn siche Werte, seit dem letztem mal geändert haben
409 if (new_time - stat_last_time_checked > HOUR_TIME_INTERVALL)
410 {
411 stat_last_time_checked = new_time;
412 LOG_I(TAG, "It is time to save statistical data in Flash memory.");
413
414 if (statDataChanged)
415 {
416 FEEPROM_StoreLogData(&sys_data);
417 statDataChanged = false;
418 }
419 }
420
421
422 static int restartAutoMode = 0;
423 // Checking switch state (Can be changed via Modbus or external button)
424 switch(sys_data.s.user_button_mode)
425 {
426 case SWITCH_OFF: // If button is set to OFF, then we disconnect both MOSFETS
427 break;
428
429 case SWITCH_ON: // If button is set to ON, then we connect both MOSFETS (Danger!!!)
430 // Checking whether temperature, current and battery voltage are within limits
431 if (temperature_shutdown_is_active == 1)
432 {
433 // If so, opening both MOSFETs (i.e. disconnecting load/charger from battery)
434#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
435 DisableShortCutDetection();
436#endif
437 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
438 MOSFETS_Management = &ADC_Open_Both_MOSFETs;
439 sys_data.s.relay_status = RELAY_IS_OPENED;
440 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
441 ExternalRedLED_Management = &ExternalRedLED1ShortOnThenLongPauseBlinking;
442 }
443 else if (overcurrent_shutdown_is_active == 1) ExternalRedLED_Management = &ExternalRedLED2ShortOnThenLongPauseBlinking;
444 else if (mosfets_voltagedrop_shutdown_is_active == 1) ExternalRedLED_Management = &ExternalRedLED3ShortOnThenLongPauseBlinking;
445 else if (overload_shutdown_is_active == 1) ExternalRedLED_Management = &ExternalRedLED4ShortOnThenLongPauseBlinking;
446 break;
447
448 case SWITCH_AUTO:
449 // Checking whether temperature, current and battery voltage are within limits
450 if ((temperature_shutdown_is_active == 1) || (low_bat_shutdown_is_active == 1))
451 {
452 if (!restartAutoMode)
453 {
454 // If so, opening both MOSFETs (i.e. disconnecting load/charger from battery)
455#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
456 DisableShortCutDetection();
457#endif
458 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
459 MOSFETS_Management = &ADC_Open_Both_MOSFETs;
460 sys_data.s.relay_status = RELAY_IS_OPENED;
461 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
462 if (temperature_shutdown_is_active == 1) ExternalRedLED_Management = &ExternalRedLED1ShortOnThenLongPauseBlinking;
463 if (low_bat_shutdown_is_active == 1) ExternalRedLED_Management = &ExternalRedLED5ShortOnThenLongPauseBlinking;
464 restartAutoMode = 1;
465 }
466 }
467 else if (overcurrent_shutdown_is_active == 1)
468 {
469 if (!restartAutoMode) { ExternalRedLED_Management = &ExternalRedLED2ShortOnThenLongPauseBlinking; restartAutoMode = 1; }
470 }
471 else if (mosfets_voltagedrop_shutdown_is_active == 1)
472 {
473 if (!restartAutoMode) { ExternalRedLED_Management = &ExternalRedLED3ShortOnThenLongPauseBlinking; restartAutoMode = 1; }
474 }
475 else if (overload_shutdown_is_active == 1)
476 {
477 if (!restartAutoMode) { ExternalRedLED_Management = &ExternalRedLED4ShortOnThenLongPauseBlinking; restartAutoMode = 1; }
478 }
479 else
480 {
481 // Normal operations
482
483 /** This is a main function that is called in AUTO mode.
484 Which one function is executed depends on DIP switch state.
485 In general, here can be executed 3 functions:
486 1. AUTO_LVP_Management (OVP is ignored)
487 2. AUTO_OVP_Management (LVP is ignored)
488 3. AUTO_LVP_OVP_Management
489 As long as device is in AUTO mode, this function is called
490 periodically.
491 */
492 AUTO_Mode(new_time, restartAutoMode);
493 restartAutoMode = 0;
494 }
495 break;
496 }
497
498 /* USER CODE END WHILE */
499
500 /* USER CODE BEGIN 3 */
501
502 } /* while (1) */
503
504 /* USER CODE END 3 */
505}
506
507/**
508 * @brief System Clock Configuration
509 * @retval None
510 */
511void SystemClock_Config(void)
512{
513 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
514 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
515
516 /** Configure the main internal regulator output voltage
517 */
518 HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
519
520 /** Initializes the RCC Oscillators according to the specified parameters
521 * in the RCC_OscInitTypeDef structure.
522 */
523 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI
524 |RCC_OSCILLATORTYPE_HSE;
525 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
526 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
527 RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV8;
528 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
529 RCC_OscInitStruct.LSIState = RCC_LSI_ON;
530 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
531 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
532 RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
533 RCC_OscInitStruct.PLL.PLLN = 16;
534 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
535 RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
536 RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
537 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
538 {
539 Error_Handler();
540 }
541
542 /** Initializes the CPU, AHB and APB buses clocks
543 */
544 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
545 |RCC_CLOCKTYPE_PCLK1;
546 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
547 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
548 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
549
550 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
551 {
552 Error_Handler();
553 }
554
555 /** Enables the Clock Security System
556 */
557 HAL_RCC_EnableCSS();
558}
559
560/* USER CODE BEGIN 4 */
561
562//-----------------------------------------------------------------------------
563
564void RS485DisableButtonManagement(uint32_t new_time)
565{
566 static uint32_t btn_last_time_checked = 0;
567 uint32_t BTN_SCAN_PERIOD = 25;
568 static uint8_t btn_state = 0;
569 static int transition = 1;
570
571 // Scanning special button on the board, which disables RS485 MODBUS interface
572 if (new_time - btn_last_time_checked > BTN_SCAN_PERIOD)
573 {
574 btn_last_time_checked = new_time;
575 BTN_SCAN_PERIOD = 25;
576
577 btn_state <<= 1;
578
579 // If this special button is pressed
580 if (HAL_GPIO_ReadPin(BTN1_GPIO_Port, BTN1_Pin) == BTN_IS_PRESSED)
581 {
582 //BTN_SCAN_PERIOD = 1500;
583 btn_state |= 1;
584
585 if (btn_state & 0xFF)
586 {
587 //btn_state = 0;
588 // If MODBUS RS485 interface is enabled
589 if (transition)
590 {
591 transition = 0;
592 if (RS485ActiveMode)
593 {
594 // We disable it
595 InternalBlueLED_Management = &TurnBlueLEDOn;
596 RS485ActiveMode = 0;
597 }
598 else
599 {
600 // We enable it
601 InternalBlueLED_Management = &BlueLEDShortBlinking;
602 RS485ActiveMode = 1;
603 }
604 }
605 }
606 }
607 else
608 {
609 btn_state |= 0;
610 if (btn_state == 0) transition = 1;
611 }
612 }
613}
614
615//-----------------------------------------------------------------------------
616
617void ABVoltageDropCalculation(void)
618{
619 static int32_t ursense_voltage_accum = 0;
620 static volatile uint32_t last_time_UabCalculated = 0;
621 static int positive_pulse_found = 0;
622
623 static volatile uint32_t new_time;
624 new_time = HAL_GetTick();
625
626 if (new_time - last_time_UabCalculated > 1)
627 {
628 last_time_UabCalculated = new_time;
629 // Calculating real voltage drop between contacts B and A in mV
630 sys_data.s.ab_raw_adc_value_with_offset = rawMOSFETsVoltageDrop + sys_data.s.ab_middle_point_offset;
631 int32_t temp = ((sys_data.s.ab_raw_adc_value_with_offset) * 2 * MAX_POSSIBLE_DIFF_TO_MEASURE) / ADC_MAX_VALUE - MAX_POSSIBLE_DIFF_TO_MEASURE;
632 // Calculating averaged value for real voltage drop between contacts B and A in mV
633 ursense_voltage_accum -= sys_data.s.ursense_voltage;
634 ursense_voltage_accum += temp;
635 sys_data.s.ursense_voltage = ursense_voltage_accum /16384;
636
637 if ((sys_data.s.relay_status != RELAY_IS_OPENED)/* || (sys_data.s.relay_status == ONLY_BA_OPENED) || (sys_data.s.relay_status == ONLY_AB_OPENED)*/)
638 {
639 if (!positive_pulse_found)
640 {
641 positive_pulse_found = 1;
642 ursense_voltage_accum = 0;
643 sys_data.s.ursense_voltage = 0;
644 return;
645 }
646
647 if (sys_data.s.relay_status == ONLY_BA_OPENED)
648 {
649 // Here we can start tracking the voltage drop on MOSFETs
650 if (sys_data.s.ursense_voltage < -(MAX_ALLOWED_MOSFETS_V_DROP + MAX_ALLOWED_MOSFETS_V_DROP_DELTA))
651 {
652 if (mosfets_voltagedrop_shutdown_is_active == 0)
653 {
654 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
655 OpenBothMOSFETSVeryFast();
656 MOSFETS_Management = &DoNothing;
657 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
658 mosfets_voltagedrop_shutdown_is_active = 1;
659 //sys_data.s.device_status |= (1 << ABBA_VOLTAGE_ERROR);
660 sys_data.s.mosfets_voltagedrop_error_cnt++;
661 statDataChanged = 1;
662 }
663 }
664 }
665 else if (sys_data.s.relay_status == ONLY_AB_OPENED)
666 {
667 // Here we can start tracking the voltage drop on MOSFETs
668 if (sys_data.s.ursense_voltage > (MAX_ALLOWED_MOSFETS_V_DROP + MAX_ALLOWED_MOSFETS_V_DROP_DELTA))
669 {
670 if (mosfets_voltagedrop_shutdown_is_active == 0)
671 {
672 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
673 OpenBothMOSFETSVeryFast();
674 MOSFETS_Management = &DoNothing;
675 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
676 mosfets_voltagedrop_shutdown_is_active = 1;
677 //sys_data.s.device_status |= (1 << ABBA_VOLTAGE_ERROR);
678 sys_data.s.mosfets_voltagedrop_error_cnt++;
679 statDataChanged = 1;
680 }
681 }
682 }
683 }
684 else positive_pulse_found = 0;
685
686 //SEGGER_RTT_printf(0, "Uab = %4d Rstatus = %d\n", sys_data.s.ursense_voltage, sys_data.s.relay_status);
687 }
688}
689
690//-----------------------------------------------------------------------------
691
692void mb_save_lock_key(void)
693{
694 if (sys_data.s.lockKey == savedLockKey)
695 {
696 FEEPROM_storeConfig(&sys_data, false);
697 savedLockKey = sys_data.s.newLockKey;
698 sys_data.s.lockKey = savedLockKey;
699 }
700
701 if (savedLockKey != 0)
702 {
703 sys_data.s.writeLocked = 1;
704 }
705 else
706 {
707 sys_data.s.writeLocked = 0;
708 }
709}
710
711//-----------------------------------------------------------------------------
712
713void SYSDATA_Init(void)
714{
715 memset(&sys_data, 0, sizeof(sys_data));
716
717 sys_data.s.device_type_id = DEVICE_TYPE_ID;
718 sys_data.s.fw_major = FW_VERSION_MAJOR;
719 sys_data.s.fw_minor = FW_VERSION_MINOR;
720 sys_data.s.fw_revision = FW_VERSION_REVISION;
721
722 sys_data.s.command = 0;
723 sys_data.s.device_status = 0;
724}
725
726//-----------------------------------------------------------------------------
727
728void CurrentOfflineCalculation(void)
729{
730 static uint32_t last_time = 0;
731
732 uint32_t new_time = HAL_GetTick();
733
734 if (new_time - last_time >= 1)
735 {
736 last_time = new_time;
737
738 // Sliding average calculation of discharge current
739 //current_temperature = (((MAX_TEMP - MIN_TEMP)*((int)ADC_values[TEMP_CHANNEL] - TEMP_SENSOR_ADC_AT_MINUS30))/(TEMP_SENSOR_ADC_AT_PLUS100 - TEMP_SENSOR_ADC_AT_MINUS30)) + MIN_TEMP;
740 //temperature_accum -= sys_data.s.temperature;
741 //temperature_accum += current_temperature;
742 //sys_data.s.temperature = temperature_accum / 32;//>> 5;
743
744 }
745
746}
747
748//-----------------------------------------------------------------------------
749
750void TrueRMSCurrentOfflineCalculation(void)
751{
752 static uint32_t last_time = 0;
753 static uint32_t samples_cnt = 0;
754 static uint64_t sum = 0;
755 const uint32_t N = 8;
756
757 uint32_t new_time = HAL_GetTick();
758
759 if (new_time - last_time >= 1)
760 {
761 last_time = new_time;
762
763 // rawContactVoltageDrop is in the range [-4095, 4095]
764 // Saving it in temporary variable, to prevent corruption of its value in ISR
765 int32_t tmp = rawContactVoltageDropPlus;
766 sum += (tmp * tmp);
767 samples_cnt++;
768 //SEGGER_RTT_printf(0, "[%3u] %5d %8u\n", samples_cnt, tmp, sum);
769 }
770
771 if (samples_cnt > (CONTROL_CURRENT_A*N)) // Number of samples is picked to correspond to CONTROL_CURRENT_A value. Must be CONTROL_CURRENT_A * N, where N is [1,2,3...]
772 {
773 samples_cnt = 0;
774 //SEGGER_RTT_printf(0, "%u\n", sum);
775
776 if (sys_data.s.ursense_voltage >= 0)
777 {
778 sys_data.s.current = sqrtf((sum*CONTROL_CURRENT_A)/(sys_data.s.copper_v_drop_adc * sys_data.s.copper_v_drop_adc * N));
779 }
780 else
781 {
782 sys_data.s.current = -sqrtf((sum*CONTROL_CURRENT_A)/(sys_data.s.copper_v_drop_adc * sys_data.s.copper_v_drop_adc * N));
783 }
784
785 //SEGGER_RTT_printf(0, "%d\n", sys_data.s.current);
786 sum = 0;
787 }
788
789}
790
791//-----------------------------------------------------------------------------
792
793/*void TrueRMSCurrentCalculation(void)
794{
795 static uint64_t total_sum = 0;
796 static uint32_t total_sum_cnt = 0;
797
798 // Executing this if ISR filled all I_RMS_SAMPLES_COUNT values into i_samples array
799 if (i_samples_counter == I_RMS_SAMPLES_COUNT)
800 {
801#ifdef DEBUG
802 static uint64_t sum = 0;
803#else
804 uint64_t sum = 0;
805 //int is_negative;
806#endif
807 for (int i = 0; i < I_RMS_SAMPLES_COUNT; i++)
808 {
809#ifdef DEBUG
810 static int32_t shifted_value = 0;
811 shifted_value = i_samples[i] - (ADC_MAX_VALUE>>1);
812 static uint32_t zero_based_value;
813#else
814 static volatile int32_t shifted_value;
815 shifted_value = i_samples[i] - (ADC_MAX_VALUE>>1); // Delta from middle point of 2047
816 //uint32_t zero_based_value;
817#endif
818 //if (shifted_value >= 0)
819 //{
820 // zero_based_value = shifted_value;
821 // //is_negative = 0;
822 //}
823 //else
824 //{
825 // zero_based_value = - shifted_value;
826 // //is_negative = 1;
827 //}
828
829 //static float divider;
830 //divider = ADC_MAX_VALUE * sys_data.s.copper_v_drop * (1 + (COPPER_TEMP_COEFFICIENT * (sys_data.s.temperature - 200))/10);
831
832 //current_value = (zero_based_value * CONTROL_CURRENT_A * ADC_VREF) / divider;
833
834 //float divider = ADC_MAX_VALUE * sys_data.s.copper_v_drop * (1 + (COPPER_TEMP_COEFFICIENT * (sys_data.s.temperature - sys_data.s.copper_v_drop_temp))/10);
835 //float divider = sys_data.s.copper_v_drop_adc * (1 + (COPPER_TEMP_COEFFICIENT * (sys_data.s.temperature - sys_data.s.copper_v_drop_temp))/10);
836 static volatile int32_t current_value;
837 current_value = (shifted_value * CONTROL_CURRENT_A) / sys_data.s.copper_v_drop_adc;
838 if (current_value < 0)
839 {
840 if (-current_value > sys_data.s.max_discharge_current) sys_data.s.max_discharge_current = -current_value;
841 else if (-current_value < sys_data.s.min_discharge_current) sys_data.s.min_discharge_current = -current_value;
842 }
843 else
844 {
845 if (current_value > sys_data.s.max_charge_current) sys_data.s.max_charge_current = current_value;
846 else if (current_value < sys_data.s.min_charge_current) sys_data.s.min_charge_current = current_value;
847 }
848
849 sum += (shifted_value * shifted_value);
850 //char div[50];
851 //sprintf(div, "%f", divider);
852 //SEGGER_RTT_printf(0, "%u, %u\n", u_samples[i], d_samples[i]);
853 }
854
855 i_samples_counter = 0;
856
857 if (total_sum_cnt < I_RMS_SAMPLES_SUM_COUNT)
858 {
859 total_sum += sum;
860 total_sum_cnt++;
861 }
862 else
863 {
864 total_sum_cnt = 0;
865 //SEGGER_RTT_printf(0, "Sum: %d\tTotal: %d\n", sum, total_sum);
866 total_sum = (total_sum * CONTROL_CURRENT_A * CONTROL_CURRENT_A) / (sys_data.s.copper_v_drop_adc * sys_data.s.copper_v_drop_adc);
867 if (sys_data.s.ursense_voltage >= 0) sys_data.s.current = sqrtf(total_sum/(I_RMS_SAMPLES_COUNT * I_RMS_SAMPLES_SUM_COUNT));
868 else sys_data.s.current = -sqrtf(total_sum/(I_RMS_SAMPLES_COUNT * I_RMS_SAMPLES_SUM_COUNT));
869 //else sys_data.s.current = sqrtf(total_sum/(I_RMS_SAMPLES_COUNT * I_RMS_SAMPLES_SUM_COUNT));
870 total_sum = 0;
871 }
872 }
873}*/
874
875//-----------------------------------------------------------------------------
876
877/*#ifdef USE_RAM_FUNC
878__RAM_FUNC void ShortCutCheck(void)
879#else
880void ShortCutCheck(void)
881#endif
882{
883 static uint32_t last_time_checked = 0;
884 static int current_integral_calc_started = 0;
885 static uint32_t current_integral = 0;
886
887 uint32_t current_time = HAL_GetTick();
888 int32_t current_adc_value = abs(rawContactVoltageDrop - (ADC_MAX_VALUE>>1));
889
890 if (current_time - last_time_checked > 1)
891 {
892 last_time_checked = current_time;
893
894 if (current_adc_value > ADC_VALUE_DELTA_AT_CONTROL_CURRENT_A)
895 {
896 if (current_integral_calc_started)
897 {
898 current_integral += current_adc_value;
899 if (current_integral > (ADC_VALUE_DELTA_AT_INRUSH_CURRENT * 5)) overcurrent_shutdown_is_active = 1;
900 SEGGER_RTT_printf(0, "\t%d\t%d\n", current_adc_value, current_integral);
901 }
902 else
903 {
904 current_integral = 0;
905 current_integral += current_adc_value;
906 current_integral_calc_started = 1;
907 SEGGER_RTT_printf(0, "Overcurrent: %d\n", current_adc_value);
908 SEGGER_RTT_printf(0, "Starting integral calculation:\n");
909 SEGGER_RTT_printf(0, "\t%d\t%d\n", current_adc_value, current_integral);
910 }
911 }
912 else
913 {
914 if (current_integral_calc_started)
915 {
916 SEGGER_RTT_printf(0, "Stopping integral calculation:\n");
917 SEGGER_RTT_printf(0, "\t%d\t%d\n", current_adc_value, current_integral);
918 current_integral = 0;
919 current_integral_calc_started = 0;
920 }
921 }
922 }
923
924}*/
925
926//-----------------------------------------------------------------------------
927
928#ifdef USE_RAM_FUNC
929void CopyingVectorTableToRAM(void)
930{
931 uint32_t SrcAddress = SCB->VTOR;
932 uint32_t DstAddress = (uint32_t)vectorTableInRAM;
933
934 if (HAL_DMA_Start(&hdma_memtomem_dma1_channel2, SrcAddress, DstAddress, 192/4) != HAL_OK)
935 {
936 LOG_E(TAG, "Cannot copy Vector Table from FLASH to RAM! DMA is not ready!");
937 while(1);
938 }
939 else LOG_I(TAG, "Starting Vector Table copying from FLASH to RAM...");
940
941 if (HAL_DMA_PollForTransfer(&hdma_memtomem_dma1_channel2, HAL_DMA_FULL_TRANSFER, 1000) != HAL_OK)
942 {
943 LOG_E(TAG, "Cannot finish copying Vector Table from FLASH to RAM!");
944 while(1);
945 }
946 else LOG_I(TAG, "Vector Table has been copied from FLASH to RAM.");
947 SCB->VTOR = DstAddress;
948}
949#endif
950
951//------------------------------------------------------------------------------
952
953void LEDBlink(uint32_t *local_prev_on_time, // last tick counter value
954 unsigned *local_step, // current number of led ignitions
955 unsigned *local_subStep, // corresponds to current phase of led blinking process
956 unsigned local_totalStages, // how many times led should blink
957 uint16_t *local_turnOnTime, // array that contains times for how long led should stay in on state
958 uint16_t *local_turnOffTime, // array that contains times for how long led should stay in off state
959 GPIO_TypeDef *GPIOx, // port name
960 uint16_t GPIO_Pin) // pin number
961{
962 uint32_t new_time = HAL_GetTick();
963
964 if (*local_step < local_totalStages)
965 {
966 switch((*local_subStep))
967 {
968 case 0: // Phase 0 - turning led on
969 HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_SET);
970 *local_prev_on_time = new_time;
971 (*local_subStep)++;
972 break;
973
974 case 1: // Phase 1 - turning led off, if it is time
975 if (new_time - *local_prev_on_time > local_turnOnTime[*local_step])
976 {
977 HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_RESET);
978 *local_prev_on_time = new_time;
979 (*local_subStep)++;
980 }
981 break;
982
983 case 2: // Phase 2 - waiting before returning to phase 0
984 if (new_time - *local_prev_on_time > local_turnOffTime[*local_step])
985 {
986 *local_prev_on_time = new_time;
987 *local_subStep = 0;
988 (*local_step)++;
989 }
990 break;
991 }
992 }
993 else *local_step = 0;
994}
995
996//------------------------------------------------------------------------------
997
998void RedLEDBlink(uint16_t *turnOnPeriods, uint16_t *turnOffPeriods, unsigned totalStages)
999{
1000 static uint32_t RedLEDLastTickTime = 0;
1001 static unsigned stage = 0;
1002 static unsigned subStage = 0;
1003
1004 LEDBlink(&RedLEDLastTickTime, &stage, &subStage, totalStages, turnOnPeriods, turnOffPeriods, LED_ERROR_GPIO_Port, LED_ERROR_Pin);
1005}
1006
1007//------------------------------------------------------------------------------
1008
1009void ExternalRedLEDBlink(uint16_t *turnOnPeriods, uint16_t *turnOffPeriods, unsigned totalStages)
1010{
1011 static uint32_t RedLEDLastTickTime = 0;
1012 static unsigned stage = 0;
1013 static unsigned subStage = 0;
1014
1015 LEDBlink(&RedLEDLastTickTime, &stage, &subStage, totalStages, turnOnPeriods, turnOffPeriods, LED_SW_ERROR_GPIO_Port, LED_SW_ERROR_Pin);
1016}
1017
1018//------------------------------------------------------------------------------
1019
1020void ExternalRedLED2ShortOnThen2LongOnThenLongPauseBlinking(void)
1021{
1022 const unsigned stages = 4;
1023 uint16_t turnOnTimes[stages];
1024 uint16_t turnOffTimes[stages];
1025
1026 turnOnTimes[0] = 200;
1027 turnOffTimes[0] = 200;
1028
1029 turnOnTimes[1] = 200;
1030 turnOffTimes[1] = 500;
1031
1032 turnOnTimes[2] = 700;
1033 turnOffTimes[2] = 500;
1034
1035 turnOnTimes[stages - 1] = 700;
1036 turnOffTimes[stages - 1] = 2500;
1037
1038 ExternalRedLEDBlink(turnOnTimes, turnOffTimes, stages);
1039 RedLEDBlink(turnOnTimes, turnOffTimes, stages);
1040}
1041
1042//------------------------------------------------------------------------------
1043
1044void ExternalRedLED6ShortOnThenLongPauseBlinking(void)
1045{
1046 const unsigned stages = 6;
1047 uint16_t turnOnTimes[stages];
1048 uint16_t turnOffTimes[stages];
1049
1050 for (unsigned i = 0; i < stages - 1; i++)
1051 {
1052 turnOnTimes[i] = 200;
1053 turnOffTimes[i] = 200;
1054 }
1055
1056 turnOnTimes[stages - 1] = 200;
1057 turnOffTimes[stages - 1] = 2500;
1058
1059 ExternalRedLEDBlink(turnOnTimes, turnOffTimes, stages);
1060 RedLEDBlink(turnOnTimes, turnOffTimes, stages);
1061}
1062
1063//------------------------------------------------------------------------------
1064
1065void ExternalRedLED5ShortOnThenLongPauseBlinking(void)
1066{
1067 const unsigned stages = 5;
1068 uint16_t turnOnTimes[stages];
1069 uint16_t turnOffTimes[stages];
1070
1071 for (unsigned i = 0; i < stages - 1; i++)
1072 {
1073 turnOnTimes[i] = 200;
1074 turnOffTimes[i] = 200;
1075 }
1076
1077 turnOnTimes[stages - 1] = 200;
1078 turnOffTimes[stages - 1] = 2500;
1079
1080 ExternalRedLEDBlink(turnOnTimes, turnOffTimes, stages);
1081 RedLEDBlink(turnOnTimes, turnOffTimes, stages);
1082}
1083
1084//------------------------------------------------------------------------------
1085
1086void ExternalRedLED4ShortOnThenLongPauseBlinking(void)
1087{
1088 const unsigned stages = 4;
1089 uint16_t turnOnTimes[stages];
1090 uint16_t turnOffTimes[stages];
1091
1092 for (unsigned i = 0; i < stages - 1; i++)
1093 {
1094 turnOnTimes[i] = 200;
1095 turnOffTimes[i] = 200;
1096 }
1097
1098 turnOnTimes[stages - 1] = 200;
1099 turnOffTimes[stages - 1] = 2500;
1100
1101 ExternalRedLEDBlink(turnOnTimes, turnOffTimes, stages);
1102 RedLEDBlink(turnOnTimes, turnOffTimes, stages);
1103}
1104
1105//------------------------------------------------------------------------------
1106
1107void ExternalRedLED3ShortOnThenLongPauseBlinking(void)
1108{
1109 const unsigned stages = 3;
1110 uint16_t turnOnTimes[stages];
1111 uint16_t turnOffTimes[stages];
1112
1113 for (unsigned i = 0; i < stages - 1; i++)
1114 {
1115 turnOnTimes[i] = 200;
1116 turnOffTimes[i] = 200;
1117 }
1118
1119 turnOnTimes[stages - 1] = 200;
1120 turnOffTimes[stages - 1] = 2500;
1121
1122 ExternalRedLEDBlink(turnOnTimes, turnOffTimes, stages);
1123 RedLEDBlink(turnOnTimes, turnOffTimes, stages);
1124}
1125
1126//------------------------------------------------------------------------------
1127
1128void ExternalRedLED2ShortOnThenLongPauseBlinking(void)
1129{
1130 const unsigned stages = 2;
1131 uint16_t turnOnTimes[stages];
1132 uint16_t turnOffTimes[stages];
1133
1134 turnOnTimes[0] = 200;
1135 turnOffTimes[0] = 200;
1136
1137 turnOnTimes[stages - 1] = 200;
1138 turnOffTimes[stages - 1] = 2500;
1139
1140 ExternalRedLEDBlink(turnOnTimes, turnOffTimes, stages);
1141 RedLEDBlink(turnOnTimes, turnOffTimes, stages);
1142}
1143
1144//------------------------------------------------------------------------------
1145
1146void ExternalRedLED1ShortOnThenLongPauseBlinking(void)
1147{
1148 const unsigned stages = 1;
1149 uint16_t turnOnTimes[stages];
1150 uint16_t turnOffTimes[stages];
1151
1152 turnOnTimes[stages - 1] = 200;
1153 turnOffTimes[stages - 1] = 2500;
1154
1155 ExternalRedLEDBlink(turnOnTimes, turnOffTimes, stages);
1156 RedLEDBlink(turnOnTimes, turnOffTimes, stages);
1157}
1158
1159//------------------------------------------------------------------------------
1160
1161/*void ExternalRedLEDVeryShortBlinking(void)
1162{
1163 static uint32_t old_on_time = 0;
1164 static uint32_t led_is_turned_on = 0;
1165 uint32_t new_time;
1166
1167 new_time = HAL_GetTick();
1168 if (!led_is_turned_on && (new_time - old_on_time > 200))
1169 {
1170 HAL_GPIO_WritePin(LED_SW_ERROR_GPIO_Port, LED_SW_ERROR_Pin, GPIO_PIN_SET); // External Red LED on button
1171 led_is_turned_on = 1;
1172 old_on_time = new_time;
1173 }
1174 else if (led_is_turned_on && (new_time - old_on_time > 200))
1175 {
1176 HAL_GPIO_WritePin(LED_SW_ERROR_GPIO_Port, LED_SW_ERROR_Pin, GPIO_PIN_RESET);
1177 led_is_turned_on = 0;
1178 old_on_time = new_time;
1179 }
1180}*/
1181
1182//------------------------------------------------------------------------------
1183
1184/*void ExternalRedLEDShortBlinking(void)
1185{
1186 static uint32_t old_on_time = 0;
1187 static uint32_t led_is_turned_on = 0;
1188 uint32_t new_time;
1189
1190 new_time = HAL_GetTick();
1191 if (!led_is_turned_on && (new_time - old_on_time > 800))
1192 {
1193 HAL_GPIO_WritePin(LED_SW_ERROR_GPIO_Port, LED_SW_ERROR_Pin, GPIO_PIN_SET); // External Red LED on button
1194 led_is_turned_on = 1;
1195 old_on_time = new_time;
1196 }
1197 else if (led_is_turned_on && (new_time - old_on_time > 200))
1198 {
1199 HAL_GPIO_WritePin(LED_SW_ERROR_GPIO_Port, LED_SW_ERROR_Pin, GPIO_PIN_RESET);
1200 led_is_turned_on = 0;
1201 old_on_time = new_time;
1202 }
1203}*/
1204
1205//------------------------------------------------------------------------------
1206
1207void TurnExternalRedLEDOff(void)
1208{
1209 HAL_GPIO_WritePin(LED_SW_ERROR_GPIO_Port, LED_SW_ERROR_Pin, GPIO_PIN_RESET);
1210 HAL_GPIO_WritePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin, GPIO_PIN_RESET);
1211 ExternalRedLED_Management = &DoNothing;
1212}
1213
1214//------------------------------------------------------------------------------
1215
1216void ExternalGreenLEDShortBlinking(void)
1217{
1218 static uint32_t old_on_time = 0;
1219 static uint32_t led_is_turned_on = 0;
1220 uint32_t new_time;
1221
1222 new_time = HAL_GetTick();
1223 if (!led_is_turned_on && (new_time - old_on_time > 800))
1224 {
1225 HAL_GPIO_WritePin(LED_SW_STATE_GPIO_Port, LED_SW_STATE_Pin, GPIO_PIN_SET); // External Green LED on button
1226 led_is_turned_on = 1;
1227 old_on_time = new_time;
1228 }
1229 else if (led_is_turned_on && (new_time - old_on_time > 200))
1230 {
1231 HAL_GPIO_WritePin(LED_SW_STATE_GPIO_Port, LED_SW_STATE_Pin, GPIO_PIN_RESET);
1232 led_is_turned_on = 0;
1233 old_on_time = new_time;
1234 }
1235}
1236
1237//------------------------------------------------------------------------------
1238
1239void TurnExternalGreenLEDOff(void)
1240{
1241 HAL_GPIO_WritePin(LED_SW_STATE_GPIO_Port, LED_SW_STATE_Pin, GPIO_PIN_RESET);
1242 ExternalGreenLED_Management = &DoNothing;
1243}
1244
1245//------------------------------------------------------------------------------
1246
1247void TurnExternalGreenLEDOn(void)
1248{
1249 HAL_GPIO_WritePin(LED_SW_STATE_GPIO_Port, LED_SW_STATE_Pin, GPIO_PIN_SET);
1250 ExternalGreenLED_Management = &DoNothing;
1251}
1252
1253//------------------------------------------------------------------------------
1254
1255void GreenLEDShortBlinking(void)
1256{
1257 static uint32_t old_on_time = 0;
1258 static uint32_t led_is_turned_on = 0;
1259 uint32_t new_time;
1260
1261 // Blue LED blinking (950ms - OFF, 50ms - ON)
1262 new_time = HAL_GetTick();
1263 if (!led_is_turned_on && (new_time - old_on_time > 950))
1264 {
1265 HAL_GPIO_WritePin(LED_STATE_GPIO_Port, LED_STATE_Pin, GPIO_PIN_SET);
1266 led_is_turned_on = 1;
1267 old_on_time = new_time;
1268 }
1269 else if (led_is_turned_on && (new_time - old_on_time > 50))
1270 {
1271 HAL_GPIO_WritePin(LED_STATE_GPIO_Port, LED_STATE_Pin, GPIO_PIN_RESET);
1272 led_is_turned_on = 0;
1273 old_on_time = new_time;
1274 }
1275}
1276
1277//------------------------------------------------------------------------------
1278
1279void TurnGreenLEDOff(void)
1280{
1281 HAL_GPIO_WritePin(LED_STATE_GPIO_Port, LED_STATE_Pin, GPIO_PIN_RESET);
1282 InternalGreenLED_Management = &DoNothing;
1283}
1284
1285//------------------------------------------------------------------------------
1286
1287void TurnGreenLEDOn(void)
1288{
1289 HAL_GPIO_WritePin(LED_STATE_GPIO_Port, LED_STATE_Pin, GPIO_PIN_SET);
1290 InternalGreenLED_Management = &DoNothing;
1291}
1292
1293//------------------------------------------------------------------------------
1294
1295void TurnBlueLEDOn(void)
1296{
1297 HAL_GPIO_WritePin(LED_FUNCTION_GPIO_Port, LED_FUNCTION_Pin, GPIO_PIN_SET);
1298 InternalBlueLED_Management = &DoNothing;
1299}
1300
1301//------------------------------------------------------------------------------
1302
1303void BlueLEDShortBlinking(void)
1304{
1305 static uint32_t old_on_time = 0;
1306 static uint32_t led_is_turned_on = 0;
1307 uint32_t new_time;
1308
1309 // Blue LED blinking (950ms - OFF, 50ms - ON)
1310 new_time = HAL_GetTick();
1311 if (!led_is_turned_on && (new_time - old_on_time > 950))
1312 {
1313 HAL_GPIO_WritePin(LED_FUNCTION_GPIO_Port, LED_FUNCTION_Pin, GPIO_PIN_SET);
1314 led_is_turned_on = 1;
1315 old_on_time = new_time;
1316 }
1317 else if (led_is_turned_on && (new_time - old_on_time > 50))
1318 {
1319 HAL_GPIO_WritePin(LED_FUNCTION_GPIO_Port, LED_FUNCTION_Pin, GPIO_PIN_RESET);
1320 led_is_turned_on = 0;
1321 old_on_time = new_time;
1322 }
1323}
1324
1325//------------------------------------------------------------------------------
1326
1327void LEDs_Management(void)
1328{
1329 InternalGreenLED_Management();
1330 InternalBlueLED_Management();
1331 InternalRedLED_Management();
1332 ExternalGreenLED_Management();
1333 ExternalRedLED_Management();
1334}
1335
1336//------------------------------------------------------------------------------
1337
1338void ExitPowerSavingMode(void)
1339{
1340 //HAL_GPIO_WritePin(DISABLE_VBOOST_GPIO_Port, DISABLE_VBOOST_Pin, GPIO_PIN_SET); // Turning VBOOST voltage generator on
1341
1342 //HAL_PWREx_DisableLowPowerRunMode();
1343 //HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
1344 //SystemClock_Config();
1345
1346 /*modbusData.uart->Instance->PRESC = UART_PRESCALER_DIV8;
1347 // Modbus Initialisierung
1348 if (sys_data.s.parity_mode == 'e') mbInit(&modbusData, sys_data.s.baudrate, MODBUS_UART_PARITY_EVEN, &huart1);
1349 else if (sys_data.s.parity_mode == 'o') mbInit(&modbusData, sys_data.s.baudrate, MODBUS_UART_PARITY_ODD, &huart1);
1350 else mbInit(&modbusData, sys_data.s.baudrate, MODBUS_UART_PARITY_NONE, &huart1);*/
1351
1352}
1353
1354//------------------------------------------------------------------------------
1355
1356void EnterPowerSavingMode(void)
1357{
1358 //SystemClock_Decrease(); // Reduce the System clock to 2 MHz
1359 //HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2); // Set regulator voltage to scale 2
1360 //HAL_PWREx_EnableLowPowerRunMode(); // Enter LP RUN Mode
1361}
1362
1363//------------------------------------------------------------------------------
1364
1365void SystemClock_Decrease(void)
1366{
1367 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
1368 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
1369
1370 /* Select HSI as system clock source */
1371 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
1372 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
1373 if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
1374 {
1375 /* Initialization Error */
1376 Error_Handler();
1377 }
1378
1379 /* Modify HSI to HSI DIV8 */
1380 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
1381 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
1382 RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV8;
1383 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
1384 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_OFF;
1385 if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
1386 {
1387 /* Initialization Error */
1388 Error_Handler();
1389 }
1390}
1391
1392//------------------------------------------------------------------------------
1393
1394void DIP_Switches(void)
1395{
1396 // Checking positions of DIP switches
1397 if ((HAL_GPIO_ReadPin(DIP0_GPIO_Port, DIP0_Pin) == DIP_IS_OFF) &&
1398 (HAL_GPIO_ReadPin(DIP1_GPIO_Port, DIP1_Pin) == DIP_IS_OFF) &&
1399 (HAL_GPIO_ReadPin(DIP2_GPIO_Port, DIP2_Pin) == DIP_IS_OFF))
1400 {
1401 // Auto-reconnect DIP-switch
1402 if (HAL_GPIO_ReadPin(DIP3_GPIO_Port, DIP3_Pin) == DIP_IS_ON)
1403 {
1404 // Modus 0 (LVP only. Active level - LOW)
1405 LOG_I(TAG, "Mode 0 is selected. Auto-reconnect is ON.");
1406
1407 AUTO_Mode = &AUTO_LVP_Management;
1408 // Assigning default functions to function pointers array, depending on LVP state
1409 LVP_OVP[0] = &OVP_ignored__LVP_not_present; // 0
1410 LVP_OVP[1] = &OVP_ignored__LVP_present; // 1
1411 LVP_OVP[2] = LVP_OVP[3] = &DoNothing; // Not used
1412 //sys_data.s.ovp_state = 2; // Ignored state
1413 LVP_OVP_logic = LOGIC_NEGATIV;
1414 sys_data.s.dip_mode = 0 | (1 << 3);
1415 }
1416 else
1417 {
1418 // Modus 0 (LVP only. Active level - LOW)
1419 LOG_I(TAG, "Mode 0 is selected. Auto-reconnect is OFF.");
1420
1421 AUTO_Mode = &LVP_Management_NoAutoreconnect;
1422 // Assigning default functions to function pointers array, depending on LVP state
1423 LVP_OVP[0] = &OVP_ignored__LVP_not_present; // 0
1424 LVP_OVP[1] = &OVP_ignored__LVP_present_NoAutoreconnect; // 1
1425 LVP_OVP[2] = LVP_OVP[3] = &DoNothing; // Not used
1426 //sys_data.s.ovp_state = 2; // Ignored state
1427 LVP_OVP_logic = LOGIC_NEGATIV;
1428 sys_data.s.dip_mode = 0;
1429 }
1430 }
1431 else if ((HAL_GPIO_ReadPin(DIP0_GPIO_Port, DIP0_Pin) == DIP_IS_ON) &&
1432 (HAL_GPIO_ReadPin(DIP1_GPIO_Port, DIP1_Pin) == DIP_IS_OFF) &&
1433 (HAL_GPIO_ReadPin(DIP2_GPIO_Port, DIP2_Pin) == DIP_IS_OFF))
1434 {
1435 // Auto-reconnect DIP-switch
1436 if (HAL_GPIO_ReadPin(DIP3_GPIO_Port, DIP3_Pin) == DIP_IS_ON)
1437 {
1438 // Modus 1 (OVP only. Active level - LOW)
1439 LOG_I(TAG, "Mode 1 is selected. Auto-reconnect is ON.");
1440
1441 AUTO_Mode = &AUTO_OVP_Management;
1442 // Assigning default functions to function pointers array, depending on OVP state
1443 LVP_OVP[0] = &OVP_not_present__LVP_ignored; // 0
1444 LVP_OVP[1] = &OVP_present__LVP_ignored; // 1
1445 LVP_OVP[2] = LVP_OVP[3] = &DoNothing; // Not used
1446 //sys_data.s.lvp_state = 2; // Ignored state
1447 LVP_OVP_logic = LOGIC_NEGATIV;
1448 sys_data.s.dip_mode = 1 | (1 << 3);
1449 }
1450 else
1451 {
1452 // Modus 1 (OVP only. Active level - LOW)
1453 LOG_I(TAG, "Mode 1 is selected. Auto-reconnect is OFF.");
1454
1455 AUTO_Mode = &OVP_Management_NoAutoreconnect;
1456 // Assigning default functions to function pointers array, depending on OVP state
1457 LVP_OVP[0] = &OVP_not_present__LVP_ignored; // 0
1458 LVP_OVP[1] = &OVP_present__LVP_ignored_NoAutoreconnect; // 1
1459 LVP_OVP[2] = LVP_OVP[3] = &DoNothing; // Not used
1460 //sys_data.s.lvp_state = 2; // Ignored state
1461 LVP_OVP_logic = LOGIC_NEGATIV;
1462 sys_data.s.dip_mode = 1;
1463 }
1464 }
1465 else if ((HAL_GPIO_ReadPin(DIP0_GPIO_Port, DIP0_Pin) == DIP_IS_OFF) &&
1466 (HAL_GPIO_ReadPin(DIP1_GPIO_Port, DIP1_Pin) == DIP_IS_ON) &&
1467 (HAL_GPIO_ReadPin(DIP2_GPIO_Port, DIP2_Pin) == DIP_IS_OFF))
1468 {
1469 // Auto-reconnect DIP-switch
1470 if (HAL_GPIO_ReadPin(DIP3_GPIO_Port, DIP3_Pin) == DIP_IS_ON)
1471 {
1472 // Modus 2 (LVP only. Active level - HIGH)
1473 LOG_I(TAG, "Mode 2 is selected. Auto-reconnect is ON.");
1474
1475 AUTO_Mode = &AUTO_LVP_Management;
1476 // Assigning default functions to function pointers array, depending on LVP state
1477 LVP_OVP[0] = &OVP_ignored__LVP_not_present; // 0
1478 LVP_OVP[1] = &OVP_ignored__LVP_present; // 1
1479 LVP_OVP[2] = LVP_OVP[3] = &DoNothing; // Not used
1480 //sys_data.s.ovp_state = 2; // Ignored state
1481 LVP_OVP_logic = LOGIC_POSITIV;
1482 sys_data.s.dip_mode = 2 | (1 << 3);
1483 }
1484 else
1485 {
1486 // Modus 2 (LVP only. Active level - HIGH)
1487 LOG_I(TAG, "Mode 2 is selected. Auto-reconnect is OFF.");
1488
1489 AUTO_Mode = &LVP_Management_NoAutoreconnect;
1490 // Assigning default functions to function pointers array, depending on LVP state
1491 LVP_OVP[0] = &OVP_ignored__LVP_not_present; // 0
1492 LVP_OVP[1] = &OVP_ignored__LVP_present_NoAutoreconnect; // 1
1493 LVP_OVP[2] = LVP_OVP[3] = &DoNothing; // Not used
1494 //sys_data.s.ovp_state = 2; // Ignored state
1495 LVP_OVP_logic = LOGIC_POSITIV;
1496 sys_data.s.dip_mode = 2;
1497 }
1498 }
1499 else if ((HAL_GPIO_ReadPin(DIP0_GPIO_Port, DIP0_Pin) == DIP_IS_ON) &&
1500 (HAL_GPIO_ReadPin(DIP1_GPIO_Port, DIP1_Pin) == DIP_IS_ON) &&
1501 (HAL_GPIO_ReadPin(DIP2_GPIO_Port, DIP2_Pin) == DIP_IS_OFF))
1502 {
1503 // Auto-reconnect DIP-switch
1504 if (HAL_GPIO_ReadPin(DIP3_GPIO_Port, DIP3_Pin) == DIP_IS_ON)
1505 {
1506 // Modus 3 (OVP only. Active level - HIGH)
1507 LOG_I(TAG, "Mode 3 is selected. Auto-reconnect is ON.");
1508
1509 AUTO_Mode = &AUTO_OVP_Management;
1510 // Assigning default functions to function pointers array, depending on OVP state
1511 LVP_OVP[0] = &OVP_not_present__LVP_ignored; // 0
1512 LVP_OVP[1] = &OVP_present__LVP_ignored; // 1
1513 LVP_OVP[2] = LVP_OVP[3] = &DoNothing; // Not used
1514 //sys_data.s.lvp_state = 2; // Ignored state
1515 LVP_OVP_logic = LOGIC_POSITIV;
1516 sys_data.s.dip_mode = 3 | (1 << 3);
1517 }
1518 else
1519 {
1520 // Modus 3 (OVP only. Active level - HIGH)
1521 LOG_I(TAG, "Mode 3 is selected. Auto-reconnect is OFF.");
1522
1523 AUTO_Mode = &OVP_Management_NoAutoreconnect;
1524 // Assigning default functions to function pointers array, depending on OVP state
1525 LVP_OVP[0] = &OVP_not_present__LVP_ignored; // 0
1526 LVP_OVP[1] = &OVP_present__LVP_ignored_NoAutoreconnect; // 1
1527 LVP_OVP[2] = LVP_OVP[3] = &DoNothing; // Not used
1528 //sys_data.s.lvp_state = 2; // Ignored state
1529 LVP_OVP_logic = LOGIC_POSITIV;
1530 sys_data.s.dip_mode = 3;
1531 }
1532 }
1533 else if ((HAL_GPIO_ReadPin(DIP0_GPIO_Port, DIP0_Pin) == DIP_IS_OFF) &&
1534 (HAL_GPIO_ReadPin(DIP1_GPIO_Port, DIP1_Pin) == DIP_IS_OFF) &&
1535 (HAL_GPIO_ReadPin(DIP2_GPIO_Port, DIP2_Pin) == DIP_IS_ON))
1536 {
1537 // Auto-reconnect DIP-switch
1538 if (HAL_GPIO_ReadPin(DIP3_GPIO_Port, DIP3_Pin) == DIP_IS_ON)
1539 {
1540 // Modus 4 (LVP & OVP. Active level - LOW. With autoreconnect)
1541 LOG_I(TAG, "Mode 4 is selected. Auto-reconnect is ON.");
1542
1543 AUTO_Mode = &AUTO_LVP_OVP_Management;
1544 // Assigning default functions to function pointers array, depending on LVP and OVP events combinations
1545 LVP_OVP[0] = &OVP_not_present__LVP_not_present; // 00 - 0
1546 LVP_OVP[1] = &OVP_not_present__LVP_present; // 01 - 1
1547 LVP_OVP[2] = &OVP_present__LVP_not_present; // 10 - 2
1548 LVP_OVP[3] = &OVP_present__LVP_present; // 11 - 3
1549 LVP_OVP_logic = LOGIC_NEGATIV;
1550 sys_data.s.dip_mode = 4 | (1 << 3);
1551 }
1552 else
1553 {
1554 // Modus 4 (LVP & OVP. Active level - LOW. Without autoreconnect)
1555 LOG_I(TAG, "Mode 4 is selected. Auto-reconnect is OFF.");
1556
1557 AUTO_Mode = &LVP_OVP_Management_NoAutoreconnect;
1558 // Assigning default functions to function pointers array, depending on LVP and OVP events combinations
1559 LVP_OVP[0] = &OVP_not_present__LVP_not_present; // 00 - 0
1560 LVP_OVP[1] = &OVP_not_present__LVP_present; // 01 - 1
1561 LVP_OVP[2] = &OVP_present__LVP_not_present; // 10 - 2
1562 LVP_OVP[3] = &OVP_present__LVP_present; // 11 - 3
1563 LVP_OVP_logic = LOGIC_NEGATIV;
1564 sys_data.s.dip_mode = 4;
1565 }
1566 }
1567 else if ((HAL_GPIO_ReadPin(DIP0_GPIO_Port, DIP0_Pin) == DIP_IS_ON) &&
1568 (HAL_GPIO_ReadPin(DIP1_GPIO_Port, DIP1_Pin) == DIP_IS_OFF) &&
1569 (HAL_GPIO_ReadPin(DIP2_GPIO_Port, DIP2_Pin) == DIP_IS_ON))
1570 {
1571 // Auto-reconnect DIP-switch
1572 if (HAL_GPIO_ReadPin(DIP3_GPIO_Port, DIP3_Pin) == DIP_IS_ON)
1573 {
1574 // Modus 5 (LVP & OVP. Active level - HIGH. With autoreconnect)
1575 LOG_I(TAG, "Mode 5 is selected. Auto-reconnect is ON.");
1576
1577 AUTO_Mode = &AUTO_LVP_OVP_Management;
1578 // Assigning default functions to function pointers array, depending on LVP and OVP events combinations
1579 LVP_OVP[0] = &OVP_not_present__LVP_not_present; // 00 - 0
1580 LVP_OVP[1] = &OVP_not_present__LVP_present; // 01 - 1
1581 LVP_OVP[2] = &OVP_present__LVP_not_present; // 10 - 2
1582 LVP_OVP[3] = &OVP_present__LVP_present; // 11 - 3
1583 LVP_OVP_logic = LOGIC_POSITIV;
1584 sys_data.s.dip_mode = 5 | (1 << 3);
1585 }
1586 else
1587 {
1588 // Modus 5 (LVP & OVP. Active level - HIGH. Without autoreconnect)
1589 LOG_I(TAG, "Mode 5 is selected. Auto-reconnect is OFF.");
1590
1591 AUTO_Mode = &LVP_OVP_Management_NoAutoreconnect;
1592 // Assigning default functions to function pointers array, depending on LVP and OVP events combinations
1593 LVP_OVP[0] = &OVP_not_present__LVP_not_present; // 00 - 0
1594 LVP_OVP[1] = &OVP_not_present__LVP_present; // 01 - 1
1595 LVP_OVP[2] = &OVP_present__LVP_not_present; // 10 - 2
1596 LVP_OVP[3] = &OVP_present__LVP_present; // 11 - 3
1597 LVP_OVP_logic = LOGIC_POSITIV;
1598 sys_data.s.dip_mode = 5;
1599 }
1600 }
1601 else // The rest of the combinations
1602 {
1603 // Auto-reconnect DIP-switch
1604 if (HAL_GPIO_ReadPin(DIP3_GPIO_Port, DIP3_Pin) == DIP_IS_ON)
1605 {
1606 // Modus 4 (LVP & OVP. Active level - LOW. With autoreconnect)
1607 LOG_I(TAG, "Illegal Mode is selected. Default Mode 4 is selected. Auto-reconnect is ON.");
1608
1609 AUTO_Mode = &AUTO_LVP_OVP_Management;
1610 // Assigning default functions to function pointers array, depending on LVP and OVP events combinations
1611 LVP_OVP[0] = &OVP_not_present__LVP_not_present; // 00 - 0
1612 LVP_OVP[1] = &OVP_not_present__LVP_present; // 01 - 1
1613 LVP_OVP[2] = &OVP_present__LVP_not_present; // 10 - 2
1614 LVP_OVP[3] = &OVP_present__LVP_present; // 11 - 3
1615 LVP_OVP_logic = LOGIC_NEGATIV;
1616 sys_data.s.dip_mode = 4 | (1 << 3);
1617 }
1618 else
1619 {
1620 // Modus 4 (LVP & OVP. Active level - LOW. Without autoreconnect)
1621 LOG_I(TAG, "Illegal Mode is selected. Default Mode 4 is selected. Auto-reconnect is OFF.");
1622
1623 AUTO_Mode = &LVP_OVP_Management_NoAutoreconnect;
1624 // Assigning default functions to function pointers array, depending on LVP and OVP events combinations
1625 LVP_OVP[0] = &OVP_not_present__LVP_not_present; // 00 - 0
1626 LVP_OVP[1] = &OVP_not_present__LVP_present; // 01 - 1
1627 LVP_OVP[2] = &OVP_present__LVP_not_present; // 10 - 2
1628 LVP_OVP[3] = &OVP_present__LVP_present; // 11 - 3
1629 LVP_OVP_logic = LOGIC_NEGATIV;
1630 sys_data.s.dip_mode = 4;
1631 }
1632 }
1633
1634 if (HAL_GPIO_ReadPin(DIP4_GPIO_Port, DIP4_Pin) == DIP_IS_ON)
1635 {
1636 manual_overdrive_is_enabled = 1; // Manual overdrive
1637 sys_data.s.dip_mode |= (1 << 4);
1638 }
1639 else manual_overdrive_is_enabled = 0;
1640
1641 if (HAL_GPIO_ReadPin(DIP5_GPIO_Port, DIP5_Pin) == DIP_IS_ON)
1642 {
1643 auto_recover_from_temp_shutdown_is_enabled = 1;
1644 sys_data.s.dip_mode |= (1 << 5);
1645 }
1646 else auto_recover_from_temp_shutdown_is_enabled = 0;
1647
1648
1649 // At the end of this function we can DeInit all these ports
1650 // to minimize power consumption
1651
1652 HAL_GPIO_DeInit(DIP0_GPIO_Port, DIP0_Pin);
1653 HAL_GPIO_DeInit(DIP1_GPIO_Port, DIP1_Pin);
1654 HAL_GPIO_DeInit(DIP2_GPIO_Port, DIP2_Pin);
1655 HAL_GPIO_DeInit(DIP3_GPIO_Port, DIP3_Pin);
1656 HAL_GPIO_DeInit(DIP4_GPIO_Port, DIP4_Pin);
1657 HAL_GPIO_DeInit(DIP5_GPIO_Port, DIP5_Pin);
1658 HAL_GPIO_DeInit(DIP6_GPIO_Port, DIP6_Pin);
1659 HAL_GPIO_DeInit(DIP7_GPIO_Port, DIP7_Pin);
1660}
1661
1662//------------------------------------------------------------------------------
1663
1664void OVP_Management_NoAutoreconnect(uint32_t new_time, int reset)
1665{
1666 static void (*WhatToDo[LVP_OVP_EVENT_NUM>>1])(void);
1667 static const uint32_t newEventDelay[LVP_OVP_EVENT_NUM>>1] = {10, 3000}; // Delays in ms for LVP events
1668 static const uint32_t repeatEventDelay[LVP_OVP_EVENT_NUM>>1] = {1, 100}; // Delays in ms for repeating LVP events
1669 static uint32_t OVP_SCAN_PERIOD = 1;
1670 static uint32_t ovp_last_time_checked = 0;
1671 static int lastIdx = -1; // Impossible index, to make initial assignment
1672
1673 // This helps to reinitialize AUTO mode when exiting OFF mode with button or modbus
1674 if (reset) { lastIdx = -1; return; }
1675
1676 if (new_time - ovp_last_time_checked > OVP_SCAN_PERIOD)
1677 {
1678 // Saving time
1679 ovp_last_time_checked = new_time;
1680
1681 // Reading the state of LVP pin
1682 GPIO_PinState current_OVP_state = HAL_GPIO_ReadPin(OVP_IN_GPIO_Port, OVP_IN_Pin);
1683 if (LVP_OVP_logic == LOGIC_POSITIV) current_OVP_state = !current_OVP_state;
1684
1685 // Creating index from LVP values: 0 and 1
1686 int Idx = current_OVP_state;
1687
1688 // If new value of LVP sygnal differs from old one, then we must update our function pointer
1689 if (Idx > lastIdx)
1690 {
1691 WhatToDo[Idx] = LVP_OVP[Idx];
1692 // When state of LVP changes, we introduce a delay, "debouncing"
1693 OVP_SCAN_PERIOD = newEventDelay[Idx];
1694 }
1695 else
1696 {
1697 WhatToDo[Idx] = &DoNothing;
1698 // When previous state is the same like current, then we do nothing with slower rate
1699 OVP_SCAN_PERIOD = repeatEventDelay[Idx];
1700 }
1701
1702 // Depending on the state of the LVP pin, calling specific function, periodically
1703 WhatToDo[Idx]();
1704 lastIdx = Idx;
1705 }
1706}
1707
1708//------------------------------------------------------------------------------
1709
1710void AUTO_OVP_Management(uint32_t new_time, int reset)
1711{
1712 static void (*WhatToDo[LVP_OVP_EVENT_NUM>>1])(void);
1713 static const uint32_t newEventDelay[LVP_OVP_EVENT_NUM>>1] = {10, 3000}; // Delays in ms for LVP events
1714 static const uint32_t repeatEventDelay[LVP_OVP_EVENT_NUM>>1] = {1, 100}; // Delays in ms for repeating LVP events
1715 static uint32_t OVP_SCAN_PERIOD = 1;
1716 static uint32_t ovp_last_time_checked = 0;
1717 static unsigned int lastIdx = 2; // Impossible index, to make initial assignment
1718
1719 // This helps to reinitialize AUTO mode when exiting OFF mode with button or modbus
1720 if (reset)
1721 {
1722 lastIdx = 2;
1723 return;
1724 }
1725
1726 if (new_time - ovp_last_time_checked > OVP_SCAN_PERIOD)
1727 {
1728 // Saving time
1729 ovp_last_time_checked = new_time;
1730
1731 // Reading the state of LVP pin
1732 GPIO_PinState current_OVP_state = HAL_GPIO_ReadPin(OVP_IN_GPIO_Port, OVP_IN_Pin);
1733 if (LVP_OVP_logic == LOGIC_POSITIV) current_OVP_state = !current_OVP_state;
1734
1735 // Creating index from LVP values: 0 and 1
1736 unsigned int Idx = current_OVP_state;
1737
1738 // If new value of LVP sygnal differs from old one, then we must update our function pointer
1739 if (Idx != lastIdx)
1740 {
1741 WhatToDo[Idx] = LVP_OVP[Idx];
1742 // When state of LVP changes, we introduce a delay, "debouncing"
1743 OVP_SCAN_PERIOD = newEventDelay[Idx];
1744 }
1745 else
1746 {
1747 WhatToDo[Idx] = &DoNothing;
1748 // When previous state is the same like current, then we do nothing with slower rate
1749 OVP_SCAN_PERIOD = repeatEventDelay[Idx];
1750 }
1751
1752 // Depending on the state of the LVP pin, calling specific function, periodically
1753 WhatToDo[Idx]();
1754 lastIdx = Idx;
1755 }
1756}
1757
1758//------------------------------------------------------------------------------
1759
1760void LVP_Management_NoAutoreconnect(uint32_t new_time, int reset)
1761{
1762 static void (*WhatToDo[LVP_OVP_EVENT_NUM>>1])(void);
1763 static const uint32_t newEventDelay[LVP_OVP_EVENT_NUM>>1] = {10, 3000}; // Delays in ms for LVP events
1764 static const uint32_t repeatEventDelay[LVP_OVP_EVENT_NUM>>1] = {1, 100}; // Delays in ms for repeating LVP events
1765 static uint32_t LVP_SCAN_PERIOD = 1;
1766 static uint32_t lvp_last_time_checked = 0;
1767 static int lastIdx = -1; // Impossible index, to make initial assignment
1768
1769 // This helps to reinitialize AUTO mode when exiting OFF mode with button or modbus
1770 if (reset)
1771 {
1772 lastIdx = -1;
1773 return;
1774 }
1775
1776 if (new_time - lvp_last_time_checked > LVP_SCAN_PERIOD)
1777 {
1778 // Saving time
1779 lvp_last_time_checked = new_time;
1780
1781 // Reading the state of LVP pin
1782 GPIO_PinState current_LVP_state = HAL_GPIO_ReadPin(LVP_IN_GPIO_Port, LVP_IN_Pin);
1783 if (LVP_OVP_logic == LOGIC_POSITIV) current_LVP_state = !current_LVP_state;
1784
1785 // Creating index from LVP values: 0 and 1
1786 int Idx = current_LVP_state;
1787
1788 // If new value of LVP sygnal differs from old one, then we must update our function pointer
1789 if (Idx > lastIdx)
1790 {
1791 WhatToDo[Idx] = LVP_OVP[Idx];
1792 // When state of LVP changes, we introduce a delay, "debouncing"
1793 LVP_SCAN_PERIOD = newEventDelay[Idx];
1794 }
1795 else
1796 {
1797 WhatToDo[Idx] = &DoNothing;
1798 // When previous state is the same like current, then we do nothing with slower rate
1799 LVP_SCAN_PERIOD = repeatEventDelay[Idx];
1800 }
1801
1802 // Depending on the state of the LVP pin, calling specific function, periodically
1803 WhatToDo[Idx]();
1804 lastIdx = Idx;
1805 }
1806}
1807
1808//------------------------------------------------------------------------------
1809
1810void AUTO_LVP_Management(uint32_t new_time, int reset)
1811{
1812 static void (*WhatToDo[LVP_OVP_EVENT_NUM>>1])(void);
1813 static const uint32_t newEventDelay[LVP_OVP_EVENT_NUM>>1] = {10, 3000}; // Delays in ms for LVP events
1814 static const uint32_t repeatEventDelay[LVP_OVP_EVENT_NUM>>1] = {1, 100}; // Delays in ms for repeating LVP events
1815 static uint32_t LVP_SCAN_PERIOD = 1;
1816 static uint32_t lvp_last_time_checked = 0;
1817 static unsigned int lastIdx = 2; // Impossible index, to make initial assignment
1818
1819 // This helps to reinitialize AUTO mode when exiting OFF mode with button or modbus
1820 if (reset)
1821 {
1822 lastIdx = 2;
1823 return;
1824 }
1825
1826 if (new_time - lvp_last_time_checked > LVP_SCAN_PERIOD)
1827 {
1828 // Saving time
1829 lvp_last_time_checked = new_time;
1830
1831 // Reading the state of LVP pin
1832 GPIO_PinState current_LVP_state = HAL_GPIO_ReadPin(LVP_IN_GPIO_Port, LVP_IN_Pin);
1833 if (LVP_OVP_logic == LOGIC_POSITIV) current_LVP_state = !current_LVP_state;
1834
1835 // Creating index from LVP values: 0 and 1
1836 unsigned int Idx = current_LVP_state;
1837
1838 // If new value of LVP sygnal differs from old one, then we must update our function pointer
1839 if (Idx != lastIdx)
1840 {
1841 WhatToDo[Idx] = LVP_OVP[Idx];
1842 // When state of LVP changes, we introduce a delay, "debouncing"
1843 LVP_SCAN_PERIOD = newEventDelay[Idx];
1844 }
1845 else
1846 {
1847 WhatToDo[Idx] = &DoNothing;
1848 // When previous state is the same like current, then we do nothing with slower rate
1849 LVP_SCAN_PERIOD = repeatEventDelay[Idx];
1850 }
1851
1852 // Depending on the state of the LVP pin, calling specific function, periodically
1853 WhatToDo[Idx]();
1854 lastIdx = Idx;
1855 }
1856}
1857
1858//------------------------------------------------------------------------------
1859
1860void LVP_OVP_Management_NoAutoreconnect(uint32_t new_time, int reset)
1861{
1862 static void (*WhatToDo[LVP_OVP_EVENT_NUM])(void);
1863 static const uint32_t newEventDelay[LVP_OVP_EVENT_NUM] = {10, 3000, 3000, 3000}; // Delays in ms for new LVP&OVP combination events
1864 static const uint32_t repeatEventDelay[LVP_OVP_EVENT_NUM] = {1, 100, 100, 100}; // Delays in ms for repeating LVP&OVP combination events
1865 static uint32_t LVP_OVP_SCAN_PERIOD = 1;
1866 static uint32_t lvp_ovp_last_time_checked = 0;
1867 static int lastIdx = -1; // Impossible index, to make initial assignment
1868 static int ovp_lvp_flag = 0;
1869
1870 // This helps to reinitialize AUTO mode when exiting OFF mode with button or modbus
1871 if (reset)
1872 {
1873 lastIdx = -1;
1874 ovp_lvp_flag = 0;
1875 return;
1876 }
1877
1878 if (new_time - lvp_ovp_last_time_checked > LVP_OVP_SCAN_PERIOD)
1879 {
1880 // Saving time
1881 lvp_ovp_last_time_checked = new_time;
1882
1883 // Reading the states of OVP&LVP pins
1884 GPIO_PinState current_OVP_state = HAL_GPIO_ReadPin(OVP_IN_GPIO_Port, OVP_IN_Pin);
1885 GPIO_PinState current_LVP_state = HAL_GPIO_ReadPin(LVP_IN_GPIO_Port, LVP_IN_Pin);
1886 if (LVP_OVP_logic == LOGIC_POSITIV)
1887 {
1888 current_OVP_state = !current_OVP_state;
1889 current_LVP_state = !current_LVP_state;
1890 }
1891
1892 // Creating index from OVP and LVP values combinations: 0, 1, 2 and 3
1893 int Idx = (current_OVP_state << 1) | current_LVP_state;
1894
1895 // Checking previous combination of OVP&LVP
1896 if (Idx != lastIdx)
1897 {
1898 if (!ovp_lvp_flag)
1899 {
1900 if (Idx > 0) ovp_lvp_flag = 1;
1901
1902 WhatToDo[Idx] = LVP_OVP[Idx];
1903 // When states of OVP&LVP changes, we introduce a delay, "debouncing"
1904 LVP_OVP_SCAN_PERIOD = newEventDelay[Idx];
1905 }
1906 }
1907 else
1908 {
1909 WhatToDo[Idx] = &DoNothing;
1910 // When previous state is the same like current, then we do nothing with slower rate
1911 LVP_OVP_SCAN_PERIOD = repeatEventDelay[Idx];
1912 }
1913
1914 // Depending on the combination of the OVP and LVP states, calling specific function, periodically
1915 if (WhatToDo[Idx]) WhatToDo[Idx]();
1916 lastIdx = Idx;
1917 }
1918}
1919
1920//------------------------------------------------------------------------------
1921
1922void AUTO_LVP_OVP_Management(uint32_t new_time, int reset)
1923{
1924 static void (*WhatToDo[LVP_OVP_EVENT_NUM])(void);
1925 static const uint32_t newEventDelay[LVP_OVP_EVENT_NUM] = {10, 3000, 3000, 3000}; // Delays in ms for new LVP&OVP combination events
1926 static const uint32_t repeatEventDelay[LVP_OVP_EVENT_NUM] = {1, 100, 100, 100}; // Delays in ms for repeating LVP&OVP combination events
1927 static uint32_t LVP_OVP_SCAN_PERIOD = 1;
1928 static uint32_t lvp_ovp_last_time_checked = 0;
1929 static unsigned int lastIdx = 4; // Impossible index, to make initial assignment
1930
1931 // This helps to reinitialize AUTO mode when exiting OFF mode with button or modbus
1932 if (reset)
1933 {
1934 lastIdx = 4;
1935 return;
1936 }
1937
1938 if (new_time - lvp_ovp_last_time_checked > LVP_OVP_SCAN_PERIOD)
1939 {
1940 // Saving time
1941 lvp_ovp_last_time_checked = new_time;
1942
1943 // Reading the states of OVP&LVP pins
1944 GPIO_PinState current_OVP_state = HAL_GPIO_ReadPin(OVP_IN_GPIO_Port, OVP_IN_Pin);
1945 GPIO_PinState current_LVP_state = HAL_GPIO_ReadPin(LVP_IN_GPIO_Port, LVP_IN_Pin);
1946 if (LVP_OVP_logic == LOGIC_POSITIV)
1947 {
1948 current_OVP_state = !current_OVP_state;
1949 current_LVP_state = !current_LVP_state;
1950 }
1951
1952 // Creating index from OVP and LVP values combinations: 0, 1, 2 and 3
1953 unsigned int Idx = (current_OVP_state << 1) | current_LVP_state;
1954
1955 // If new combination of OVP&LVP sygnals differ from old one, then we must update our function pointer
1956 if (Idx != lastIdx)
1957 {
1958 WhatToDo[Idx] = LVP_OVP[Idx];
1959 // When states of OVP&LVP changes, we introduce a delay, "debouncing"
1960 LVP_OVP_SCAN_PERIOD = newEventDelay[Idx];
1961 }
1962 else
1963 {
1964 WhatToDo[Idx] = &DoNothing;
1965 // When previous state is the same like current, then we do nothing with slower rate
1966 LVP_OVP_SCAN_PERIOD = repeatEventDelay[Idx];
1967 }
1968
1969 // Depending on the combination of the OVP and LVP states, calling specific function, periodically
1970 WhatToDo[Idx]();
1971 lastIdx = Idx;
1972 }
1973}
1974
1975//------------------------------------------------------------------------------
1976static uint32_t last_time_started = 0;
1977
1978void StartAutoMode(void)
1979{
1980
1981 uint32_t current_time = HAL_GetTick();
1982
1983 // Checking whether we are already in this mode
1984 if ((sys_data.s.user_button_mode != SWITCH_AUTO) && (sys_data.s.user_button_mode != SWITCH_ON))
1985 {
1986 // We should not allow to start this mode very often
1987 if (current_time - last_time_started > 1000)
1988 {
1989 if ((current_time - overload_shutdown_time > 10000) && (current_time - overcurrent_shutdown_time > 10000))
1990 {
1991 HAL_TIM_Base_Stop_IT(&ON_MODE_AUTO_OFF_TIMER);
1992 last_time_started = current_time;
1993
1994 // Turning VBOOST voltage generator on
1995 //HAL_GPIO_WritePin(DISABLE_VBOOST_GPIO_Port, DISABLE_VBOOST_Pin, GPIO_PIN_SET);
1996
1997 // After 250ms of VBOOST stabilization time, we turn on MOSFETs regulation
1998 //HAL_TIM_Base_Stop_IT(&VBOOST_ON_TIMER);
1999 __HAL_TIM_CLEAR_FLAG(&VBOOST_ON_TIMER, TIM_FLAG_UPDATE);
2000 __HAL_TIM_SET_COUNTER(&VBOOST_ON_TIMER, 0);
2001 HAL_TIM_Base_Start_IT(&VBOOST_ON_TIMER);
2002
2003 //CLEAR_BIT(&hadc1->State, HAL_ADC_STATE_AWD2);
2004 //CLEAR_BIT(&hadc1->State, HAL_ADC_STATE_AWD3);
2005
2006#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
2007 //__HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_AWD2);
2008 //__HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_AWD3);
2009 //NVIC_ClearPendingIRQ(ADC1_COMP_IRQn);
2010 HAL_NVIC_EnableIRQ(ADC1_COMP_IRQn);
2011#endif
2012
2013 sys_data.s.switch_cnt++;
2014 statDataChanged = 1;
2015 //HAL_GPIO_WritePin(FET_PULLDOWN_A_GPIO_Port, FET_PULLDOWN_A_Pin, GPIO_PIN_RESET);
2016 //HAL_GPIO_WritePin(FET_PULLDOWN_B_GPIO_Port, FET_PULLDOWN_B_Pin, GPIO_PIN_RESET);
2017 }
2018 }
2019 }
2020}
2021
2022//------------------------------------------------------------------------------
2023
2024void StartOffMode(int reset)
2025{
2026 uint32_t current_time = HAL_GetTick();
2027
2028 // Checking whether we are allowed to enter this mode
2029 //if ((sys_data.s.user_button_mode == SWITCH_ON) || (sys_data.s.user_button_mode == SWITCH_AUTO) || reset)
2030 //{
2031 if ((current_time - last_time_started > 500) || reset)
2032 {
2033 HAL_TIM_Base_Stop_IT(&ON_MODE_AUTO_OFF_TIMER);
2034 if (sys_data.s.user_button_mode != SWITCH_OFF) last_time_started = current_time;
2035
2036 sys_data.s.user_button_mode = SWITCH_OFF;
2037
2038#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
2039 DisableShortCutDetection();
2040#endif
2041 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2042 MOSFETS_Management = &ADC_Open_Both_MOSFETs;
2043 sys_data.s.relay_status = RELAY_IS_OPENED;
2044 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2045
2046 ExternalGreenLED_Management = &TurnExternalGreenLEDOff;
2047 ExternalRedLED_Management = &TurnExternalRedLEDOff;
2048 InternalGreenLED_Management = &TurnGreenLEDOff;
2049
2050 // After 100ms we turn off VBOOST voltage for power saving
2051 //HAL_TIM_Base_Stop_IT(&VBOOST_OFF_TIMER);
2052 __HAL_TIM_CLEAR_FLAG(&VBOOST_OFF_TIMER, TIM_FLAG_UPDATE);
2053 __HAL_TIM_SET_COUNTER(&VBOOST_OFF_TIMER, 0);
2054 HAL_TIM_Base_Start_IT(&VBOOST_OFF_TIMER);
2055
2056#ifndef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
2057 __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_AWD2);
2058 __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_AWD3);
2059 NVIC_ClearPendingIRQ(ADC1_COMP_IRQn);
2060 HAL_NVIC_EnableIRQ(ADC1_COMP_IRQn);
2061#endif
2062
2063 overcurrent_shutdown_is_active = 0;
2064 overload_shutdown_is_active = 0;
2065 temperature_shutdown_is_active = 0;
2066 mosfets_voltagedrop_shutdown_is_active = 0;
2067
2068 sys_data.s.last_shortcut_during_charge = 0;
2069 sys_data.s.last_shortcut_during_discharge = 0;
2070 }
2071 //}
2072}
2073
2074//------------------------------------------------------------------------------
2075
2076void StartOnMode(void)
2077{
2078 //static uint32_t last_time_started = 0;
2079
2080 //uint32_t current_time = HAL_GetTick();
2081
2082 // Checking whether we are already in this mode
2083 if ((sys_data.s.user_button_mode != SWITCH_ON) && (sys_data.s.user_button_mode != SWITCH_AUTO))
2084 {
2085 if (manual_overdrive_is_enabled)
2086 {
2087 // We should not allow to start this mode very often
2088 //if (current_time - last_time_started > 3000)
2089 //{
2090 //last_time_started = current_time;
2091 last_time_started = HAL_GetTick();
2092
2093 //HAL_GPIO_WritePin(DISABLE_VBOOST_GPIO_Port, DISABLE_VBOOST_Pin, VBOOST_ENABLE);
2094
2095 // After 250ms of VBOOST stabilization time, we turn on MOSFETs On mode
2096 __HAL_TIM_CLEAR_FLAG(&htim6, TIM_FLAG_UPDATE);
2097 __HAL_TIM_SET_COUNTER(&htim6, 0);
2098 HAL_TIM_Base_Start_IT(&htim6);
2099
2100 // To prevent some unintentional damage to cells we turn this mode off after 1 minute
2101 __HAL_TIM_CLEAR_FLAG(&htim16, TIM_FLAG_UPDATE);
2102 __HAL_TIM_SET_COUNTER(&htim16, 0);
2103 HAL_TIM_Base_Start_IT(&htim16);
2104
2105 sys_data.s.switch_cnt++;
2106 statDataChanged = 1;
2107 //HAL_GPIO_WritePin(FET_PULLDOWN_A_GPIO_Port, FET_PULLDOWN_A_Pin, GPIO_PIN_RESET);
2108 //HAL_GPIO_WritePin(FET_PULLDOWN_B_GPIO_Port, FET_PULLDOWN_B_Pin, GPIO_PIN_RESET);
2109
2110 //sys_data.s.user_button_mode = SWITCH_ON;
2111
2112 // We disable shortcut detecting interrupt
2113 HAL_NVIC_DisableIRQ(ADC1_COMP_IRQn);
2114 //}
2115 }
2116 }
2117}
2118
2119//------------------------------------------------------------------------------
2120
2121void Keys_Management(void)
2122{
2123 static uint32_t last_time_checked = 0;
2124
2125 uint32_t current_time = HAL_GetTick();
2126
2127 if (current_time - last_time_checked >= 1)
2128 {
2129 last_time_checked = current_time;
2130 checkKeys();
2131
2132 if (get_key_short(SW_ON_Pin))
2133 {
2134 LOG_I(TAG, "UP button is pressed.");
2135 StartAutoMode();
2136 }
2137 else if (get_key_long(SW_ON_Pin))
2138 {
2139 LOG_I(TAG, "UP button is long-pressed.");
2140 StartOnMode();
2141 }
2142 else if (get_key_short(SW_OFF_Pin))
2143 {
2144 LOG_I(TAG, "DOWN button is pressed.");
2145 StartOffMode(0);
2146 }
2147 }
2148}
2149
2150//------------------------------------------------------------------------------
2151
2152static inline __attribute__((always_inline)) void CalculatingSwitchSideVoltage(void)
2153{
2154 static int32_t ubsensea_voltage_accum = 0;
2155
2156 // Calculatiing and averaging switch side voltage
2157 int32_t temp = ADC_values[U_SW_CHANNEL]; // Converting ADC value into int32_t type
2158 temp = (temp*ADC_VREF)>>ADC_RESOLUTION; // Getting voltage value on ADC input [0:3000]mV
2159#ifdef VARIANT_24V
2160 temp = (temp*(R19 + R20 + R27 + R26))/R26;
2161#else
2162 temp = (temp*(R25 + R24))/R24; // Getting voltage value on contact A [0:17100]mV
2163#endif
2164 ubsensea_voltage_accum -= sys_data.s.ubsensea_voltage;
2165 if (ubsensea_voltage_accum < 0) ubsensea_voltage_accum = 0;
2166 ubsensea_voltage_accum += temp;
2167 sys_data.s.ubsensea_voltage = ubsensea_voltage_accum / 8;
2168}
2169
2170//------------------------------------------------------------------------------
2171
2172inline __attribute__((always_inline)) void CalculatingMinMaxVoltagesForContactA(void)
2173{
2174 // Calculating MIN & MAX voltage values for contact A
2175 if (sys_data.s.ubsensea_voltage > sys_data.s.max_ubsensea_voltage) sys_data.s.max_ubsensea_voltage = sys_data.s.ubsensea_voltage;
2176 else if (sys_data.s.ubsensea_voltage < sys_data.s.min_ubsensea_voltage) sys_data.s.min_ubsensea_voltage = sys_data.s.ubsensea_voltage;
2177}
2178
2179//------------------------------------------------------------------------------
2180
2181static inline __attribute__((always_inline)) void CalculatingAndAveragingVoltageOnContactB(void)
2182{
2183 static int32_t ubsenseb_voltage_accum = U_BAT_RECOVERY_VOLTAGE * 32; // << ubsenseb_voltage_accum_avg;
2184
2185 // Calculating and averaging battery side voltage
2186 int32_t temp = ADC_values[U_BAT_CHANNEL]; // Converting ADC value into int32_t type
2187 temp = (temp*ADC_VREF)>>ADC_RESOLUTION; // Getting voltage value on ADC input [0:3000]mV
2188#ifdef VARIANT_24V
2189 temp = (temp*(R23 + R24 + R25 + R33))/R33; // Getting voltage value on contact B []mV
2190#else
2191 temp = (temp*(R23 + R22))/R22; // Getting voltage value on contact B [0:17100]mV
2192#endif
2193 ubsenseb_voltage_accum -= sys_data.s.ubsenseb_voltage;
2194 if (ubsenseb_voltage_accum < 0) ubsenseb_voltage_accum = 0;
2195 ubsenseb_voltage_accum += temp;
2196 sys_data.s.ubsenseb_voltage = ubsenseb_voltage_accum / 32; //>> ubsenseb_voltage_accum_avg;
2197}
2198
2199//------------------------------------------------------------------------------
2200
2201inline __attribute__((always_inline)) void TestingForLowVoltageShutdown(void)
2202{
2203 // If voltage on contact B is lower than critical one, then we must initiate "low voltage shutdown"
2204 if (sys_data.s.ubsenseb_voltage < U_BAT_CRITICAL_VOLTAGE)
2205 {
2206 if (low_bat_shutdown_is_active == 0)
2207 {
2208 low_bat_shutdown_is_active = 1;
2209 sys_data.s.device_status |= (1 << LOWBAT_ERROR);
2210 sys_data.s.lowbat_error_cnt++;
2211 statDataChanged = 1;
2212 }
2213 }
2214 else if (sys_data.s.ubsenseb_voltage > U_BAT_RECOVERY_VOLTAGE)
2215 {
2216 low_bat_shutdown_is_active = 0;
2217 sys_data.s.device_status &= ~(1 << LOWBAT_ERROR);
2218 }
2219}
2220
2221//------------------------------------------------------------------------------
2222
2223inline __attribute__((always_inline)) void CalculatingMinMaxVoltagesForContactB(void)
2224{
2225 // Calculating MIN & MAX voltage values for contact B
2226 if (sys_data.s.ubsenseb_voltage > sys_data.s.max_ubsenseb_voltage) sys_data.s.max_ubsenseb_voltage = sys_data.s.ubsenseb_voltage;
2227 else if (sys_data.s.ubsenseb_voltage < sys_data.s.min_ubsenseb_voltage) sys_data.s.min_ubsenseb_voltage = sys_data.s.ubsenseb_voltage;
2228}
2229
2230//------------------------------------------------------------------------------
2231
2232static inline __attribute__((always_inline)) void SettingNewValuesForShortcutDetection(int isEnabled)
2233{
2234 // Setting limits for analogue watchdog to catch overcurrent events
2235 static int16_t last_shortcut_current_in_mV = 0;
2236
2237 if (last_shortcut_current_in_mV != sys_data.s.shortcut_current_in_mV)
2238 {
2239 HAL_ADC_Stop_DMA(&hadc1);
2240
2241 // Compensating possible skin-effect
2242 // Shortcut current lower then 400A does not make much sense
2243 if (sys_data.s.shortcut_current_in_mV < sys_data.s.copper_v_drop) sys_data.s.shortcut_current_in_mV = sys_data.s.copper_v_drop;
2244 if (sys_data.s.shortcut_current_in_mV > ADC_VREF) sys_data.s.shortcut_current_in_mV = ADC_VREF;
2245
2246 //int32_t maxShortCutCurrent = (CONTROL_CURRENT_A * ADC_MAX_VALUE) / sys_data.s.copper_v_drop_adc;
2247 //if (compensatedShortcut_current > maxShortCutCurrent) compensatedShortcut_current = maxShortCutCurrent;
2248
2249 last_shortcut_current_in_mV = sys_data.s.shortcut_current_in_mV;
2250 // Refreshing shortcut detecting value for Analog Watchdog
2251 ADC_AnalogWDGConfTypeDef AnalogWDGConfig = {0};
2252
2253 AnalogWDGConfig.WatchdogNumber = ADC_ANALOGWATCHDOG_2;
2254 AnalogWDGConfig.WatchdogMode = ADC_ANALOGWATCHDOG_SINGLE_REG;
2255 AnalogWDGConfig.Channel = ADC_CHANNEL_2; // I+ current sensor
2256 AnalogWDGConfig.ITMode = (isEnabled)? ENABLE: DISABLE;
2257 AnalogWDGConfig.HighThreshold = (sys_data.s.shortcut_current_in_mV * ADC_MAX_VALUE)/ADC_VREF;
2258 AnalogWDGConfig.LowThreshold = 0x000;
2259 if (HAL_ADC_AnalogWDGConfig(&hadc1, &AnalogWDGConfig) != HAL_OK) Error_Handler();
2260
2261 AnalogWDGConfig.WatchdogNumber = ADC_ANALOGWATCHDOG_3;
2262 AnalogWDGConfig.WatchdogMode = ADC_ANALOGWATCHDOG_SINGLE_REG;
2263 AnalogWDGConfig.Channel = ADC_CHANNEL_6; // I- current sensor
2264 AnalogWDGConfig.ITMode = (isEnabled)? ENABLE: DISABLE;;
2265 AnalogWDGConfig.HighThreshold = (sys_data.s.shortcut_current_in_mV * ADC_MAX_VALUE)/ADC_VREF;
2266 //sys_data.s.reserved = AnalogWDGConfig.HighThreshold;
2267 AnalogWDGConfig.LowThreshold = 0x000;
2268 if (HAL_ADC_AnalogWDGConfig(&hadc1, &AnalogWDGConfig) != HAL_OK) Error_Handler();
2269
2270 if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_values, ADC_CHANNELS) != HAL_OK) LOG_E(TAG, "Cannot start ADC in DMA mode!");
2271 DMA1_Channel1->CCR &= ~DMA_CCR_HTIE; // Disabling Half-Transfer interrupt, because we don't need it
2272 }
2273}
2274
2275//------------------------------------------------------------------------------
2276
2277#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
2278
2279inline __attribute__((always_inline)) void DisableShortCutDetection(void)
2280{
2281 __HAL_ADC_DISABLE_IT(&hadc1, ADC_IT_AWD2);
2282 __HAL_ADC_DISABLE_IT(&hadc1, ADC_IT_AWD3);
2283 __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_AWD2);
2284 __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_AWD3);
2285
2286 // Switch-off process lasts approximately 1ms
2287 // We start this timer and in interrupt reactivate shortcut detection
2288 HAL_TIM_Base_Stop_IT(&htim15);
2289 __HAL_TIM_SetCounter(&htim15, 0);
2290 __HAL_TIM_CLEAR_FLAG(&htim15, TIM_IT_UPDATE);
2291 HAL_TIM_Base_Start_IT(&htim15);
2292
2293 //HAL_GPIO_WritePin(TP2_GPIO_Port, TP2_Pin, GPIO_PIN_SET);
2294}
2295
2296//------------------------------------------------------------------------------
2297
2298inline __attribute__((always_inline)) void EnableShortCutDetection(void)
2299{
2300 __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_AWD2);
2301 __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_AWD3);
2302 __HAL_ADC_ENABLE_IT(&hadc1, ADC_IT_AWD2);
2303 __HAL_ADC_ENABLE_IT(&hadc1, ADC_IT_AWD3);
2304
2305 //HAL_GPIO_WritePin(TP2_GPIO_Port, TP2_Pin, GPIO_PIN_RESET);
2306}
2307
2308#endif
2309
2310//------------------------------------------------------------------------------
2311
2312void HeavyCalculations(uint32_t current_time)
2313{
2314 static uint32_t heavy_calc_last_time = 0;
2315 static uint32_t HEAVY_CALCULATIONS_PERIOD = 3000;
2316 static int32_t temperature_accum = 0;
2317 int current_temperature;
2318 //static int32_t prev_ursense_voltage = 0;
2319 //int const ubsenseb_voltage_accum_avg = 5;
2320 //int const ubsensea_voltage_accum_avg = 4;
2321
2322 static int64_t ubbsense_voltage_accum = 0;
2323
2324
2325 // During first start, somtimes we read 0s from ADC, so we need to wait for a while before calculating Min & Max values, especially Min values
2326 if (current_time - heavy_calc_last_time > HEAVY_CALCULATIONS_PERIOD)
2327 {
2328 heavy_calc_last_time = current_time;
2329 HEAVY_CALCULATIONS_PERIOD = 135;
2330
2331 CalculatingSwitchSideVoltage();
2332
2333 CalculatingMinMaxVoltagesForContactA();
2334
2335 CalculatingAndAveragingVoltageOnContactB();
2336
2337 TestingForLowVoltageShutdown();
2338
2339 CalculatingMinMaxVoltagesForContactB();
2340
2341 // Sliding average calculation for board temperature
2342 current_temperature = (((MAX_TEMP - MIN_TEMP)*((int)ADC_values[TEMP_CHANNEL] - TEMP_SENSOR_ADC_AT_MINUS30))/(TEMP_SENSOR_ADC_AT_PLUS100 - TEMP_SENSOR_ADC_AT_MINUS30)) + MIN_TEMP;
2343 temperature_accum -= sys_data.s.temperature;
2344 temperature_accum += current_temperature;
2345 sys_data.s.temperature = temperature_accum / 32;//>> 5;
2346 //sys_data.s.temperature = current_temperature;
2347
2348 // Calculating MIN & MAX temperature values
2349 if (sys_data.s.temperature > sys_data.s.max_temperature) sys_data.s.max_temperature = sys_data.s.temperature;
2350 else if (sys_data.s.temperature < sys_data.s.min_temperature) sys_data.s.min_temperature = sys_data.s.temperature;
2351
2352 // If temperature is above critical then we initiate temperature shutdown
2353 if (sys_data.s.temperature >= sys_data.s.temperature_shutdown)
2354 {
2355 if (temperature_shutdown_is_active == 0)
2356 {
2357 temperature_shutdown_is_active = 1;
2358 sys_data.s.device_status |= (1 << OVERTEMP_ERROR);
2359 sys_data.s.overtemp_error_cnt++;
2360 statDataChanged = 1;
2361 }
2362 }
2363 else if (sys_data.s.temperature < (((100 - TEMP_RECOVER_PERCENT)*sys_data.s.temperature_shutdown)/100))
2364 {
2365 if (auto_recover_from_temp_shutdown_is_enabled)
2366 {
2367 temperature_shutdown_is_active = 0;
2368 sys_data.s.device_status &= ~(1 << OVERTEMP_ERROR);
2369 }
2370 }
2371
2372 if (overcurrent_shutdown_is_active == 1) sys_data.s.device_status |= (1 << OVERCURRENT_ERROR);
2373 else sys_data.s.device_status &= ~(1 << OVERCURRENT_ERROR);
2374
2375 if (overload_shutdown_is_active == 1) sys_data.s.device_status |= (1 << OVERLOAD_ERROR);
2376 else sys_data.s.device_status &= ~(1 << OVERLOAD_ERROR);
2377
2378 if (mosfets_voltagedrop_shutdown_is_active == 1) sys_data.s.device_status |= (1 << ABBA_VOLTAGE_ERROR);
2379 else sys_data.s.device_status &= ~(1 << ABBA_VOLTAGE_ERROR);
2380
2381 // Calculating MIN & MAX voltage drop
2382 if (sys_data.s.ursense_voltage < 0)
2383 {
2384 // Discharge
2385 if (-sys_data.s.ursense_voltage > sys_data.s.max_discharge_ursense_voltage) sys_data.s.max_discharge_ursense_voltage = -sys_data.s.ursense_voltage;
2386 else if (-sys_data.s.ursense_voltage < sys_data.s.min_discharge_ursense_voltage) sys_data.s.min_discharge_ursense_voltage = -sys_data.s.ursense_voltage;
2387 }
2388 else
2389 {
2390 // Charge
2391 if (sys_data.s.ursense_voltage > sys_data.s.max_charge_ursense_voltage) sys_data.s.max_charge_ursense_voltage = sys_data.s.ursense_voltage;
2392 else if (sys_data.s.ursense_voltage < sys_data.s.min_charge_ursense_voltage) sys_data.s.min_charge_ursense_voltage = sys_data.s.ursense_voltage;
2393 }
2394
2395 // Saving raw ADC value for voltage drop in special register
2396 sys_data.s.adc_plus_current_sensor = rawContactVoltageDropPlus;
2397 sys_data.s.adc_minus_current_sensor = rawContactVoltageDropMinus;
2398
2399 // Calculating averaged voltage drop on COPPER-plate on contact B
2400 static int32_t rawContactVoltageDropPlus_accum = 0;
2401 static int32_t rawContactVoltageDropMinus_accum = 0;
2402 static int32_t tmp_i_plus = 0;
2403 static int32_t tmp_i_minus = 0;
2404 const int32_t AVG = 16;
2405 rawContactVoltageDropPlus_accum -= tmp_i_plus;
2406 rawContactVoltageDropPlus_accum += rawContactVoltageDropPlus;
2407 tmp_i_plus = rawContactVoltageDropPlus_accum / AVG;
2408 rawContactVoltageDropMinus_accum -= tmp_i_minus;
2409 rawContactVoltageDropMinus_accum += rawContactVoltageDropMinus;
2410 tmp_i_minus = rawContactVoltageDropMinus_accum / AVG;
2411 uint32_t final_i_plus = (tmp_i_plus >= sys_data.s.i_plus_offset)? tmp_i_plus - sys_data.s.i_plus_offset: 0;
2412 uint32_t final_i_minus = (tmp_i_minus >= sys_data.s.i_minus_offset)? tmp_i_minus - sys_data.s.i_minus_offset: 0;
2413 int32_t rawContactVoltageDrop = final_i_plus - final_i_minus;
2414 sys_data.s.ubbsense_voltage = (rawContactVoltageDrop * ADC_VREF) / ADC_MAX_VALUE;
2415 sys_data.s.current = (rawContactVoltageDrop * CONTROL_CURRENT_A) / sys_data.s.copper_v_drop_adc;
2416 //SEGGER_RTT_printf(0, "Iadc+ = %u Iadc- = %u Iadc = %d Ubb = %d mV I = %d A\n", final_i_plus, final_i_minus, rawContactVoltageDrop, sys_data.s.ubbsense_voltage, sys_data.s.current);
2417
2418 if ((sys_data.s.relay_status == RELAY_IS_OPENED) && (InternalGreenLED_Management != &TurnGreenLEDOff)) InternalGreenLED_Management = &TurnGreenLEDOff;
2419 else if ((sys_data.s.relay_status == RELAY_IS_CLOSED) && (InternalGreenLED_Management != &TurnGreenLEDOn)) InternalGreenLED_Management = &TurnGreenLEDOn;
2420 else if (InternalGreenLED_Management != &GreenLEDShortBlinking) InternalGreenLED_Management = &GreenLEDShortBlinking;
2421
2422 GPIO_PinState current_OVP_state = HAL_GPIO_ReadPin(OVP_IN_GPIO_Port, OVP_IN_Pin);
2423 GPIO_PinState current_LVP_state = HAL_GPIO_ReadPin(LVP_IN_GPIO_Port, LVP_IN_Pin);
2424 if (LVP_OVP_logic == LOGIC_POSITIV)
2425 {
2426 //if (sys_data.s.lvp_state != 2)
2427 //{
2428 if (current_LVP_state == GPIO_PIN_SET) sys_data.s.lvp_state = 0;
2429 else sys_data.s.lvp_state = 1;
2430 //}
2431 //if (sys_data.s.ovp_state != 2)
2432 //{
2433 if (current_OVP_state == GPIO_PIN_SET) sys_data.s.ovp_state = 0;
2434 else sys_data.s.ovp_state = 1;
2435 //}
2436 }
2437 else
2438 {
2439 //if (sys_data.s.lvp_state != 2)
2440 //{
2441 if (current_LVP_state == GPIO_PIN_RESET) sys_data.s.lvp_state = 0;
2442 else sys_data.s.lvp_state = 1;
2443 //}
2444 //if (sys_data.s.ovp_state != 2)
2445 //{
2446 if (current_OVP_state == GPIO_PIN_RESET) sys_data.s.ovp_state = 0;
2447 else sys_data.s.ovp_state = 1;
2448 //}
2449 }
2450 //HAL_GPIO_TogglePin(OUT_CTRL_GPIO_Port, OUT_CTRL_Pin);
2451 // If voltage on contact A is greater than voltage on contact B, then we assume a charger presence
2452 // We allow a pre-heater to be turned on
2453 // when OVP sygnal is active - when battery is cold
2454 static int32_t heater_cnt = 0;
2455 if ((sys_data.s.relay_status == RELAY_IS_CLOSED) || (sys_data.s.relay_status == ONLY_BA_OPENED) || (sys_data.s.relay_status == ONLY_AB_OPENED))
2456 {
2457 if ((sys_data.s.ursense_voltage > BAT_CHARGE_SIGN_V))
2458 {
2459 HAL_GPIO_WritePin(OUT_CTRL_GPIO_Port, OUT_CTRL_Pin, OUT_CTRL_ACTIVATE);
2460 heater_cnt = 500;
2461 //if (sys_data.s.ovp_state == 1) HAL_GPIO_WritePin(OUT_CTRL_GPIO_Port, OUT_CTRL_Pin, GPIO_PIN_SET);
2462 //else HAL_GPIO_WritePin(OUT_CTRL_GPIO_Port, OUT_CTRL_Pin, GPIO_PIN_RESET);
2463 }
2464 else if (sys_data.s.ursense_voltage <= 0)
2465 {
2466 if (heater_cnt > 0) heater_cnt--;
2467 if (heater_cnt == 0) HAL_GPIO_WritePin(OUT_CTRL_GPIO_Port, OUT_CTRL_Pin, OUT_CTRL_DEACTIVATE);
2468 }
2469 }
2470 else HAL_GPIO_WritePin(OUT_CTRL_GPIO_Port, OUT_CTRL_Pin, OUT_CTRL_DEACTIVATE);
2471
2472 // Updating Inrush-Current value (A)
2473 static uint16_t last_inrush_max_current_in_mV = 0;
2474 if ((last_inrush_max_current_in_mV != sys_data.s.inrush_max_current_in_mV) && (sys_data.s.inrush_max_current_in_mV > sys_data.s.copper_v_drop))
2475 {
2476 if (sys_data.s.inrush_max_current_in_mV >= ADC_VREF) sys_data.s.inrush_max_current_in_mV = ADC_VREF;
2477
2478 last_inrush_max_current_in_mV = sys_data.s.inrush_max_current_in_mV;
2479 sys_data.s.inrush_max_current_in_adc = (sys_data.s.inrush_max_current_in_mV * ADC_MAX_VALUE) / ADC_VREF;
2480 maxIntegral = sys_data.s.inrush_max_current_in_adc * sys_data.s.inrush_curr_integral_steps;
2481 }
2482
2483 // Updating Inrush-Current period value (µs)
2484 static uint16_t last_inrush_curr_period = 0;
2485 if (last_inrush_curr_period != sys_data.s.inrush_curr_period)
2486 {
2487 if (sys_data.s.inrush_curr_period < 31) sys_data.s.inrush_curr_period = 31;
2488
2489 last_inrush_curr_period = sys_data.s.inrush_curr_period;
2490 sys_data.s.inrush_curr_integral_steps = (CURRENT_INTEGRAL_FREQ * sys_data.s.inrush_curr_period) / (1000*1000);
2491 maxIntegral = sys_data.s.inrush_max_current_in_adc * sys_data.s.inrush_curr_integral_steps;
2492 }
2493
2494 // Testing if there is a current on battery heater
2495 if (HAL_GPIO_ReadPin(OUT_CS_GPIO_Port, OUT_CS_Pin) == GPIO_PIN_SET) sys_data.s.heater_status = 1;
2496 else sys_data.s.heater_status = 0;
2497
2498 SettingNewValuesForShortcutDetection(1);
2499 }
2500}
2501
2502//------------------------------------------------------------------------------
2503
2504void DEBUG_print(uint32_t current_time)
2505{
2506 static uint32_t debug_print_old_time = 0;
2507
2508 if (current_time - debug_print_old_time > 77) // 77
2509 {
2510 //SEGGER_RTT_printf(0, "%4d\n", rawVoltageDrop);
2511 debug_print_old_time = current_time;
2512 const char* separator_color = RTT_CTRL_TEXT_BLACK;
2513 const char* values_color = RTT_CTRL_TEXT_BRIGHT_GREEN;
2514
2515 SEGGER_RTT_printf(0, "%s%s", values_color, TAG);
2516 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2517 SEGGER_RTT_printf(0, "Vab: %4d mV", sys_data.s.ursense_voltage);
2518 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2519 SEGGER_RTT_printf(0, "Vbb: %5d mV", sys_data.s.ubbsense_voltage);
2520 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2521 SEGGER_RTT_printf(0, "I: %5d A", sys_data.s.current);
2522 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2523 SEGGER_RTT_printf(0, "Va: %6d mV", sys_data.s.ubsensea_voltage);
2524 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2525 SEGGER_RTT_printf(0, "Vb: %6d mV", sys_data.s.ubsenseb_voltage);
2526 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2527 SEGGER_RTT_printf(0, "OVP: %1s", (sys_data.s.ovp_state == 0)? "N": RTT_CTRL_TEXT_RED"Y"RTT_CTRL_TEXT_BRIGHT_GREEN);
2528 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2529 SEGGER_RTT_printf(0, "LVP: %1s", (sys_data.s.lvp_state == 0)? "N": RTT_CTRL_TEXT_RED"Y"RTT_CTRL_TEXT_BRIGHT_GREEN);
2530 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2531 SEGGER_RTT_printf(0, "DAC_A: %4d", DAC_HANDLE.Instance->DAC_CH_A);
2532 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2533 SEGGER_RTT_printf(0, "DAC_B: %4d", DAC_HANDLE.Instance->DAC_CH_B);
2534 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2535 SEGGER_RTT_printf(0, "R: %s", (sys_data.s.relay_status == 0)? "OP": (sys_data.s.relay_status == 1)? "CL": (sys_data.s.relay_status == 2)? "BA": "AB");
2536 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2537 SEGGER_RTT_printf(0, "T: %2d.%d \260C", sys_data.s.temperature/10, abs(sys_data.s.temperature - (sys_data.s.temperature/10)*10) );
2538 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2539 if (sys_data.s.device_status & (1 << OVERTEMP_ERROR))
2540 {
2541 SEGGER_RTT_printf(0, "%s", RTT_CTRL_TEXT_BRIGHT_RED);
2542 SEGGER_RTT_printf(0, "%s", "OT");
2543 }
2544 else SEGGER_RTT_printf(0, "%s", "OT");
2545 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2546
2547 if (sys_data.s.device_status & (1 << OVERCURRENT_ERROR))
2548 {
2549 SEGGER_RTT_printf(0, "%s", RTT_CTRL_TEXT_BRIGHT_RED);
2550 SEGGER_RTT_printf(0, "%s", "OC");
2551 }
2552 else SEGGER_RTT_printf(0, "%s", "OC");
2553 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2554
2555 if (sys_data.s.device_status & (1 << OVERLOAD_ERROR))
2556 {
2557 SEGGER_RTT_printf(0, "%s", RTT_CTRL_TEXT_BRIGHT_RED);
2558 SEGGER_RTT_printf(0, "%s", "OL");
2559 }
2560 else SEGGER_RTT_printf(0, "%s", "OL");
2561 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2562
2563 if (sys_data.s.device_status & (1 << LOWBAT_ERROR))
2564 {
2565 SEGGER_RTT_printf(0, "%s", RTT_CTRL_TEXT_BRIGHT_RED);
2566 SEGGER_RTT_printf(0, "%s", "LB");
2567 }
2568 else SEGGER_RTT_printf(0, "%s", "LB");
2569 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2570
2571 if (sys_data.s.device_status & (1 << ABBA_VOLTAGE_ERROR))
2572 {
2573 SEGGER_RTT_printf(0, "%s", RTT_CTRL_TEXT_BRIGHT_RED);
2574 SEGGER_RTT_printf(0, "%s", "AB");
2575 }
2576 else SEGGER_RTT_printf(0, "%s", "AB");
2577 SEGGER_RTT_printf(0, "%s | %s", separator_color, values_color);
2578
2579 if (HAL_GPIO_ReadPin(OUT_CTRL_GPIO_Port, OUT_CTRL_Pin) == OUT_CTRL_ACTIVATE)
2580 {
2581 SEGGER_RTT_printf(0, "%s", RTT_CTRL_TEXT_BRIGHT_CYAN);
2582 SEGGER_RTT_printf(0, "%s", "CHG - 1");
2583 }
2584 else
2585 {
2586 SEGGER_RTT_printf(0, "%s", "CHG - 0");
2587 }
2588
2589 SEGGER_RTT_printf(0, "\n");
2590 }
2591}
2592
2593//------------------------------------------------------------------------------
2594
2595inline __attribute__((always_inline)) void MODBUS_Management(void)
2596{
2597 // Modbus Kommunikation
2598 if (mbGetFrameComplete(&modbusData))
2599 {
2600 if (mbSlaveCheckModbusRtuQuery(&modbusData) == RESPOND_TO_QUERY)
2601 {
2602 if (RS485ActiveMode)
2603 {
2604 mbSlaveProcessRtuQuery(&modbusData);
2605 }
2606 }
2607 else huart1.RxState = HAL_UART_STATE_BUSY_RX;
2608 }
2609
2610 // This code prevents unauthorized write-access to registers
2611 // Prüfe KEY
2612 if (sys_data.s.lockKey == savedLockKey)
2613 {
2614 sys_data.s.keyAccepted = 1;
2615 keyAccepted = 1;
2616 }
2617 else
2618 {
2619 sys_data.s.keyAccepted = 0;
2620 keyAccepted = 0;
2621 }
2622
2623 // Checking whether command parser is active or not
2624 if (command_parser_is_enabled)
2625 {
2626 // Checking command which came via Modbus
2627 if ((sys_data.s.command != 0) && (modbusData.current_query == MB_QUERY_NOTHING))
2628 {
2629 switch (sys_data.s.command)
2630 {
2631 case COMMAND_SAVE_CONFIG:
2632 // Saving new settings without SN in FLASH
2633 if (FEEPROM_storeConfig(&sys_data, 0)) LOG_E(TAG, "Cannot save data in FLASH memory!");
2634 // Fetching configuration from FLASH
2635 if (FEEPROM_readConfig(&sys_data)) LOG_E(TAG, "Cannot read configuration from FLASH memory!");
2636 //if (FEEPROM_ReadLogData(&sys_data)) LOG_E(TAG, "Cannot read statistcal data from FLASH memory!");
2637 break;
2638
2639 case COMMAND_SAVE_LOCK_KEY:
2640 LOG_I(TAG, "SAVE LOCK-KEY COMMAND.");
2641 mb_save_lock_key();
2642 break;
2643
2644 case COMMAND_RESTART_MODBUS:
2645 // Modbus Re-initialization
2646 if (sys_data.s.parity_mode == 'e') mbInit(&modbusData, sys_data.s.baudrate, MODBUS_UART_PARITY_EVEN, &huart1, accessModeTable, &keyAccepted);
2647 else if (sys_data.s.parity_mode == 'o') mbInit(&modbusData, sys_data.s.baudrate, MODBUS_UART_PARITY_ODD, &huart1, accessModeTable, &keyAccepted);
2648 else mbInit(&modbusData, sys_data.s.baudrate, MODBUS_UART_PARITY_NONE, &huart1, accessModeTable, &keyAccepted);
2649 break;
2650
2651 case COMMAND_RESTORE_DEFAULTS:
2652 if (FEEPROM_fullRestore(/*&sys_data*/)) LOG_E(TAG, "Cannot restore default settings from FLASH memory!");
2653 FEEPROM_ResetLogData();
2654 // Fetching configuration from FLASH
2655 if (FEEPROM_readConfig(&sys_data)) LOG_E(TAG, "Cannot read configuration from FLASH memory!");
2656 if (FEEPROM_ReadLogData(&sys_data)) LOG_E(TAG, "Cannot read statistcal data from FLASH memory!");
2657 break;
2658
2659 case COMMAND_ON_SWITCH: StartOnMode(); break;
2660
2661 case COMMAND_OFF_SWITCH: StartOffMode(0); break;
2662
2663 case COMMAND_AUTO_SWITCH: StartAutoMode(); break;
2664
2665 case COMMAND_SAVE_CONFIG_WITH_SN:
2666 // Saving new settings with new SN in FLASH
2667 if (FEEPROM_storeConfig(&sys_data, 1)) LOG_E(TAG, "Cannot save new SN in FLASH memory!");
2668 // Fetching configuration from FLASH
2669 if (FEEPROM_readConfig(&sys_data)) LOG_E(TAG, "Cannot read configuration from FLASH memory!");
2670 //if (FEEPROM_ReadLogData(&sys_data)) LOG_E(TAG, "Cannot read statistcal data from FLASH memory!");
2671 break;
2672
2673 case COMMAND_RESTART:
2674 OpenBothMOSFETSVeryFast();
2675 NVIC_SystemReset();
2676 break;
2677
2678 case COMMAND_OFFSET_CALIBRATION:
2679 if (Callibration == DoNothing) Callibration = &CallibrateVoltageDropABMiddlePointOffset;
2680 break;
2681
2682 case COMMAND_CURRENT_CALIBRATION:
2683 if (Callibration == DoNothing) Callibration = &CallibrateControlCurrentVoltageDropOnContactBB;
2684 break;
2685
2686 case COMMAND_CURRENT_OFFSET_CALIBRATION:
2687 if (Callibration == DoNothing) Callibration = &CallibrateCurrentSensorZeroOffsetOnContactBB;
2688 break;
2689
2690 case COMMAND_TURN_OVERLOAD_DETECTION_OFF:
2691 InrushCurrentManagement = &DoNothing;
2692 break;
2693
2694 case COMMAND_TURN_OVERLOAD_DETECTION_ON:
2695 InrushCurrentManagement = &InrushCurrentDetected;
2696 break;
2697
2698 default:
2699 // When we recieve some unknown command we freeze our command parser for 10 sec (to prevent bruteforce).
2700 __HAL_TIM_CLEAR_FLAG(&htim17, TIM_FLAG_UPDATE);
2701 __HAL_TIM_SET_COUNTER(&htim17, 0);
2702 if (HAL_TIM_Base_Start_IT(&htim17) != HAL_OK) LOG_E(TAG, "Cannot start TIM17 in ISR mode!");
2703 command_parser_is_enabled = 0;
2704 LOG_W(TAG, "Unknown command!");
2705 }
2706 sys_data.s.command = 0;
2707 }
2708 }
2709 else sys_data.s.command = 0;
2710}
2711
2712//------------------------------------------------------------------------------
2713
2714void OVP_not_present__LVP_ignored(void)
2715{
2716 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2717#ifdef INVERTER_CAP_PRECHARGE
2718 SetReturnFunction(&ADC_OVP_not_present__LVP_ignored);
2719 MOSFETS_Management = &PreChargeStage;
2720#else
2721 MOSFETS_Management = &ADC_OVP_not_present__LVP_ignored;
2722#endif
2723 sys_data.s.relay_status = RELAY_IS_CLOSED;
2724 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2725
2726 ExternalGreenLED_Management = &ExternalGreenLEDShortBlinking;
2727}
2728
2729//------------------------------------------------------------------------------
2730
2731void OVP_present__LVP_ignored(void)
2732{
2733#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
2734 DisableShortCutDetection();
2735#endif
2736 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2737 MOSFETS_Management = &ADC_OVP_present__LVP_ignored;
2738 sys_data.s.relay_status = RELAY_IS_OPENED;
2739 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2740
2741 ExternalGreenLED_Management = &ExternalGreenLEDShortBlinking;
2742 sys_data.s.ovp_cnt++;
2743 statDataChanged = 1;
2744}
2745
2746//------------------------------------------------------------------------------
2747
2748void OVP_present__LVP_ignored_NoAutoreconnect(void)
2749{
2750#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
2751 DisableShortCutDetection();
2752#endif
2753 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2754 MOSFETS_Management = &ADC_Open_Both_MOSFETs;
2755 sys_data.s.relay_status = RELAY_IS_OPENED;
2756 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2757
2758 sys_data.s.user_button_mode = SWITCH_OFF;
2759
2760 ExternalGreenLED_Management = &TurnExternalGreenLEDOff;
2761
2762 // After 100ms we turn off VBOOST voltage for power saving
2763 __HAL_TIM_CLEAR_FLAG(&VBOOST_OFF_TIMER, TIM_FLAG_UPDATE);
2764 __HAL_TIM_SET_COUNTER(&VBOOST_OFF_TIMER, 0);
2765 HAL_TIM_Base_Start_IT(&VBOOST_OFF_TIMER);
2766
2767 sys_data.s.ovp_cnt++;
2768 statDataChanged = 1;
2769}
2770
2771//------------------------------------------------------------------------------
2772
2773void OVP_ignored__LVP_not_present(void)
2774{
2775 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2776#ifdef INVERTER_CAP_PRECHARGE
2777 SetReturnFunction(&ADC_OVP_ignored__LVP_not_present);
2778 MOSFETS_Management = &PreChargeStage;
2779#else
2780 MOSFETS_Management = &ADC_OVP_ignored__LVP_not_present;
2781#endif
2782 sys_data.s.relay_status = RELAY_IS_CLOSED;
2783 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2784
2785 ExternalGreenLED_Management = &ExternalGreenLEDShortBlinking;
2786 //ExternalRedLED_Management = &TurnExternalRedLEDOff;
2787}
2788
2789//------------------------------------------------------------------------------
2790
2791void OVP_ignored__LVP_present(void)
2792{
2793#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
2794 DisableShortCutDetection();
2795#endif
2796 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2797 MOSFETS_Management = &ADC_OVP_ignored__LVP_present;
2798 sys_data.s.relay_status = RELAY_IS_OPENED;
2799 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2800
2801 ExternalGreenLED_Management = &ExternalGreenLEDShortBlinking;
2802 //ExternalRedLED_Management = &ExternalRedLEDShortBlinking;
2803
2804 sys_data.s.lvp_cnt++;
2805 statDataChanged = 1;
2806}
2807
2808//------------------------------------------------------------------------------
2809
2810void OVP_ignored__LVP_present_NoAutoreconnect(void)
2811{
2812#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
2813 DisableShortCutDetection();
2814#endif
2815 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2816 MOSFETS_Management = &ADC_Open_Both_MOSFETs;
2817 sys_data.s.relay_status = RELAY_IS_OPENED;
2818 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2819
2820 sys_data.s.user_button_mode = SWITCH_OFF;
2821
2822 ExternalGreenLED_Management = &TurnExternalGreenLEDOff;
2823
2824 // After 100ms we turn off VBOOST voltage for power saving
2825 __HAL_TIM_CLEAR_FLAG(&VBOOST_OFF_TIMER, TIM_FLAG_UPDATE);
2826 __HAL_TIM_SET_COUNTER(&VBOOST_OFF_TIMER, 0);
2827 HAL_TIM_Base_Start_IT(&VBOOST_OFF_TIMER);
2828
2829 sys_data.s.lvp_cnt++;
2830 statDataChanged = 1;
2831}
2832
2833//------------------------------------------------------------------------------
2834
2835void OVP_not_present__LVP_not_present(void)
2836{
2837 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2838#ifdef INVERTER_CAP_PRECHARGE
2839 SetReturnFunction(&ADC_OVP_not_present__LVP_not_present);
2840 MOSFETS_Management = &PreChargeStage;
2841#else
2842 MOSFETS_Management = &ADC_OVP_not_present__LVP_not_present;
2843#endif
2844 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2845 sys_data.s.relay_status = RELAY_IS_CLOSED;
2846
2847 ExternalGreenLED_Management = &ExternalGreenLEDShortBlinking;
2848 TurnExternalRedLEDOff();
2849}
2850
2851//------------------------------------------------------------------------------
2852
2853void OVP_not_present__LVP_present(void)
2854{
2855#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
2856 DisableShortCutDetection();
2857#endif
2858 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2859 MOSFETS_Management = &ADC_OVP_not_present__LVP_present;
2860 sys_data.s.relay_status = ONLY_AB_OPENED;
2861 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2862
2863 ExternalGreenLED_Management = &ExternalGreenLEDShortBlinking;
2864 TurnExternalRedLEDOff();
2865
2866 sys_data.s.lvp_cnt++;
2867 statDataChanged = 1;
2868}
2869
2870//------------------------------------------------------------------------------
2871
2872void OVP_present__LVP_not_present(void)
2873{
2874 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2875 MOSFETS_Management = &ADC_OVP_present__LVP_not_present;
2876 sys_data.s.relay_status = ONLY_BA_OPENED;
2877 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2878
2879 ExternalGreenLED_Management = &ExternalGreenLEDShortBlinking;
2880 TurnExternalRedLEDOff();
2881 //GreenLED_Management =
2882
2883 sys_data.s.ovp_cnt++;
2884 statDataChanged = 1;
2885}
2886
2887//------------------------------------------------------------------------------
2888
2889void OVP_present__LVP_present(void)
2890{
2891#ifdef DISABLE_SHORTCUT_DETECTION_DURING_SWITCH_OFF
2892 DisableShortCutDetection();
2893#endif
2894 HAL_NVIC_DisableIRQ(ADC_DMA_IRQ);
2895 MOSFETS_Management = &ADC_OVP_present__LVP_present;
2896 sys_data.s.relay_status = RELAY_IS_OPENED;
2897 HAL_NVIC_EnableIRQ(ADC_DMA_IRQ);
2898
2899 ExternalGreenLED_Management = &TurnExternalGreenLEDOff;
2900 ExternalRedLED_Management = &ExternalRedLED2ShortOnThen2LongOnThenLongPauseBlinking;
2901
2902 sys_data.s.lvp_cnt++;
2903 sys_data.s.ovp_cnt++;
2904 statDataChanged = 1;
2905}
2906
2907//------------------------------------------------------------------------------
2908
2909#ifdef USE_RAM_FUNC
2910__RAM_FUNC void ADC_OVP_present__LVP_ignored(void)
2911#else
2912void ADC_OVP_present__LVP_ignored(void)
2913#endif
2914{
2915 OpenBothMOSFETS();
2916}
2917
2918//------------------------------------------------------------------------------
2919#ifdef USE_RAM_FUNC
2920__RAM_FUNC void ADC_OVP_ignored__LVP_present(void)
2921#else
2922void ADC_OVP_ignored__LVP_present(void)
2923#endif
2924{
2925 OpenBothMOSFETS();
2926}
2927
2928//------------------------------------------------------------------------------
2929
2930#ifdef USE_RAM_FUNC
2931__RAM_FUNC void ADC_Open_Both_MOSFETs(void)
2932#else
2933void ADC_Open_Both_MOSFETs(void)
2934#endif
2935{
2936 OpenBothMOSFETS();
2937}
2938
2939//------------------------------------------------------------------------------
2940
2941#ifdef USE_RAM_FUNC
2942__RAM_FUNC void ADC_OVP_present__LVP_present(void)
2943#else
2944void ADC_OVP_present__LVP_present(void)
2945#endif
2946{
2947 OpenBothMOSFETS();
2948}
2949
2950//------------------------------------------------------------------------------
2951
2952#ifdef USE_RAM_FUNC
2953__RAM_FUNC void ADC_OVP_not_present__LVP_present(void)
2954#else
2955void ADC_OVP_not_present__LVP_present(void)
2956#endif
2957{
2958 // Reading current DAC value for MOSFET B
2959 uint32_t dacA_value = DAC_HANDLE.Instance->DAC_CH_A;
2960 // Checking voltage drop on MOSFETs
2961 if ((rawMOSFETsVoltageDrop + sys_data.s.ab_middle_point_offset) < POS_ALLOWED_MOSFETS_V_DROP_ADC)
2962 {
2963 if (dacA_value >= (DAC_0V + DAC_STEP)) dacA_value -= DAC_STEP;
2964 }
2965 else if ((rawMOSFETsVoltageDrop + sys_data.s.ab_middle_point_offset) > POS_ALLOWED_MOSFETS_V_DROP_ADC)
2966 {
2967 if (dacA_value <= (DAC_3V - DAC_STEP)) dacA_value += DAC_STEP;
2968 }
2969 // Writing DAC value for MOSFET B
2970 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_A_ALIGNMENT(DAC_ALIGN_12B_R)) = dacA_value;
2971
2972 // Reading DAC value for MOSFET channel A
2973 uint32_t dacB_value = DAC_HANDLE.Instance->DAC_CH_B;
2974 // We do not allow DAC value to be greater than max value
2975 if (dacB_value <= (DAC_3V - DAC_STEP)) dacB_value += DAC_STEP;
2976 // Sending new DAC value to DAC
2977 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_B_ALIGNMENT(DAC_ALIGN_12B_R)) = dacB_value;
2978}
2979
2980//------------------------------------------------------------------------------
2981
2982#ifdef USE_RAM_FUNC
2983__RAM_FUNC void ADC_OVP_present__LVP_not_present(void)
2984#else
2985void ADC_OVP_present__LVP_not_present(void)
2986#endif
2987{
2988 // Reading current DAC value for MOSFET B channel
2989 uint32_t dacB_value = DAC_HANDLE.Instance->DAC_CH_B;
2990 // Making sure that BA voltage drop during discharging is within the limit
2991 if ((rawMOSFETsVoltageDrop + sys_data.s.ab_middle_point_offset) < NEG_ALLOWED_MOSFETS_V_DROP_ADC)
2992 {
2993 if (dacB_value <= (DAC_3V - DAC_STEP)) dacB_value += DAC_STEP;
2994 }
2995 else if ((rawMOSFETsVoltageDrop + sys_data.s.ab_middle_point_offset) > NEG_ALLOWED_MOSFETS_V_DROP_ADC)
2996 {
2997 if (dacB_value >= (DAC_0V + DAC_STEP)) dacB_value -= DAC_STEP;
2998 }
2999 // Writing DAC value for MOSFET A channel
3000 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_B_ALIGNMENT(DAC_ALIGN_12B_R)) = dacB_value;
3001
3002 // Reading DAC value for MOSFET channel A
3003 uint32_t dacA_value = DAC_HANDLE.Instance->DAC_CH_A;
3004 // Channel A must be fully closed, so we increase smoothly DAC value
3005 // We do not allow DAC value to be greater than max value
3006 if (dacA_value <= (DAC_3V - DAC_STEP)) dacA_value += DAC_STEP;
3007 // Sending new DAC value to DAC
3008 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_A_ALIGNMENT(DAC_ALIGN_12B_R)) = dacA_value;
3009}
3010
3011//------------------------------------------------------------------------------
3012
3013#ifdef USE_RAM_FUNC
3014__RAM_FUNC void ADC_OVP_not_present__LVP_ignored(void)
3015#else
3016void ADC_OVP_not_present__LVP_ignored(void)
3017#endif
3018{
3019 CloseBothMOSFETS();
3020}
3021
3022//------------------------------------------------------------------------------
3023
3024#ifdef USE_RAM_FUNC
3025__RAM_FUNC void ADC_OVP_ignored__LVP_not_present(void)
3026#else
3027void ADC_OVP_ignored__LVP_not_present(void)
3028#endif
3029{
3030 CloseBothMOSFETS();
3031}
3032
3033//------------------------------------------------------------------------------
3034
3035#ifdef USE_RAM_FUNC
3036__RAM_FUNC void ADC_Close_Both_MOSFETs(void)
3037#else
3038void ADC_Close_Both_MOSFETs(void)
3039#endif
3040{
3041 CloseBothMOSFETS();
3042}
3043
3044//------------------------------------------------------------------------------
3045
3046#ifdef USE_RAM_FUNC
3047__RAM_FUNC void ADC_OVP_not_present__LVP_not_present(void)
3048#else
3049void ADC_OVP_not_present__LVP_not_present(void)
3050#endif
3051{
3052 CloseBothMOSFETS();
3053}
3054
3055//-----------------------------------------------------------------------------
3056
3057void CallibrateCurrentSensorZeroOffsetOnContactBB(void)
3058{
3059 // Assuming that load is not connected
3060
3061 uint32_t adc_value_accum_i_plus_channel = 0;
3062 uint32_t adc_value_accum_i_minus_channel = 0;
3063 const uint32_t SAMPLE_COUNT = 50000;
3064
3065 // Sampling N values
3066 for (int i = 0; i < SAMPLE_COUNT; i++)
3067 {
3068 // Calculating offsets on both current sensors
3069 adc_value_accum_i_plus_channel += rawContactVoltageDropPlus;
3070 adc_value_accum_i_minus_channel += rawContactVoltageDropMinus;
3071 SEGGER_RTT_printf(0, "\t[%4d] Sampled values: I+ = %6u I- = %6u\n", i, rawContactVoltageDropPlus, rawContactVoltageDropMinus);
3072 //SEGGER_RTT_printf(0, "%u,%u\n", ADC_values[I_PLUS_CHANNEL], ADC_values[I_MINUS_CHANNEL]);
3073 }
3074
3075 sys_data.s.i_plus_offset = adc_value_accum_i_plus_channel / SAMPLE_COUNT;
3076 sys_data.s.i_minus_offset = adc_value_accum_i_minus_channel / SAMPLE_COUNT;
3077 SEGGER_RTT_printf(0, "\t\tOffset values: I+ = %u I- = %u\n", sys_data.s.i_plus_offset, sys_data.s.i_minus_offset);
3078
3079 Callibration = &DoNothing;
3080}
3081
3082//------------------------------------------------------------------------------
3083
3084int32_t Rescale(int32_t x, int32_t x1, int32_t x2, int32_t y1, int32_t y2)
3085{
3086 int32_t res = ((y2 - y1) * (x - x1)) / (x2 - x1) + y1;
3087 return res;
3088}
3089
3090//------------------------------------------------------------------------------
3091
3092int32_t TemperatureCompensation(int32_t rawADCValueUnderMaxCurrent, int32_t temp_dGrad)
3093{
3094 if (temp_dGrad < 200) rawADCValueUnderMaxCurrent = (rawADCValueUnderMaxCurrent * (100 + 10)) / 100; // +10%
3095 else if (temp_dGrad >= 200 && temp_dGrad < 600) rawADCValueUnderMaxCurrent = (rawADCValueUnderMaxCurrent * (100 + Rescale(temp_dGrad, 200, 600, 10, 0))) / 100; // +[0%...10%]
3096 else if (temp_dGrad >= 600) rawADCValueUnderMaxCurrent = rawADCValueUnderMaxCurrent; // +0%
3097
3098 return rawADCValueUnderMaxCurrent;
3099}
3100
3101//-----------------------------------------------------------------------------
3102
3103void CallibrateControlCurrentVoltageDropOnContactBB(void)
3104{
3105 // Assuming that 500A load is connected
3106
3107 LOG_I(TAG, "Current callibration sequence started.");
3108
3109 // Turning off inrush current protection
3110 //InrushCurrentManagement = &DoNothing;
3111
3112 uint32_t start_time = HAL_GetTick();
3113 int32_t ubbsense_adc_accum = 0;
3114 int32_t ubbsense_adc = 0;
3115 int32_t ubbsense_voltage = 0;
3116
3117 while (HAL_GetTick() - start_time < 60000)
3118 {
3119 ubbsense_adc_accum -= ubbsense_adc;
3120 ubbsense_adc_accum += rawContactVoltageDropMinus;
3121 ubbsense_adc = ubbsense_adc_accum / 16;
3122
3123 SEGGER_RTT_printf(0, "\t\tVoltage-drop ADC value: %5d.\n", ubbsense_adc);
3124 HAL_Delay(1);
3125 }
3126
3127 ubbsense_adc -= sys_data.s.i_minus_offset;
3128 ubbsense_adc = TemperatureCompensation(ubbsense_adc, sys_data.s.temperature);
3129 ubbsense_voltage = (ubbsense_adc * ADC_VREF) / ADC_MAX_VALUE;
3130
3131 // Recording copper-plate voltage-drop under control current
3132 sys_data.s.copper_v_drop = ubbsense_voltage;
3133 // Recording ADC value drop under control current
3134 sys_data.s.copper_v_drop_adc = ubbsense_adc;
3135 sys_data.s.copper_v_drop_adc_limit = (sys_data.s.copper_v_drop_adc * 110) / 100;
3136
3137 SEGGER_RTT_printf(0, "\t\t\tFinal voltage-drop ADC value: %4u. Final voltage-drop value: %3u mV\n", sys_data.s.copper_v_drop_adc, sys_data.s.copper_v_drop);
3138
3139 // Updating inrush current settings
3140 //sys_data.s.inrush_max_current_in_adc = (sys_data.s.inrush_max_current * sys_data.s.copper_v_drop_adc) / CONTROL_CURRENT_A;
3141 //maxIntegral = sys_data.s.inrush_max_current_in_adc * sys_data.s.inrush_curr_integral_steps;
3142
3143 Callibration = &DoNothing;
3144 //InrushCurrentManagement = &InrushCurrentDetected; // Test program disables this, so we must re-enable it after callibration
3145}
3146
3147//-----------------------------------------------------------------------------
3148
3149void CallibrateVoltageDropABMiddlePointOffset(void)
3150{
3151 // Assuming that load is not connected
3152
3153 uint32_t adc_value_accum = 0;
3154 const uint32_t SAMPLE_COUNT = 50000;
3155
3156 // Sampling N values
3157 for (int i = 0; i < SAMPLE_COUNT; i++)
3158 {
3159 // Calculating averaged value for real voltage drop between contacts B and A in ADC values
3160 adc_value_accum += rawMOSFETsVoltageDrop;
3161 SEGGER_RTT_printf(0, "\t[%4d] Sampled value: %4d\n", i, rawMOSFETsVoltageDrop);
3162 }
3163
3164 sys_data.s.ab_middle_point_offset = (ADC_MAX_VALUE>>1) - (adc_value_accum / SAMPLE_COUNT);
3165 SEGGER_RTT_printf(0, "\t\tOffset value: %4d\n", sys_data.s.ab_middle_point_offset);
3166
3167 Callibration = &DoNothing;
3168}
3169
3170//------------------------------------------------------------------------------
3171
3172void InrushCurrentDetected(void)
3173{
3174 OpenBothMOSFETSVeryFast();
3175 MOSFETS_Management = &DoNothing;
3176
3177 if (overcurrent_shutdown_is_active == 0 )
3178 {
3179 if (overload_shutdown_is_active == 0)
3180 {
3181 sys_data.s.overload_error_cnt++;
3182 statDataChanged = 1;
3183 }
3184
3185 overload_shutdown_is_active = 1;
3186 overload_shutdown_time = HAL_GetTick();
3187 }
3188}
3189
3190//------------------------------------------------------------------------------
3191
3192inline __attribute__((always_inline)) void OpenBothMOSFETS(void)
3193{ // Reading DAC values for MOSFET channels A and B
3194 uint32_t dacA_value = DAC_HANDLE.Instance->DAC_CH_A;
3195 uint32_t dacB_value = DAC_HANDLE.Instance->DAC_CH_B;
3196
3197 // Opening MOSFETS
3198 if (dacA_value >= (DAC_0V + DAC_STEP)) dacA_value -= DAC_STEP;
3199 if (dacB_value >= (DAC_0V + DAC_STEP)) dacB_value -= DAC_STEP;
3200
3201 // Setting new values
3202 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_A_ALIGNMENT(DAC_ALIGN_12B_R)) = dacA_value;
3203 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_B_ALIGNMENT(DAC_ALIGN_12B_R)) = dacB_value;
3204}
3205
3206//------------------------------------------------------------------------------
3207
3208inline __attribute__((always_inline)) void CloseBothMOSFETS(void)
3209{
3210 // Reading DAC values for MOSFET channels A and B
3211 uint32_t dacA_value = DAC_HANDLE.Instance->DAC_CH_A;
3212 uint32_t dacB_value = DAC_HANDLE.Instance->DAC_CH_B;
3213
3214 // Closing MOSFETS
3215 if (dacA_value <= (DAC_3V - DAC_STEP)) dacA_value += DAC_STEP;
3216 if (dacB_value <= (DAC_3V - DAC_STEP)) dacB_value += DAC_STEP;
3217
3218 // Setting new values
3219 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_A_ALIGNMENT(DAC_ALIGN_12B_R)) = dacA_value;
3220 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_B_ALIGNMENT(DAC_ALIGN_12B_R)) = dacB_value;
3221}
3222
3223//------------------------------------------------------------------------------
3224
3225void CloseBothMOSFETSVeryFast(void)
3226{
3227 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_A_ALIGNMENT(DAC_ALIGN_12B_R)) = DAC_3V; // Expression from HAL_DAC_SetValue function
3228 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_B_ALIGNMENT(DAC_ALIGN_12B_R)) = DAC_3V; // Expression from HAL_DAC_SetValue function
3229 sys_data.s.relay_status = RELAY_IS_CLOSED;
3230}
3231
3232//------------------------------------------------------------------------------
3233
3234inline __attribute__((always_inline)) void OpenBothMOSFETSVeryFast(void)
3235{
3236 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_A_ALIGNMENT(DAC_ALIGN_12B_R)) = DAC_0V; // Expression from HAL_DAC_SetValue function
3237 *(__IO uint32_t *)((uint32_t)DAC_HANDLE.Instance + DAC_CH_B_ALIGNMENT(DAC_ALIGN_12B_R)) = DAC_0V; // Expression from HAL_DAC_SetValue function
3238 sys_data.s.relay_status = RELAY_IS_OPENED;
3239}
3240
3241//------------------------------------------------------------------------------
3242
3243void ShowSlaveAddressOnLED(uint16_t address, GPIO_TypeDef *port, uint16_t pin)
3244{
3245 for (int i = 0; i < address; i++)
3246 {
3247 HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET);
3248 HAL_Delay(333);
3249 HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET);
3250 HAL_Delay(333);
3251 }
3252}
3253
3254//------------------------------------------------------------------------------
3255
3256void StartUpSequence(void)
3257{
3258 HAL_GPIO_WritePin(LED_FUNCTION_GPIO_Port, LED_FUNCTION_Pin, GPIO_PIN_SET);
3259 HAL_GPIO_WritePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin, GPIO_PIN_SET);
3260 HAL_GPIO_WritePin(LED_STATE_GPIO_Port, LED_STATE_Pin, GPIO_PIN_SET);
3261
3262 HAL_Delay(1000);
3263
3264 HAL_GPIO_WritePin(LED_FUNCTION_GPIO_Port, LED_FUNCTION_Pin, GPIO_PIN_RESET);
3265 HAL_GPIO_WritePin(LED_ERROR_GPIO_Port, LED_ERROR_Pin, GPIO_PIN_RESET);
3266 HAL_GPIO_WritePin(LED_STATE_GPIO_Port, LED_STATE_Pin, GPIO_PIN_RESET);
3267
3268 HAL_Delay(500);
3269}
3270
3271//-----------------------------------------------------------------------------
3272#ifdef USE_RAM_FUNC
3273__RAM_FUNC void DoNothing(void)
3274#else
3275void DoNothing(void)
3276#endif
3277{
3278
3279}
3280
3281//-----------------------------------------------------------------------------
3282
3283/* USER CODE END 4 */
3284
3285/**
3286 * @brief This function is executed in case of error occurrence.
3287 * @retval None
3288 */
3289void Error_Handler(void)
3290{
3291 /* USER CODE BEGIN Error_Handler_Debug */
3292 /* User can add his own implementation to report the HAL error return state */
3293 LOG_E(TAG, "HAL error!");
3294 /* USER CODE END Error_Handler_Debug */
3295}
3296
3297#ifdef USE_FULL_ASSERT
3298/**
3299 * @brief Reports the name of the source file and the source line number
3300 * where the assert_param error has occurred.
3301 * @param file: pointer to the source file name
3302 * @param line: assert_param error line source number
3303 * @retval None
3304 */
3305void assert_failed(uint8_t *file, uint32_t line)
3306{
3307 /* USER CODE BEGIN 6 */
3308 /* User can add his own implementation to report the file name and line number,
3309 tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
3310 SEGGER_RTT_printf(0, "Wrong parameters value: file %s on line %d\n", file, line);
3311 /* USER CODE END 6 */
3312}
3313#endif /* USE_FULL_ASSERT */
Note: See TracBrowser for help on using the repository browser.