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

Last change on this file was 9, checked in by f.jahn, 2 years ago

Some minor bugfixes.

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