Statistics
| Branch: | Tag: | Revision:

amiro-blt / Target / Modules / PowerManagement_1-1 / Boot / main.c @ 2d379838

History | View | Annotate | Download (56.668 KB)

1 69661903 Thomas Schöpping
/************************************************************************************//**
2
* \file         Demo\ARMCM4_STM32_Olimex_STM32E407_GCC\Boot\main.c
3
* \brief        Bootloader application source file.
4
* \ingroup      Boot_ARMCM4_STM32_Olimex_STM32E407_GCC
5
* \internal
6
*----------------------------------------------------------------------------------------
7
*                          C O P Y R I G H T
8
*----------------------------------------------------------------------------------------
9
*   Copyright (c) 2013  by Feaser    http://www.feaser.com    All rights reserved
10
*
11
*----------------------------------------------------------------------------------------
12
*                            L I C E N S E
13
*----------------------------------------------------------------------------------------
14
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
15
* modify it under the terms of the GNU General Public License as published by the Free
16
* Software Foundation, either version 3 of the License, or (at your option) any later
17
* version.
18
*
19
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
20
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
21
* PURPOSE. See the GNU General Public License for more details.
22
*
23
* You should have received a copy of the GNU General Public License along with OpenBLT.
24
* If not, see <http://www.gnu.org/licenses/>.
25
*
26 470d0567 Thomas Schöpping
* A special exception to the GPL is included to allow you to distribute a combined work
27
* that includes OpenBLT without being obliged to provide the source code for any
28 69661903 Thomas Schöpping
* proprietary components. The exception text is included at the bottom of the license
29
* file <license.html>.
30 470d0567 Thomas Schöpping
*
31 69661903 Thomas Schöpping
* \endinternal
32
****************************************************************************************/
33
34
/****************************************************************************************
35
* Include files
36
****************************************************************************************/
37
#include "boot.h"                                /* bootloader generic header          */
38
#include "com.h"
39
#include "ARMCM4_STM32/types.h"
40 470d0567 Thomas Schöpping
#include "AMiRo/amiroblt.h"
41 2d379838 Thomas Schöpping
#include "helper.h"
42 09ad5212 Thomas Schöpping
#include "iodef.h"
43 69661903 Thomas Schöpping
44
/****************************************************************************************
45
* Defines
46
****************************************************************************************/
47
#define HIBERNATE_TIME_MS       5000
48
49
/****************************************************************************************
50
* Function prototypes and static variables
51
****************************************************************************************/
52
static void Init(void);
53
54
static void initGpio();
55
static void initExti();
56
void configGpioForShutdown();
57
void systemPowerDown();
58
59
ErrorStatus handleColdReset();
60
ErrorStatus handleSoftwareReset();
61
ErrorStatus handleUartDnWakeup();
62
ErrorStatus handlePathDcWakeup();
63
ErrorStatus handleTouchWakeup();
64
ErrorStatus handleIwdgWakeup();
65
66
static void indicateHibernate();
67
static void AdcSingleMeasurement();
68
69
ADC_TypeDef* setupADC(ADC_TypeDef* adc, const uint16_t low_th, const uint16_t high_th);
70
uint16_t configIwdg(const uint16_t ms);
71
72
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type);
73
void shutdownToTransportation();
74
void shutdownToDeepsleep();
75
void shutdownToHibernate();
76
void shutdownAndRestart();
77
78 470d0567 Thomas Schöpping
volatile blBackupRegister_t backup_reg;
79 69661903 Thomas Schöpping
80
/****************************************************************************************
81
* Callback configuration
82
****************************************************************************************/
83
void blCallbackShutdownTransportation(void);
84
void blCallbackShutdownDeepsleep(void);
85
void blCallbackShutdownHibernate(void);
86
void blCallbackShutdownRestart(void);
87
void blCallbackHandleShutdownRequest(void);
88
89 470d0567 Thomas Schöpping
const blCallbackTable_t cbtable __attribute__ ((section ("_callback_table"))) = {
90 69661903 Thomas Schöpping
  .magicNumber = BL_MAGIC_NUMBER,
91 d54d2f07 Thomas Schöpping
  .vBootloader = {BL_VERSION_ID_AMiRoBLT_Release, BL_VERSION_MAJOR, BL_VERSION_MINOR, 0},
92 470d0567 Thomas Schöpping
  .vSSSP = {BL_VERSION_ID_SSSP, SSSP_VERSION_MAJOR, SSSP_VERSION_MINOR, 0},
93
  .vCompiler = {BL_VERSION_ID_GCC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__},  // currently only GCC is supported
94 69661903 Thomas Schöpping
  .cbShutdownHibernate = blCallbackShutdownHibernate,
95
  .cbShutdownDeepsleep = blCallbackShutdownDeepsleep,
96
  .cbShutdownTransportation = blCallbackShutdownTransportation,
97
  .cbShutdownRestart = blCallbackShutdownRestart,
98
  .cbHandleShutdownRequest = blCallbackHandleShutdownRequest,
99
  .cb5 = (void*)0,
100
  .cb6 = (void*)0,
101
  .cb7 = (void*)0,
102
  .cb8 = (void*)0,
103
  .cb9 = (void*)0,
104
  .cb10 = (void*)0,
105
  .cb11 = (void*)0
106
};
107
108
/************************************************************************************//**
109 470d0567 Thomas Schöpping
** \brief     This is the entry point for the bootloader application and is called
110 69661903 Thomas Schöpping
**            by the reset interrupt vector after the C-startup routines executed.
111
** \return    none.
112
**
113
****************************************************************************************/
114
void main(void)
115
{
116
  /* initialize the microcontroller */
117
  Init();
118
119
  /* activate some required clocks */
120
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE);
121
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
122
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
123
124
  /* initialize GPIOs and EXTI lines */
125
  initGpio();
126
  setLed(BLT_TRUE);
127
  initExti();
128
129
  /* initialize the timer */
130
  TimerInit(); // do not use saTimerInit() in order to initialize the static variable.
131
132
  /* read the backup register */
133
  backup_reg.raw = RTC_ReadBackupRegister(BL_RTC_BACKUP_REG);
134
135
  /* detect the primary reason for this wakeup/restart */
136
  backup_reg.wakeup_pri_reason =
137
      ((RCC_GetFlagStatus(RCC_FLAG_LPWRRST) == SET) ? BL_WAKEUP_PRI_RSN_LPWRRST : 0) |
138
      ((RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) ? BL_WAKEUP_PRI_RSN_WWDGRST : 0) |
139
      ((RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) ? BL_WAKEUP_PRI_RSN_IWDGRST : 0) |
140
      ((RCC_GetFlagStatus(RCC_FLAG_SFTRST) == SET) ? BL_WAKEUP_PRI_RSN_SFTRST : 0)   |
141
      ((RCC_GetFlagStatus(RCC_FLAG_PORRST) == SET) ? BL_WAKEUP_PRI_RSN_PORRST : 0)   |
142
      ((RCC_GetFlagStatus(RCC_FLAG_PINRST) == SET) ? BL_WAKEUP_PRI_RSN_PINRST : 0)   |
143
      ((RCC_GetFlagStatus(RCC_FLAG_BORRST) == SET) ? BL_WAKEUP_PRI_RSN_BORRST : 0)   |
144
      ((PWR_GetFlagStatus(PWR_FLAG_WU) == SET) ? BL_WAKEUP_PRI_RSN_WKUP : 0);
145
146
  /* when woken from standby mode, detect the secondary reason for this wakeup/reset */
147
  if ( (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_WKUP) && (PWR_GetFlagStatus(PWR_FLAG_SB) == SET) ) {
148
    if (GPIO_ReadInputDataBit(SYS_UART_DN_GPIO, SYS_UART_DN_PIN) == Bit_RESET) {
149
      backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UART;
150
    } else if (GPIO_ReadInputDataBit(PATH_DC_GPIO, PATH_DC_PIN) == Bit_SET) {
151
      backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_PWRPLUG;
152
    } else {
153
      backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_TOUCH;
154
    }
155
  } else {
156
    backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UNKNOWN;
157
  }
158
159
  /* store the information about this wakeup/restart in the backup register */
160
  PWR_BackupAccessCmd(ENABLE);
161
  RTC_WriteBackupRegister(BL_RTC_BACKUP_REG, backup_reg.raw);
162
163
  /* clear the flags */
164
  RCC_ClearFlag();
165
  PWR_ClearFlag(PWR_FLAG_WU);
166
167
  setLed(BLT_FALSE);
168
169
  /* handle different wakeup/reset reasons */
170
  ErrorStatus status = ERROR;
171
  if (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_SFTRST) {
172
    /* system was reset by software */
173
    status = handleSoftwareReset();
174
  } else if (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_WKUP) {
175
    /* system was woken via WKUP pin */
176
    /* differeciate between thre wakeup types */
177
    switch (backup_reg.wakeup_sec_reason) {
178
      case BL_WAKEUP_SEC_RSN_UART:
179
        status = handleUartDnWakeup();
180
        break;
181
      case BL_WAKEUP_SEC_RSN_PWRPLUG:
182
        status = handlePathDcWakeup();
183
        break;
184
      case BL_WAKEUP_SEC_RSN_TOUCH:
185
        status = handleTouchWakeup();
186
        break;
187
      default:
188
        status = ERROR;
189
        break;
190
    }
191
  } else if (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_IWDGRST) {
192
    /* system was woken by IWDG */
193
    status = handleIwdgWakeup();
194
  } else if (backup_reg.wakeup_pri_reason == BL_WAKEUP_PRI_RSN_PINRST) {
195
    /* system was reset via NRST pin */
196
    status = handleColdReset();
197
  } else {
198
    /* system was woken/reset for an unexpected reason.
199
     * In this case the LED blinks "SOS" (... --- ...) and the system resets.
200
     */
201
    blinkSOS(1);
202
    status = ERROR;
203
    backup_reg.shutdown_pri_reason = BL_SHUTDOWN_PRI_RSN_RESTART;
204
    backup_reg.shutdown_sec_reason = BL_SHUTDOWN_SEC_RSN_UNKNOWN;
205
    RTC_WriteBackupRegister(BL_RTC_BACKUP_REG, backup_reg.raw);
206
    NVIC_SystemReset();
207
  }
208
209
  /* if something went wrong, signal this failure */
210
  if (status != SUCCESS) {
211
    blinkSOSinf();
212
  }
213
214
  return;
215
} /*** end of main ***/
216
217
218
/************************************************************************************//**
219 470d0567 Thomas Schöpping
** \brief     Initializes the microcontroller.
220 69661903 Thomas Schöpping
** \return    none.
221
**
222
****************************************************************************************/
223
static void Init(void)
224
{
225
#if (BOOT_COM_UART_ENABLE > 0 || BOOT_GATE_UART_ENABLE > 0)
226
  GPIO_InitTypeDef  GPIO_InitStructure;
227
#elif (BOOT_FILE_SYS_ENABLE > 0)
228
  GPIO_InitTypeDef  GPIO_InitStructure;
229
  USART_InitTypeDef USART_InitStructure;
230
#elif (BOOT_COM_CAN_ENABLE > 0 || BOOT_GATE_CAN_ENABLE > 0)
231
  GPIO_InitTypeDef  GPIO_InitStructure;
232 470d0567 Thomas Schöpping
#endif
233 69661903 Thomas Schöpping
234
  /* initialize the system and its clocks */
235
  SystemInit();
236
#if (BOOT_COM_UART_ENABLE > 0 || BOOT_GATE_UART_ENABLE > 0)
237
  /* enable UART peripheral clock */
238
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
239
  /* enable GPIO peripheral clock for transmitter and receiver pins */
240
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
241
  /* connect the pin to the peripherals alternate function */
242
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
243
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
244
  /* configure USART Tx as alternate function  */
245
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
246
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
247
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
248
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
249
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
250
  GPIO_Init(GPIOA, &GPIO_InitStructure);
251
  /* configure USART Rx as alternate function */
252
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
253
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
254
  GPIO_Init(GPIOA, &GPIO_InitStructure);
255
#endif
256
257
#if (BOOT_COM_BLUETOOTH_UART_ENABLE > 0)
258
  /* enable UART peripheral clock */
259
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
260
261
  /* enable GPIO peripheral clock for transmitter and receiver pins */
262
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
263
  /* connect the pin to the peripherals alternate function */
264
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
265
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_USART3);
266
  /* configure USART Tx as alternate function  */
267
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
268
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
269
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
270
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
271
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
272
  GPIO_Init(GPIOC, &GPIO_InitStructure);
273
  /* configure USART Rx as alternate function */
274
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
275
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
276
  GPIO_Init(GPIOC, &GPIO_InitStructure);
277
278
  /* Configure Bluetooth reset pin */
279
  GPIO_InitTypeDef  gpio_init;
280
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
281
  gpio_init.GPIO_Pin   = BT_RST_PIN;
282
  gpio_init.GPIO_OType = GPIO_OType_OD;
283
  gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
284
  gpio_init.GPIO_Mode = GPIO_Mode_OUT;
285
  gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
286
  GPIO_Init(BT_RST_GPIO, &gpio_init);
287
  /* Reset Bluetooth reset pin */
288
  GPIO_ResetBits(BT_RST_GPIO, BT_RST_PIN);
289
#endif
290
291
292
#if (BOOT_COM_CAN_ENABLE > 0 || BOOT_GATE_CAN_ENABLE > 0)
293
  /* enable clocks for CAN transmitter and receiver pins */
294
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
295
  /* select alternate function for the CAN pins */
296
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1);
297 470d0567 Thomas Schöpping
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1);
298 69661903 Thomas Schöpping
  /* configure CAN RX and TX pins */
299
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
300
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
301
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
302
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
303
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
304
  GPIO_Init(GPIOA, &GPIO_InitStructure);
305
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
306
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
307
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
308
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
309
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
310
  GPIO_Init(GPIOA, &GPIO_InitStructure);
311 470d0567 Thomas Schöpping
#endif
312 69661903 Thomas Schöpping
313
} /*** end of Init ***/
314
315
/*
316
 * Initializes all GPIO used by the bootloader
317
 */
318
static void initGpio() {
319
  GPIO_InitTypeDef gpio_init;
320
321
  /*
322
   * OUTPUTS
323
   */
324
325
  /* initialize LED and push it up (inactive) */
326
  GPIO_SetBits(LED_GPIO, LED_PIN);
327
  gpio_init.GPIO_Pin    = LED_PIN;
328
  gpio_init.GPIO_Mode   = GPIO_Mode_OUT;
329
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
330
  gpio_init.GPIO_OType  = GPIO_OType_PP;
331
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
332
  GPIO_Init(LED_GPIO, &gpio_init);
333
334
  /* initialize SYS_PD_N and push it up (inactive) */
335
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
336
  gpio_init.GPIO_Pin    = SYS_PD_N_PIN;
337
  gpio_init.GPIO_Mode   = GPIO_Mode_OUT;
338
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
339
  gpio_init.GPIO_OType  = GPIO_OType_OD;
340
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
341
  GPIO_Init(SYS_PD_N_GPIO, &gpio_init);
342
343
  /* initialize SYS_SYNC_N and pull it down (active) */
344
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
345
  gpio_init.GPIO_Pin    = SYS_SYNC_N_PIN;
346
  gpio_init.GPIO_Mode   = GPIO_Mode_OUT;
347
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
348
  gpio_init.GPIO_OType  = GPIO_OType_OD;
349
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
350
  GPIO_Init(SYS_SYNC_N_GPIO, &gpio_init);
351
352
  /* initialize SYS_WARMRST_N and pull it down (active) */
353
  GPIO_ResetBits(SYS_WARMRST_N_GPIO, SYS_WARMRST_N_PIN);
354
  gpio_init.GPIO_Pin    = SYS_WARMRST_N_PIN;
355
  gpio_init.GPIO_Mode   = GPIO_Mode_OUT;
356
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
357
  gpio_init.GPIO_OType  = GPIO_OType_OD;
358
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
359
  GPIO_Init(SYS_WARMRST_N_GPIO, &gpio_init);
360
361
  /* initialize SYS_UART_DN and push it up (inactive) */
362
  GPIO_SetBits(SYS_UART_DN_GPIO, SYS_UART_DN_PIN);
363
  gpio_init.GPIO_Pin    = SYS_UART_DN_PIN;
364
  gpio_init.GPIO_Mode   = GPIO_Mode_OUT;
365
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
366
  gpio_init.GPIO_OType  = GPIO_OType_OD;
367
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
368
  GPIO_Init(SYS_UART_DN_GPIO, &gpio_init);
369
370
  /* initialize POWER_EN and pull it down (inactive) */
371
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
372
  gpio_init.GPIO_Pin    = POWER_EN_PIN;
373
  gpio_init.GPIO_Mode   = GPIO_Mode_OUT;
374
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
375
  gpio_init.GPIO_OType  = GPIO_OType_PP;
376
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
377
  GPIO_Init(POWER_EN_GPIO, &gpio_init);
378
379
  /* initialize SYS_REG_EN and pull it down (inactive) */
380
  GPIO_ResetBits(SYS_REG_EN_GPIO, SYS_REG_EN_PIN);
381
  gpio_init.GPIO_Pin    = SYS_REG_EN_PIN;
382
  gpio_init.GPIO_Mode   = GPIO_Mode_OUT;
383
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
384
  gpio_init.GPIO_OType  = GPIO_OType_PP;
385
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
386
  GPIO_Init(SYS_REG_EN_GPIO, &gpio_init);
387
388
  /* initialize CHARGE_EN1_N and CHARGE_EN2_N and push them up (inactive) */
389
  GPIO_SetBits(CHARGE_EN1_N_GPIO, CHARGE_EN1_N_PIN);
390
  GPIO_SetBits(CHARGE_EN2_N_GPIO, CHARGE_EN2_N_PIN);
391
  gpio_init.GPIO_Pin    = CHARGE_EN1_N_PIN;
392
  gpio_init.GPIO_Mode   = GPIO_Mode_OUT;
393
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
394
  gpio_init.GPIO_OType  = GPIO_OType_PP;
395
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
396
  GPIO_Init(CHARGE_EN1_N_GPIO, &gpio_init);
397
  gpio_init.GPIO_Pin    = CHARGE_EN2_N_PIN;
398
  GPIO_Init(CHARGE_EN2_N_GPIO, &gpio_init);
399
400
  /*
401
   * INPUTS
402
   */
403
404
  /* initialize PATH_DC */
405
  gpio_init.GPIO_Pin    = PATH_DC_PIN;
406
  gpio_init.GPIO_Mode   = GPIO_Mode_IN;
407
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
408
  gpio_init.GPIO_OType  = GPIO_OType_PP;
409
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
410
  GPIO_Init(PATH_DC_GPIO, &gpio_init);
411
412
  /* initialize TOUCH_INT_N */
413
  gpio_init.GPIO_Pin    = TOUCH_INT_N_PIN;
414
  gpio_init.GPIO_Mode   = GPIO_Mode_IN;
415
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
416
  gpio_init.GPIO_OType  = GPIO_OType_PP;
417
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
418
  GPIO_Init(TOUCH_INT_N_GPIO, &gpio_init);
419
420
  /* initialize VSYS_SENSE as analog input */
421
  gpio_init.GPIO_Pin    = VSYS_SENSE_PIN;
422
  gpio_init.GPIO_Mode   = GPIO_Mode_AN;
423
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
424
  gpio_init.GPIO_OType  = GPIO_OType_PP;
425
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
426
  GPIO_Init(VSYS_SENSE_GPIO, &gpio_init);
427
428
  /* initialize GPIOB4, since it is configured in alternate function mode on reset */
429
  gpio_init.GPIO_Pin    = CHARGE_STAT2A_PIN;
430
  gpio_init.GPIO_Mode   = GPIO_Mode_IN;
431
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
432
  gpio_init.GPIO_OType  = GPIO_OType_PP;
433
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
434
  GPIO_Init(CHARGE_STAT2A_GPIO, &gpio_init);
435
436
  return;
437
} /*** end of initGpio ***/
438
439
/*
440
 * Initialize all EXTI lines
441
 */
442
static void initExti() {
443
  /* configure EXTI lines */
444
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource0); // IR_INT1_N
445
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource0); // CHARGE_STAT1A
446
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource1); // GAUGE_BATLOW1
447
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource2); // GAUGE_BATGD1_N
448
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource3); // SYS_UART_DN
449
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource4); // CHARGE_STAT2A
450
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource4); // IR_INT2_N
451
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource5); // TOUCH_INT_N
452
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource6); // GAUGE_BATLOW2
453
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource7); // GAUGE_BATGD2_N
454
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource8); // PATH_DC
455
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource9); // SYS_SPI_DIR
456
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource12); // SYS_SYNC_N
457
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13); // SYS_PD_N
458
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource14); // SYS_WARMRST_N
459
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource15); // SYS_UART_UP
460
461
  return;
462
} /*** end of initExti ***/
463
464
/*
465
 * Signals, which type of low-power mode the system shall enter after the shutdown sequence.
466
 */
467
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type) {
468
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
469
  ErrorStatus ret_val = ERROR;
470
471
  switch (type) {
472
    case BL_SHUTDOWN_PRI_RSN_UNKNOWN:
473
    case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
474
    case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
475
    case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
476
    {
477
      // broadcast a number of pulses, depending on the argument
478
      uint8_t pulse_counter = 0;
479
      for (pulse_counter = 0; pulse_counter < type; ++pulse_counter) {
480
        msleep(1);
481
        GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
482
        msleep(1);
483
        GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
484
      }
485
      // wait for timeout
486
      msleep(10);
487
      ret_val = SUCCESS;
488
      break;
489
    }
490
    case BL_SHUTDOWN_PRI_RSN_RESTART:
491
    {
492
      // since there is no ambiguity for restart requests, no pulses are generated
493
      msleep(10);
494
      ret_val = SUCCESS;
495
      break;
496
    }
497
    default:
498
      ret_val = ERROR;
499
      break;
500
  }
501
502
  return ret_val;
503
} /*** end of shutdownDisambiguationProcedure ***/
504
505
/*
506
 * Final shutdown of the system to enter transportation mode.
507
 */
508
void shutdownToTransportation() {
509
  /* configure some criticpal GPIOs as input
510
   * This is required, because otherwise some hardware might be powered through these signals */
511
  configGpioForShutdown();
512
513
  /* power down the system */
514
  systemPowerDown();
515
516
  /* deactivate the WKUP pin */
517
  PWR_WakeUpPinCmd(DISABLE);
518
519
  /* deactivate any RTC related events */
520
  RTC_WakeUpCmd(DISABLE);
521
  RTC_TamperCmd(RTC_Tamper_1, DISABLE);
522
  RTC_TimeStampCmd(RTC_TimeStampEdge_Rising, DISABLE);
523
  RTC_TimeStampCmd(RTC_TimeStampEdge_Falling, DISABLE);
524
  RTC_ClearFlag(~0);
525
526
  /* disable the IWDG */
527
  IWDG_ReloadCounter();
528
529
  /* write some information to the backup register */
530 470d0567 Thomas Schöpping
  blBackupRegister_t backup;
531 69661903 Thomas Schöpping
  backup.shutdown_pri_reason = BL_SHUTDOWN_PRI_RSN_TRANSPORT;
532
  backup.shutdown_sec_reason = BL_SHUTDOWN_SEC_RSN_UNKNOWN;
533
  backup.wakeup_pri_reason = BL_WAKEUP_PRI_RSN_UNKNOWN;
534
  backup.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UNKNOWN;
535
  PWR_BackupAccessCmd(ENABLE);
536
  RTC_WriteBackupRegister(BL_RTC_BACKUP_REG, backup.raw);
537
538
  /* morse 'OK' via the LED to signal that shutdown was successful */
539
  blinkOK(1);
540
541
  /* enter standby mode */
542
  PWR_EnterSTANDBYMode();
543
544
  return;
545
} /*** end of shutdownToTransportation ***/
546
547
/*
548
 * Final shutdown of the system to enter deepseleep mode.
549
 */
550
void shutdownToDeepsleep() {
551
  /* configure some criticpal GPIOs as input
552
   * This is required, because otherwise some hardware might be powered through these signals */
553
  configGpioForShutdown();
554
555
  /* power down the system */
556
  systemPowerDown();
557
558
  /* activate the WKUP pin */
559
  PWR_WakeUpPinCmd(ENABLE);
560
561
  /*
562
   * Configuration of RTC and IWDG belongs to the OS.
563
   */
564
565
  /* write some information to the backup register */
566 470d0567 Thomas Schöpping
  blBackupRegister_t backup;
567 69661903 Thomas Schöpping
  backup.shutdown_pri_reason = BL_SHUTDOWN_PRI_RSN_DEEPSLEEP;
568
  backup.shutdown_sec_reason = BL_SHUTDOWN_SEC_RSN_UNKNOWN;
569
  backup.wakeup_pri_reason = BL_WAKEUP_PRI_RSN_UNKNOWN;
570
  backup.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UNKNOWN;
571
  PWR_BackupAccessCmd(ENABLE);
572
  RTC_WriteBackupRegister(BL_RTC_BACKUP_REG, backup.raw);
573
574
  /* morse 'OK' via the LED to signal that shutdown was successful */
575
  blinkOK(1);
576
577
  /* enter standby mode or restart the system in case a power plug is already present */
578
  if (GPIO_ReadInputDataBit(PATH_DC_GPIO, PATH_DC_PIN) != Bit_SET) {
579
    PWR_EnterSTANDBYMode();
580
  } else {
581
    NVIC_SystemReset();
582
  }
583
584
  return;
585
} /*** end of shutdownToDeepsleep ***/
586
587
/*
588
 * Final shutdown of the system to enter hibernate mode.
589
 */
590
void shutdownToHibernate() {
591
  /* configure some criticpal GPIOs as input
592
   * This is required, because otherwise some hardware might be powered through these signals */
593
  configGpioForShutdown();
594
595
  /* power down the system */
596
  systemPowerDown();
597
598
  /* write some information to the backup register */
599 470d0567 Thomas Schöpping
  blBackupRegister_t backup;
600 69661903 Thomas Schöpping
  backup.shutdown_pri_reason = BL_SHUTDOWN_PRI_RSN_HIBERNATE;
601
  backup.shutdown_sec_reason = BL_SHUTDOWN_SEC_RSN_UNKNOWN;
602
  backup.wakeup_pri_reason = BL_WAKEUP_PRI_RSN_UNKNOWN;
603
  backup.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UNKNOWN;
604
  PWR_BackupAccessCmd(ENABLE);
605
  RTC_WriteBackupRegister(BL_RTC_BACKUP_REG, backup.raw);
606
607
  /* morse 'OK' via the LED to signal that shutodnw was successful */
608
  blinkOK(1);
609
610
  /* reset the MCU */
611
  NVIC_SystemReset();
612
613
  return;
614
} /*** end of shutdownToHibernate ***/
615
616
/*
617
 * Final shutdown of the system and restart.
618
 */
619
void shutdownAndRestart() {
620
  /* configure some criticpal GPIOs as input
621
   * This is required, because otherwise some hardware might be powered through these signals */
622
  configGpioForShutdown();
623
624
  /* power down the system */
625
  systemPowerDown();
626
627
  /* write some information to the backup register */
628 470d0567 Thomas Schöpping
  blBackupRegister_t backup;
629 69661903 Thomas Schöpping
  backup.shutdown_pri_reason = BL_SHUTDOWN_PRI_RSN_RESTART;
630
  backup.shutdown_sec_reason = BL_SHUTDOWN_SEC_RSN_UNKNOWN;
631
  backup.wakeup_pri_reason = BL_WAKEUP_PRI_RSN_UNKNOWN;
632
  backup.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UNKNOWN;
633
  PWR_BackupAccessCmd(ENABLE);
634
  RTC_WriteBackupRegister(BL_RTC_BACKUP_REG, backup.raw);
635
636
  /* morse 'OK' via the LED to signal that shutodnw was successful */
637
  blinkOK(1);
638
639
  /* reset the MCU */
640
  NVIC_SystemReset();
641
642
  return;
643
} /*** end of shutdownAndRestart ***/
644
645
/*
646
 * Configures some GPIO pins as inputs for safety reasons.
647
 * Under certain circumstances, these pins might power hardware that is supposed to be shut down.
648
 */
649
void configGpioForShutdown() {
650
  /* setup the configuration */
651
  GPIO_InitTypeDef  gpio_init;
652
  gpio_init.GPIO_Mode   = GPIO_Mode_IN;
653
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
654
  gpio_init.GPIO_OType  = GPIO_OType_PP;
655
  gpio_init.GPIO_PuPd   = GPIO_PuPd_NOPULL;
656
657
  /* configure SYS_UART_TX */
658
  gpio_init.GPIO_Pin = SYS_UART_TX_PIN;
659
  GPIO_Init(SYS_UART_TX_GPIO, &gpio_init);
660
661
  /* configure all SYS_SPI signals */
662
  gpio_init.GPIO_Pin = SYS_SPI_SS0_N_PIN;
663
  GPIO_Init(SYS_SPI_SS0_N_GPIO, &gpio_init);
664
  gpio_init.GPIO_Pin = SYS_SPI_SCLK_PIN;
665
  GPIO_Init(SYS_SPI_SCLK_GPIO, &gpio_init);
666
  gpio_init.GPIO_Pin = SYS_SPI_MISO_PIN;
667
  GPIO_Init(SYS_SPI_MISO_GPIO, &gpio_init);
668
  gpio_init.GPIO_Pin = SYS_SPI_MOSI_PIN;
669
  GPIO_Init(SYS_SPI_MOSI_GPIO, &gpio_init);
670
  gpio_init.GPIO_Pin = SYS_SPI_SS1_N_PIN;
671
  GPIO_Init(SYS_SPI_SS1_N_GPIO, &gpio_init);
672
  gpio_init.GPIO_Pin = SYS_SPI_DIR_PIN;
673
  GPIO_Init(SYS_SPI_DIR_GPIO, &gpio_init);
674
675
  /* configure CAN_TX */
676
  gpio_init.GPIO_Pin = CAN_TX_PIN;
677
  GPIO_Init(CAN_TX_GPIO, &gpio_init);
678
679
  /* configure all Bluetooth signals */
680
  gpio_init.GPIO_Pin = BT_CTS_PIN;
681
  GPIO_Init(BT_CTS_GPIO, &gpio_init);
682
  gpio_init.GPIO_Pin = BT_RX_PIN;
683
  GPIO_Init(BT_RX_GPIO, &gpio_init);
684
685
  return;
686
} /*** end of configGpioForShutdown ***/
687
688
/*
689
 * Disables all regulated voltages and finally cuts power to the rest of the system.
690
 */
691
void systemPowerDown() {
692
  setLed(BLT_TRUE);
693
694
  /* make sure that all other modules are shut down */
695
  msleep(10);
696
697
  /* reset slave modules */
698
  GPIO_ResetBits(SYS_WARMRST_N_GPIO, SYS_WARMRST_N_PIN);
699
700
  /* disable voltage regulators */
701
  GPIO_ResetBits(SYS_REG_EN_GPIO, SYS_REG_EN_PIN);
702
703
  /* cut power */
704
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
705
706
  /* make sure, all capacitors are discharged */
707
  msleep(100);
708
709
  setLed(BLT_FALSE);
710
711
  return;
712
} /*** end of systemPowerDown ***/
713
714
/*
715
 * Cofigures the independent watchdog (IWDG) to fire after the specified time when it is enabled.
716
 * The argument is the requested time in milliseconds.
717
 * The time that was actually set for the IWDG is returned by the function (again in milliseconds).
718
 * In some cases the returned value might differ from the requested one, but if so, it will alwyas be smaller.
719
 * Although the IWDG provides higher resolutions than milliseconds, these are not supported by this function.
720
 */
721
uint16_t configIwdg(const uint16_t ms) {
722
  /* apply an upper bound to the ms argument */
723
  uint16_t ms_capped = (ms >= 0x8000) ? 0x7FFF : ms;
724
725
  /* detect the best fitting prescaler and compute the according reload value */
726
  uint8_t prescaler = 0;
727
  uint16_t reload_val = 0;
728
  if (ms_capped >= 0x4000) {
729
    prescaler = IWDG_Prescaler_256;
730
    reload_val = ms_capped >> 3;  // note: this corresponds to a floor function
731
    ms_capped = reload_val << 3;  // this applies the floor function to ms_capped
732
  } else if (ms_capped >= 0x2000) {
733
    prescaler = IWDG_Prescaler_128;
734
    reload_val = ms_capped >> 2;  // note: this corresponds to a floor function
735
    ms_capped = reload_val << 2;  // this applies the floor function to ms_capped
736
  } else if (ms_capped >= 0x1000) {
737
    ms_capped &= ~(0x0001);
738
    prescaler = IWDG_Prescaler_64;
739
    reload_val = ms_capped >> 1;  // note: this corresponds to a floor function
740
    ms_capped = reload_val << 1;  // this applies the floor function to ms_capped
741
  } else {
742
    prescaler = IWDG_Prescaler_32;
743
    reload_val = ms_capped;
744
  }
745
746
  /* configure the IWDG */
747
  if (reload_val > 0) {
748
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
749
    IWDG_SetPrescaler(prescaler);
750
    IWDG_SetReload(reload_val);
751
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Disable);
752
  }
753
754
  return ms_capped;
755
} /*** end of configIWDG ***/
756
757
/*
758
 * System was reset via the NRST pin or the reason could not be detected.
759
 * In this case, everything is started up.
760
 * If an attempt for an OS update is detected, flashing mode is entered.
761
 * Otherwise, the system will boot the OS.
762
 */
763
ErrorStatus handleColdReset() {
764
  /* activate system power and wait some time to ensure stable voltages */
765
  setLed(BLT_TRUE);
766
  GPIO_SetBits(POWER_EN_GPIO, POWER_EN_PIN);
767
  msleep(10);
768
  GPIO_SetBits(SYS_REG_EN_GPIO, SYS_REG_EN_PIN);
769
  msleep(10);
770
  setLed(BLT_FALSE);
771
772
  /* drive SYS_WARMRST_N high (inactive) */
773
  GPIO_SetBits(SYS_WARMRST_N_GPIO, SYS_WARMRST_N_PIN);
774
775
  /* enable CAN clock
776
   * Note that CAN1 shares reception filters with CAN1 so for CAN2 the CAN1 peripheral also needs to be enabled. */
777
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2 | RCC_APB1Periph_CAN1, ENABLE);
778
779
  /* wait 1ms to make sure that all modules are running and started the bootloader */
780
  msleep(1);
781
782
  /* initialize the bootloader */
783
  BootInit();
784
785
  /* start the infinite program loop */
786
  uint32_t loopStartTime = 0;
787
  saTimerUpdate(&loopStartTime);
788
  uint32_t currentTime = loopStartTime;
789
  while (1)
790
  {
791 d54d2f07 Thomas Schöpping
//    /* make the LED "double-blink" */
792
//    saTimerUpdate(&currentTime);
793
//    if (currentTime < loopStartTime + 50) {
794
//      setLed(BLT_TRUE);
795
//    } else if (currentTime < loopStartTime + 50+100) {
796
//      setLed(BLT_FALSE);
797
//    } else if (currentTime < loopStartTime + 50+100+50) {
798
//      setLed(BLT_TRUE);
799
//    } else if (currentTime < loopStartTime + 50+100+50+300) {
800
//      setLed(BLT_FALSE);
801
//    } else {
802
//      loopStartTime = currentTime;
803
//    }
804 69661903 Thomas Schöpping
805
    /* run the bootloader task */
806
    BootTask();
807
808
    /* check the SYS_PD_N signal */
809
    if (GPIO_ReadInputDataBit(SYS_PD_N_GPIO, SYS_PD_N_PIN) == Bit_RESET) {
810
      blCallbackHandleShutdownRequest();
811
      return SUCCESS;
812
    }
813
  }
814
815
  return ERROR;
816
} /*** end of handleColdReset ***/
817
818
/*
819
 * System was reset by software.
820
 * Depending on the argument, which was read from the 1st backup register (see main function) the effect of this function differs.
821
 * There are three cases that can occur:
822
 * - The system was reset to enter hibernate mode.
823
 *   In this case the system will enter a medium power saving mode (hibernate mode), but can be charged via the charging pins.
824
 *   The system can be woken up in the same way as in deepsleep mode (cf. blCallbackShutdownDeepsleep() function).
825
 * - The system was reset to reboot.
826
 *   In this case the system will restart in the same way as after a cold reset.
827
 * - The reason is unknown.
828
 *   This case will cause an error.
829
 */
830
ErrorStatus handleSoftwareReset() {
831
  /* action depends on original shutdown reason */
832
  switch (backup_reg.shutdown_pri_reason) {
833
    case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
834
    {
835
      /* activate the WKUP pin */
836
      PWR_WakeUpPinCmd(ENABLE);
837
838
      /* deactivate any RTC related events */
839
      RTC_WakeUpCmd(DISABLE);
840
      RTC_TamperCmd(RTC_Tamper_1, DISABLE);
841
      RTC_TimeStampCmd(RTC_TimeStampEdge_Rising, DISABLE);
842
      RTC_TimeStampCmd(RTC_TimeStampEdge_Falling, DISABLE);
843
844
      /* configure the IWDG to wake the system from standby mode */
845
      uint16_t iwdg_ms = 1;
846
      if (GPIO_ReadInputDataBit(PATH_DC_GPIO, PATH_DC_PIN) != Bit_SET) {
847
        /* if a power plug is detected, fire immediately (1ms), else fire after the defined hibernate time */
848
        iwdg_ms = HIBERNATE_TIME_MS;
849
      }
850
      configIwdg(iwdg_ms);
851
      IWDG_Enable();
852
853
      /* enter standby mode */
854
      PWR_EnterSTANDBYMode();
855
856
      return SUCCESS;
857
      break;
858
    }
859
    case BL_SHUTDOWN_PRI_RSN_RESTART:
860
    {
861
      return handleColdReset();
862
      break;
863
    }
864
    case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
865
    {
866
      if (GPIO_ReadInputDataBit(PATH_DC_GPIO, PATH_DC_PIN) == Bit_SET) {
867
        return handlePathDcWakeup();
868
      } else {
869
        blCallbackShutdownDeepsleep();
870
      }
871
      break;
872
    }
873
    default:
874
      return ERROR;
875
  }
876
  return ERROR;
877
} /*** end of handleSoftwareReset ***/
878
879
/*
880
 * System was woken up via the WKUP pin and the SYS_UART_DN signal was found to be responsible.
881
 * In this case, the system starts as after a cold reset.
882
 * this function is identical to handleTouchWakeup().
883
 */
884
ErrorStatus handleUartDnWakeup() {
885
  return handleColdReset();
886
} /*** end of hanldeUartDnWakeup ***/
887
888
/*
889
 * System was woken up via the WKUP pin and the PATH_DC signal was found to be responsible.
890
 * If the system was woken from deepsleep mode, it will enter hibernate mode to enable charging as long as the power plug is present.
891
 * In any other case, the system will just enter the previous low-power mode again.
892
 */
893
ErrorStatus handlePathDcWakeup() {
894
  /* reenter the previous low-power mode */
895
  switch (backup_reg.shutdown_pri_reason) {
896
    case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
897
      blCallbackShutdownHibernate();
898
      return SUCCESS;
899
      break;
900
    case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
901
      /* visualize that the power plug was detected
902
       * This is helpful for feedback, and required for the follwing reason:
903
       * When the power plug is detected, it takes some additional time for the ADC to detect a high voltage.
904
       * If the ADC detects a low voltage at the first attempt, the system will enter hibernate mode.
905
       * Thus, the ADC will measure the voltage again after several seconds and charging will start.
906
       * However, this behaviour does not meet the user expection.
907
       * Hence, the voltage has some to adapt at this point
908
       */
909
      setLed(BLT_TRUE);
910
      msleep(500);
911
      setLed(BLT_FALSE);
912
913
      return handleIwdgWakeup();
914
      break;
915
    case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
916
      blCallbackShutdownTransportation();
917
      return SUCCESS;
918
      break;
919
    default:
920
      return ERROR;
921
      break;
922
  }
923
924
  return ERROR;
925
} /*** end of handlePathDcWakeup ***/
926
927
/*
928
 * System was woken up via the WKUP pin and the touch sensors were found to be responsible.
929
 * In this case the system starts as after an cold reset.
930
 * This function is identical to handleUartDnWakeup().
931
 */
932
ErrorStatus handleTouchWakeup() {
933
  return handleColdReset();
934
} /*** end of handleTouchWakeup ***/
935
936
/*
937
 * System was woken up via the IWDG.
938
 * In this case the ADC is configured and VSYS is measured once.
939
 * If VSYS is found to be high enough to charge the batteries, the system will stay active until VSYS drops or an EXTI event occurs.
940
 * Otherwise, the system will configure the IWDG to wake the system again after five seconds and enter standby mode.
941
 */
942
ErrorStatus handleIwdgWakeup() {
943
  /* handle different situations, depending on the backup data */
944
  if ((backup_reg.shutdown_pri_reason == BL_SHUTDOWN_PRI_RSN_HIBERNATE) ||
945
      (backup_reg.shutdown_pri_reason == BL_SHUTDOWN_PRI_RSN_DEEPSLEEP)) {
946
    /* handle periodic wakeup in hibernate mode and in deepsleep mode when a power plug was detetced */
947
948
    /* if in hibernate mode, indicate the DiWheelDrive to enter hibernate mode as well, so it will activate the charging pins */
949
    if (backup_reg.shutdown_pri_reason == BL_SHUTDOWN_PRI_RSN_HIBERNATE) {
950
      indicateHibernate();
951
    }
952
953
    /* measure the current voltage of VSYS */
954
    AdcSingleMeasurement();
955
956
    /* evaluate the value
957
     * The ADC value represents the analog voltage between Vref- (= GND = 0.0V) and Vref+ (= VDD = 3.3V) as 12-bit value.
958
     * Hence, the value read from the register is first scaled to [0V .. 3.3V].
959
     * Then, an additional factor 5.33 is applied to account the downscaling on the board.
960
     * Actually, the factor should be 5.0, but due to too large resistors it was corrected to 5.33.
961
     */
962
    if ( (((float)(ADC_GetConversionValue(ADC1)) / (float)(0x0FFF)) * 3.3f * 5.33f) < 9.0f ) {
963
      /* VSYS was found to be < 9V */
964
965
      /* re-enter power saving mode
966
       * If the system was shut down to deepsleep mode and the power plug was removed, re-enter deepsleep mode.
967
       * (This could be done earlier in this function, but since charging via the pins of the DeWheelDrive may be
968
       *  supported in the future, this is done after measuring VSYS)
969
       */
970
      if (backup_reg.shutdown_pri_reason == BL_SHUTDOWN_PRI_RSN_DEEPSLEEP &&
971
          GPIO_ReadInputDataBit(PATH_DC_GPIO, PATH_DC_PIN) == Bit_RESET) {
972
        blCallbackShutdownDeepsleep();
973
      } else {
974
        /* reconfigure the IWDG and power down for five seconds */
975
        configIwdg(HIBERNATE_TIME_MS);
976
        IWDG_Enable();
977
978
        /* enter standby mode */
979
        PWR_EnterSTANDBYMode();
980
      }
981
982
      return SUCCESS;
983
    } else {
984
      /* VSYS was found to be >= 9V */
985
      setLed(BLT_TRUE);
986
987
      /* charge the battieries */
988
      GPIO_ResetBits(CHARGE_EN1_N_GPIO, CHARGE_EN1_N_PIN);
989
      GPIO_ResetBits(CHARGE_EN2_N_GPIO, CHARGE_EN2_N_PIN);
990
991
      /* configure analog watchdoch to fire as soon as the voltage drops below 9V */
992
      ADC_DeInit();
993
      setupADC(ADC1, (uint16_t)(9.0f / 5.33f / 3.3f * (float)0x0FFF), 0x0FFF);
994
995
      EXTI_InitTypeDef exti;
996
      /* configure UART_DN EXTI */
997
      exti.EXTI_Line = EXTI_Line3;
998
      exti.EXTI_Mode = EXTI_Mode_Interrupt;
999
      exti.EXTI_Trigger = EXTI_Trigger_Falling;
1000
      exti.EXTI_LineCmd = ENABLE;
1001
      EXTI_Init(&exti);
1002
1003
      /* configure TOUCH_INT_N EXTI */
1004
      exti.EXTI_Line = EXTI_Line5;
1005
      exti.EXTI_Mode = EXTI_Mode_Interrupt;
1006
      exti.EXTI_Trigger = EXTI_Trigger_Falling;
1007
      exti.EXTI_LineCmd = ENABLE;
1008
      EXTI_Init(&exti);
1009
1010
      /* configure PATH_DC EXTI */
1011
      if (backup_reg.shutdown_pri_reason == BL_SHUTDOWN_PRI_RSN_DEEPSLEEP) {
1012
        exti.EXTI_Line = EXTI_Line8;
1013
        exti.EXTI_Mode = EXTI_Mode_Interrupt;
1014
        exti.EXTI_Trigger = EXTI_Trigger_Falling;
1015
        exti.EXTI_LineCmd = ENABLE;
1016
        EXTI_Init(&exti);
1017
      }
1018
1019