Statistics
| Branch: | Tag: | Revision:

amiro-blt / Target / Modules / DiWheelDrive_1-1 / Boot / main.c @ d54d2f07

History | View | Annotate | Download (39.288 KB)

1
/************************************************************************************//**
2
* \file         Demo\ARMCM3_STM32_Olimex_STM32P103_GCC\Boot\main.c
3
* \brief        Bootloader application source file.
4
* \ingroup      Boot_ARMCM3_STM32_Olimex_STM32P103_GCC
5
* \internal
6
*----------------------------------------------------------------------------------------
7
*                          C O P Y R I G H T
8
*----------------------------------------------------------------------------------------
9
*   Copyright (c) 2012  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
* 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
* proprietary components. The exception text is included at the bottom of the license
29
* file <license.html>.
30
*
31
* \endinternal
32
****************************************************************************************/
33

    
34
/****************************************************************************************
35
* Include files
36
****************************************************************************************/
37
#include "boot.h"                                /* bootloader generic header          */
38
#include "stm32f10x.h"                           /* microcontroller registers          */
39
#include "stm32f10x_conf.h"                      /* STM32 peripheral drivers           */
40
#include "timer.h"
41
#include "ARMCM3_STM32/types.h"
42
#include "AMiRo/amiroblt.h"
43
#include "AMiRo/helper.h"
44

    
45
/****************************************************************************************
46
* Defines
47
****************************************************************************************/
48
#define WKUP_GPIO           GPIOA
49
#define WKUP_PIN            GPIO_Pin_0
50
#define LED_GPIO            GPIOA
51
#define LED_PIN             GPIO_Pin_1
52
#define DRIVE_PWM1A_GPIO    GPIOA
53
#define DRIVE_PWM1A_PIN     GPIO_Pin_2
54
#define DRIVE_PWM1B_GPIO    GPIOA
55
#define DRIVE_PWM1B_PIN     GPIO_Pin_3
56
#define MOTION_SCLK_GPIO    GPIOA
57
#define MOTION_SCLK_PIN     GPIO_Pin_5
58
#define MOTION_MISO_GPIO    GPIOA
59
#define MOTION_MISO_PIN     GPIO_Pin_6
60
#define MOTION_MOSI_GPIO    GPIOA
61
#define MOTION_MOSI_PIN     GPIO_Pin_7
62
#define PROG_RX_GPIO        GPIOA
63
#define PROG_RX_PIN         GPIO_Pin_9
64
#define PROG_TX_GPIO        GPIOA
65
#define PROG_TX_PIN         GPIO_Pin_10
66
#define CAN_RX_GPIO         GPIOA
67
#define CAN_RX_PIN          GPIO_Pin_11
68
#define CAN_TX_GPIO         GPIOA
69
#define CAN_TX_PIN          GPIO_Pin_12
70
#define SWDIO_GPIO          GPIOA
71
#define SWDIO_PIN           GPIO_Pin_13
72
#define SWCLK_GPIO          GPIOA
73
#define SWCLK_PIN           GPIO_Pin_14
74
#define DRIVE_PWM2B_GPIO    GPIOA
75
#define DRIVE_PWM2B_PIN     GPIO_Pin_15
76

    
77
#define DRIVE_SENSE2_GPIO   GPIOB
78
#define DRIVE_SENSE2_PIN    GPIO_Pin_1
79
#define POWER_EN_GPIO       GPIOB
80
#define POWER_EN_PIN        GPIO_Pin_2
81
#define DRIVE_PWM2A_GPIO    GPIOB
82
#define DRIVE_PWM2A_PIN     GPIO_Pin_3
83
#define COMPASS_DRDY_GPIO   GPIOB
84
#define COMPASS_DRDY_PIN    GPIO_Pin_5
85
#define DRIVE_ENC1A_GPIO    GPIOB
86
#define DRIVE_ENC1A_PIN     GPIO_Pin_6
87
#define DRIVE_ENC1B_GPIO    GPIOB
88
#define DRIVE_ENC1B_PIN     GPIO_Pin_7
89
#define COMPASS_SCL_GPIO    GPIOB
90
#define COMPASS_SCL_PIN     GPIO_Pin_8
91
#define COMPASS_SDA_GPIO    GPIOB
92
#define COMPASS_SDA_PIN     GPIO_Pin_9
93
#define IR_SCL_GPIO         GPIOB
94
#define IR_SCL_PIN          GPIO_Pin_10
95
#define IR_SDA_GPIO         GPIOB
96
#define IR_SDA_PIN          GPIO_Pin_11
97
#define IR_INT_GPIO         GPIOB
98
#define IR_INT_PIN          GPIO_Pin_12
99
#define GYRP_DRDY_GPIO      GPIOB
100
#define GYRO_DRDY_PIN       GPIO_Pin_13
101
#define SYS_UART_UP_GPIO    GPIOB
102
#define SYS_UART_UP_PIN     GPIO_Pin_14
103
#define ACCEL_INT_N_GPIO    GPIOB
104
#define ACCEL_INT_N_PIN     GPIO_Pin_15
105

    
106
#define DRIVE_SENSE1_GPIO   GPIOC
107
#define DRIVE_SENSE1_PIN    GPIO_Pin_0
108
#define SYS_SYNC_N_GPIO     GPIOC
109
#define SYS_SYNC_N_PIN      GPIO_Pin_1
110
#define PATH_DCSTAT_GPIO    GPIOC
111
#define PATH_DCSTAT_PIN     GPIO_Pin_3
112
#define PATH_DCEN_GPIO      GPIOC
113
#define PATH_DCEN_PIN       GPIO_Pin_5
114
#define DRIVE_ENC2B_GPIO    GPIOC
115
#define DRIVE_ENC2B_PIN     GPIO_Pin_6
116
#define DRIVE_ENC2A_GPIO    GPIOC
117
#define DRIVE_ENC2A_PIN     GPIO_Pin_7
118
#define SYS_PD_N_GPIO       GPIOC
119
#define SYS_PD_N_PIN        GPIO_Pin_8
120
#define SYS_REG_EN_GPIO     GPIOC
121
#define SYS_REG_EN_PIN      GPIO_Pin_9
122
#define SYS_UART_RX_GPIO    GPIOC
123
#define SYS_UART_RX_PIN     GPIO_Pin_10
124
#define SYS_UART_TX_GPIO    GPIOC
125
#define SYS_UART_TX_PIN     GPIO_Pin_11
126
#define ACCEL_SS_N_GPIO     GPIOC
127
#define ACCEL_SS_N_PIN      GPIO_Pin_13
128
#define GYRO_SS_N_GPIO      GPIOC
129
#define GYRO_SS_N_PIN       GPIO_Pin_14
130

    
131
#define OSC_IN_GPIO         GPIOD
132
#define OSC_IN_PIN          GPIO_Pin_0
133
#define OSC_OUT_GPIO        GPIOD
134
#define OSC_OUT_PIN         GPIO_Pin_1
135
#define SYS_WARMRST_N_GPIO  GPIOD
136
#define SYS_WARMRST_N_PIN   GPIO_Pin_2
137

    
138
#define RESET_TIMEOUT_MS    100
139

    
140
/****************************************************************************************
141
* Function prototypes
142
****************************************************************************************/
143
static void Init(void);
144

    
145
static void initGpio();
146
static void initExti();
147
void configGpioForShutdown();
148

    
149
ErrorStatus handleColdReset();
150
ErrorStatus handleUartWakeup();
151
ErrorStatus handleAccelWakeup();
152

    
153
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type);
154
void shutdownToTransportation(const blt_bool exec_disambiguation);
155
void shutdownToDeepsleep(const blt_bool exec_disambiguation);
156
void shutdownToHibernate(const blt_bool exec_disambiguation);
157
void shutdownAndRestart(const blt_bool exec_disambiguation);
158

    
159
volatile blBackupRegister_t backup_reg;
160

    
161
/****************************************************************************************
162
* Callback configuration
163
****************************************************************************************/
164
void blCallbackShutdownTransportation(void);
165
void blCallbackShutdownDeepsleep(void);
166
void blCallbackShutdownHibernate(void);
167
void blCallbackShutdownRestart(void);
168
void blCallbackHandleShutdownRequest(void);
169

    
170
const blCallbackTable_t cbtable __attribute__ ((section ("_callback_table"))) = {
171
  .magicNumber = BL_MAGIC_NUMBER,
172
  .vBootloader = {BL_VERSION_ID_AMiRoBLT_Release, BL_VERSION_MAJOR, BL_VERSION_MINOR, 0},
173
  .vSSSP = {BL_VERSION_ID_SSSP, SSSP_VERSION_MAJOR, SSSP_VERSION_MINOR, 0},
174
  .vCompiler = {BL_VERSION_ID_GCC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__},  // currently only GCC is supported
175
  .cbShutdownHibernate = blCallbackShutdownHibernate,
176
  .cbShutdownDeepsleep = blCallbackShutdownDeepsleep,
177
  .cbShutdownTransportation = blCallbackShutdownTransportation,
178
  .cbShutdownRestart = blCallbackShutdownRestart,
179
  .cbHandleShutdownRequest = blCallbackHandleShutdownRequest,
180
  .cb5 = (void*)0,
181
  .cb6 = (void*)0,
182
  .cb7 = (void*)0,
183
  .cb8 = (void*)0,
184
  .cb9 = (void*)0,
185
  .cb10 = (void*)0,
186
  .cb11 = (void*)0
187
};
188

    
189

    
190
/************************************************************************************//**
191
** \brief     This is the entry point for the bootloader application and is called
192
**            by the reset interrupt vector after the C-startup routines executed.
193
** \return    Program return code.
194
**
195
****************************************************************************************/
196
int main(void)
197
{
198
  /* initialize the microcontroller */
199
  Init();
200

    
201
  /* activate some required clocks */
202
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
203
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
204

    
205
  /* initialize GPIOs and EXTI lines */
206
  initGpio();
207
  setLed(BLT_TRUE);
208
  initExti();
209

    
210
  /* initialize the timer */
211
  TimerInit();
212

    
213
  /* detect the primary reason for this wakeup/restart */
214
  backup_reg.wakeup_pri_reason =
215
      ((RCC_GetFlagStatus(RCC_FLAG_LPWRRST) == SET) ? BL_WAKEUP_PRI_RSN_LPWRRST : 0) |
216
      ((RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) ? BL_WAKEUP_PRI_RSN_WWDGRST : 0) |
217
      ((RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) ? BL_WAKEUP_PRI_RSN_IWDGRST : 0) |
218
      ((RCC_GetFlagStatus(RCC_FLAG_SFTRST) == SET) ? BL_WAKEUP_PRI_RSN_SFTRST : 0)   |
219
      ((RCC_GetFlagStatus(RCC_FLAG_PORRST) == SET) ? BL_WAKEUP_PRI_RSN_PORRST : 0)   |
220
      ((RCC_GetFlagStatus(RCC_FLAG_PINRST) == SET) ? BL_WAKEUP_PRI_RSN_PINRST : 0)   |
221
      ((PWR_GetFlagStatus(PWR_FLAG_WU) == SET) ? BL_WAKEUP_PRI_RSN_WKUP : 0);
222

    
223
  /* when woken from standby mode, detect the secondary reason for thiswakeup/reset */
224
  if ( (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_WKUP) && (PWR_GetFlagStatus(PWR_FLAG_SB) == SET) ) {
225
    if (GPIO_ReadInputDataBit(SYS_UART_UP_GPIO, SYS_UART_UP_PIN) == Bit_SET) {
226
      backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UART;
227
    } else {
228
      backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_ACCEL;
229
    }
230
  } else {
231
    backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UNKNOWN;
232
  }
233

    
234
  /* clear the flags */
235
  RCC_ClearFlag();
236
  PWR_ClearFlag(PWR_FLAG_WU);
237

    
238
  setLed(BLT_FALSE);
239

    
240
  /* wait 1ms for all signals to become stable */
241
  msleep(1);
242

    
243
  /* handle different wakeup/reset reasons */
244
  ErrorStatus status = ERROR;
245
  if (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_WKUP) {
246
    /* the system was woken via WKUP pin */
247
    /* differenciate between two wakeup types */
248
    switch (backup_reg.wakeup_sec_reason) {
249
      case BL_WAKEUP_SEC_RSN_UART:
250
        status = handleUartWakeup();
251
        break;
252
      case BL_WAKEUP_SEC_RSN_ACCEL:
253
        status = handleAccelWakeup();
254
        break;
255
      default:
256
        status = ERROR;
257
        break;
258
    }
259
  } else if (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_PINRST) {
260
    /* system was woken via NRST pin */
261
    status = handleColdReset();
262
  } else {
263
    /* system was woken/reset for an unexpected reason */
264
    blinkSOS(1);
265
    status = handleColdReset();
266
  }
267

    
268
  /* if something wehnt wrong, signal this failure */
269
  if (status != SUCCESS) {
270
    blinkSOSinf();
271
  }
272

    
273
  return 0;
274
} /*** end of main ***/
275

    
276

    
277
/************************************************************************************//**
278
** \brief     Initializes the microcontroller.
279
** \return    none.
280
**
281
****************************************************************************************/
282
static void Init(void)
283
{
284
  volatile blt_int32u StartUpCounter = 0, HSEStatus = 0;
285
  blt_int32u pll_multiplier;
286
#if (BOOT_FILE_LOGGING_ENABLE > 0) && (BOOT_COM_UART_ENABLE == 0)
287
  GPIO_InitTypeDef  GPIO_InitStruct;
288
  USART_InitTypeDef USART_InitStruct;
289
#endif
290

    
291
  /* reset the RCC clock configuration to the default reset state (for debug purpose) */
292
  /* set HSION bit */
293
  RCC->CR |= (blt_int32u)0x00000001;
294
  /* reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
295
  RCC->CFGR &= (blt_int32u)0xF8FF0000;
296
  /* reset HSEON, CSSON and PLLON bits */
297
  RCC->CR &= (blt_int32u)0xFEF6FFFF;
298
  /* reset HSEBYP bit */
299
  RCC->CR &= (blt_int32u)0xFFFBFFFF;
300
  /* reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
301
  RCC->CFGR &= (blt_int32u)0xFF80FFFF;
302
  /* disable all interrupts and clear pending bits  */
303
  RCC->CIR = 0x009F0000;
304
  /* enable HSE */
305
  RCC->CR |= ((blt_int32u)RCC_CR_HSEON);
306
  /* wait till HSE is ready and if Time out is reached exit */
307
  do
308
  {
309
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
310
    StartUpCounter++;
311
  }
312
  while((HSEStatus == 0) && (StartUpCounter != 1500));
313
  /* check if time out was reached */
314
  if ((RCC->CR & RCC_CR_HSERDY) == RESET)
315
  {
316
    /* cannot continue when HSE is not ready */
317
    ASSERT_RT(BLT_FALSE);
318
  }
319
  /* enable flash prefetch buffer */
320
  FLASH->ACR |= FLASH_ACR_PRFTBE;
321
  /* reset flash wait state configuration to default 0 wait states */
322
  FLASH->ACR &= (blt_int32u)((blt_int32u)~FLASH_ACR_LATENCY);
323
#if (BOOT_CPU_SYSTEM_SPEED_KHZ > 48000)
324
  /* configure 2 flash wait states */
325
  FLASH->ACR |= (blt_int32u)FLASH_ACR_LATENCY_2;
326
#elif (BOOT_CPU_SYSTEM_SPEED_KHZ > 24000)
327
  /* configure 1 flash wait states */
328
  FLASH->ACR |= (blt_int32u)FLASH_ACR_LATENCY_1;
329
#endif
330
  /* HCLK = SYSCLK */
331
  RCC->CFGR |= (blt_int32u)RCC_CFGR_HPRE_DIV1;
332
  /* PCLK2 = HCLK/2 */
333
  RCC->CFGR |= (blt_int32u)RCC_CFGR_PPRE2_DIV2;
334
  /* PCLK1 = HCLK/2 */
335
  RCC->CFGR |= (blt_int32u)RCC_CFGR_PPRE1_DIV2;
336
  /* reset PLL configuration */
337
  RCC->CFGR &= (blt_int32u)((blt_int32u)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | \
338
                                          RCC_CFGR_PLLMULL));
339
  /* assert that the pll_multiplier is between 2 and 16 */
340
  ASSERT_CT((BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ) >= 2);
341
  ASSERT_CT((BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ) <= 16);
342
  /* calculate multiplier value */
343
  pll_multiplier = BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ;
344
  /* convert to register value */
345
  pll_multiplier = (blt_int32u)((pll_multiplier - 2) << 18);
346
  /* set the PLL multiplier and clock source */
347
  RCC->CFGR |= (blt_int32u)(RCC_CFGR_PLLSRC_HSE | pll_multiplier);
348
  /* enable PLL */
349
  RCC->CR |= RCC_CR_PLLON;
350
  /* wait till PLL is ready */
351
  while((RCC->CR & RCC_CR_PLLRDY) == 0)
352
  {
353
  }
354
  /* select PLL as system clock source */
355
  RCC->CFGR &= (blt_int32u)((blt_int32u)~(RCC_CFGR_SW));
356
  RCC->CFGR |= (blt_int32u)RCC_CFGR_SW_PLL;
357
  /* wait till PLL is used as system clock source */
358
  while ((RCC->CFGR & (blt_int32u)RCC_CFGR_SWS) != (blt_int32u)0x08)
359
  {
360
  }
361

    
362
  /* remap JTAG pins */
363
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
364
  AFIO->MAPR &= ~(blt_int32u)((blt_int32u)0x7 << 24);
365
  AFIO->MAPR |=  (blt_int32u)((blt_int32u)0x2 << 24);
366
  /* all input */
367

    
368
#if (BOOT_COM_CAN_ENABLE > 0 || BOOT_GATE_CAN_ENABLE > 0)
369
  /* enable clocks for CAN transmitter and receiver pins (GPIOB and AFIO) */
370
  RCC->APB2ENR |= (blt_int32u)(0x00000004 | 0x00000001);
371
  /* configure CAN Rx (GPIOA11) as alternate function input */
372
  /* first reset the configuration */
373
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 12);
374
  /* CNF8[1:0] = %01 and MODE8[1:0] = %00 */
375
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0x4 << 12);
376
  /* configure CAN Tx (GPIOA12) as alternate function push-pull */
377
  /* first reset the configuration */
378
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 16);
379
  /* CNF9[1:0] = %11 and MODE9[1:0] = %11 */
380
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0xb << 16);
381

    
382
  /* remap CAN1 pins to PortA */
383
  AFIO->MAPR &= ~(blt_int32u)((blt_int32u)0x3 << 13);
384
  AFIO->MAPR |=  (blt_int32u)((blt_int32u)0x0 << 13);
385
#endif
386

    
387
#if (BOOT_COM_UART_ENABLE > 0 || BOOT_GATE_UART_ENABLE > 0)
388
  /* enable clocks for USART1 peripheral, transmitter and receiver pins (GPIOA and AFIO) */
389
  RCC->APB2ENR |= (blt_int32u)(0x00004000 | 0x00000004 | 0x00000001);
390
  /* configure USART1 Tx (GPIOA9) as alternate function push-pull */
391
  /* first reset the configuration */
392
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 4);
393
  /* CNF2[1:0] = %10 and MODE2[1:0] = %11 */
394
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0xb << 4);
395
  /* configure USART1 Rx (GPIOA10) as alternate function input floating */
396
  /* first reset the configuration */
397
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 8);
398
  /* CNF2[1:0] = %01 and MODE2[1:0] = %00 */
399
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0x4 << 8);
400
#endif
401

    
402
} /*** end of Init ***/
403

    
404
/*
405
 * Initializes all GPIO used by the bootloader
406
 */
407
static void initGpio() {
408
  GPIO_InitTypeDef gpio_init;
409

    
410
  /*
411
   * OUTPUTS
412
   */
413

    
414
  /* initialize LED and push it up (inactive) */
415
  GPIO_SetBits(LED_GPIO, LED_PIN);
416
  gpio_init.GPIO_Pin    = LED_PIN;
417
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
418
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
419
  GPIO_Init(LED_GPIO, &gpio_init);
420

    
421
  /* initialize SYS_PD_N and let it go (inactive) */
422
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
423
  gpio_init.GPIO_Pin    = SYS_PD_N_PIN;
424
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
425
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
426
  GPIO_Init(SYS_PD_N_GPIO, &gpio_init);
427

    
428
  /* initialize SYS_SYNC_N and pull it down (active) */
429
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
430
  gpio_init.GPIO_Pin    = SYS_SYNC_N_PIN;
431
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
432
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
433
  GPIO_Init(SYS_SYNC_N_GPIO, &gpio_init);
434

    
435
  /* initialize SYS_WARMST_N and let it go (active) */
436
  GPIO_SetBits(SYS_WARMRST_N_GPIO, SYS_WARMRST_N_PIN);
437
  gpio_init.GPIO_Pin    = SYS_WARMRST_N_PIN;
438
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
439
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
440
  GPIO_Init(SYS_WARMRST_N_GPIO, &gpio_init);
441

    
442
  /* initialize SYS_UART_UP and let it go (inactive) */
443
  GPIO_SetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
444
  gpio_init.GPIO_Pin    = SYS_UART_UP_PIN;
445
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
446
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
447
  GPIO_Init(SYS_UART_UP_GPIO, &gpio_init);
448

    
449
  /* initialize PATH_DCEN and pull it down (inactive) */
450
  GPIO_ResetBits(PATH_DCEN_GPIO, PATH_DCEN_PIN);
451
  gpio_init.GPIO_Pin    = PATH_DCEN_PIN;
452
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
453
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
454
  GPIO_Init(PATH_DCEN_GPIO, &gpio_init);
455

    
456
  /*
457
   * INPUTS
458
   */
459

    
460
  /* initialize the input ACCEL_INT_N */
461
  gpio_init.GPIO_Pin    = ACCEL_INT_N_PIN;
462
  gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
463
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
464
  GPIO_Init(ACCEL_INT_N_GPIO, &gpio_init);
465

    
466
  return;
467
} /*** end of initGpio ***/
468

    
469
/*
470
 * Initialize all EXTI lines
471
 */
472
static void initExti() {
473
  /* configure EXTI lines */
474
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource1); // SYS_SYNC_N
475
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource2); // SYS_WARMRST_N
476
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource3); // PATH_DCSTAT
477
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource5); // COMPASS_DRDY
478
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource8); // SYS_PD_N
479
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource9); // SYS_REG_EN
480
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12); // IR_INT
481
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource13); // GYRO_DRDY
482
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14); // SYS_UART_UP
483
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource15); // ACCEL_INT_N
484

    
485
  return;
486
}
487

    
488
/*
489
 * Signals, which type of low-power mode the system shall enter after the shutdown sequence.
490
 */
491
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type) {
492
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
493
  ErrorStatus ret_val = ERROR;
494

    
495
  switch (type) {
496
    case BL_SHUTDOWN_PRI_RSN_UNKNOWN:
497
    case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
498
    case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
499
    case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
500
    {
501
      // broadcast a number of pulses, depending on the argument
502
      uint8_t pulse_counter = 0;
503
      for (pulse_counter = 0; pulse_counter < type; ++pulse_counter) {
504
        msleep(1);
505
        GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
506
        msleep(1);
507
        GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
508
      }
509
      // wait for timeout
510
      msleep(10);
511
      ret_val = SUCCESS;
512
      break;
513
    }
514
    case BL_SHUTDOWN_PRI_RSN_RESTART:
515
    {
516
      // since there is no ambiguity for restart requests, no pulses are generated
517
      msleep(10);
518
      ret_val = SUCCESS;
519
      break;
520
    }
521
    default:
522
      ret_val = ERROR;
523
      break;
524
  }
525

    
526
  return ret_val;
527
} /*** end of shutdownDisambiguationProcedure ***/
528

    
529
/*
530
 * Final shutdown of the system to enter transportation mode.
531
 */
532
void shutdownToTransportation(const blt_bool exec_disambiguation) {
533
  /* configure some criticpal GPIOs as input
534
   * This is required, because otherwise some hardware might be powered through these signals */
535
  configGpioForShutdown();
536

    
537
  /* turn off the motors */
538
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
539

    
540
  /* deactivate the WKUP pin */
541
  PWR_WakeUpPinCmd(DISABLE);
542

    
543
  /* deactivate any RTC related events */
544
  RTC_ITConfig(RTC_IT_ALR | RTC_IT_OW | RTC_IT_SEC, DISABLE);
545
  RTC_ClearFlag(~0);
546

    
547
  /* disable the IWDG */
548
  IWDG_ReloadCounter();
549

    
550
  /* wait for all boards to be ready for shutdown */
551
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
552
  if (GPIO_ReadInputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
553
    // this must skipped if the pullup voltage (VIO3.3) is not active
554
    setLed(BLT_TRUE);
555
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
556
    setLed(BLT_FALSE);
557
  }
558

    
559
  if (exec_disambiguation == BLT_TRUE) {
560
    /* execute disambiguation procedure and signal all modules to enter transportation mode */
561
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_TRANSPORT) != SUCCESS) {
562
      blinkSOS(1);
563
      msleep(10);
564
    }
565
  }
566

    
567
  /* morse 'OK' via the LED to signal that shutdown was successful */
568
  blinkOK(1);
569

    
570
  /* enter standby mode */
571
  PWR_EnterSTANDBYMode();
572

    
573
  return;
574
} /*** end of shutdownToTransportation ***/
575

    
576
/*
577
 * Final shutdown of the system to enter deepseleep mode.
578
 */
579
void shutdownToDeepsleep(const blt_bool exec_disambiguation) {
580
  /* configure some criticpal GPIOs as input
581
   * This is required, because otherwise some hardware might be powered through these signals */
582
  configGpioForShutdown();
583

    
584
  /* turn off the motors */
585
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
586

    
587
  /* deactivate the WKUP pin */
588
  PWR_WakeUpPinCmd(ENABLE);
589

    
590
  /*
591
   * Configuration of RTC and IWDG belongs to the OS.
592
   */
593

    
594
  /* wait for all boards to be ready for shutdown */
595
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
596
  if (GPIO_ReadInputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
597
    // this must skipped if the pullup voltage (VIO3.3) is not active
598
    setLed(BLT_TRUE);
599
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
600
    setLed(BLT_FALSE);
601
  }
602

    
603
  if (exec_disambiguation == BLT_TRUE) {
604
    /* execute disambiguation procedure and signal all modules to enter deepsleep mode */
605
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_DEEPSLEEP) != SUCCESS) {
606
      blinkSOS(1);
607
      msleep(10);
608
    }
609
  }
610

    
611
  /* morse 'OK' via the LED to signal that shutdown was successful */
612
  blinkOK(1);
613

    
614
  /* enter standby mode */
615
  PWR_EnterSTANDBYMode();
616

    
617
  return;
618
} /*** end of shutdownToDeepsleep ***/
619

    
620
/*
621
 * Final shutdown of the system to enter hibernate mode.
622
 */
623
void shutdownToHibernate(const blt_bool exec_disambiguation) {
624
  /* configure some criticpal GPIOs as input
625
   * This is required, because otherwise some hardware might be powered through these signals */
626
  configGpioForShutdown();
627

    
628
  /* turn off the motors */
629
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
630

    
631
  /* deactivate the WKUP pin */
632
  PWR_WakeUpPinCmd(ENABLE);
633

    
634
  /*
635
   * Configuration of RTC and IWDG belongs to the OS.
636
   */
637

    
638
  /* wait for all boards to be ready for shutdown */
639
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
640
  if (GPIO_ReadInputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
641
    // this must skipped if the pullup voltage (VIO3.3) is not active
642
    setLed(BLT_TRUE);
643
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
644
    setLed(BLT_FALSE);
645
  }
646

    
647
  if (exec_disambiguation == BLT_TRUE) {
648
    /* execute disambiguation procedure and signal all modules to enter deepsleep mode */
649
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_HIBERNATE) != SUCCESS) {
650
      blinkSOS(1);
651
      msleep(10);
652
    }
653
  }
654

    
655
  /* morse 'OK' via the LED to signal that shutdown was successful */
656
  blinkOK(1);
657

    
658
  /* enter standby mode */
659
  PWR_EnterSTANDBYMode();
660

    
661
  return;
662
} /* end of shutdownToHibernate ***/
663

    
664
/*
665
 * Final shutdown of the system and restart.
666
 */
667
void shutdownAndRestart(const blt_bool exec_disambiguation) {
668
  /* configure some criticpal GPIOs as input
669
   * This is required, because otherwise some hardware might be powered through these signals */
670
  configGpioForShutdown();
671

    
672
  /* turn off the motors */
673
  GPIO_ResetBits(POWER_EN_GPIO, POWER_EN_PIN);
674

    
675
  /* prepare for low-power mode */
676
  PWR_WakeUpPinCmd(DISABLE); // disable WKUP pin
677
  RTC_ITConfig(RTC_IT_ALR | RTC_IT_OW | RTC_IT_SEC, DISABLE); // unset RTC events
678
  RTC_ClearFlag(~0); // clear pending RTC events
679
  IWDG_ReloadCounter(); // disable IWDG
680

    
681
  /* wait for all boards to be ready for shutdown */
682
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
683
  if (GPIO_ReadInputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
684
    // this must skipped if the pullup voltage (VIO3.3) is not active
685
    setLed(BLT_TRUE);
686
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
687
    setLed(BLT_FALSE);
688
  }
689

    
690
  if (exec_disambiguation == BLT_TRUE) {
691
    /* execute disambiguation procedure and signal all modules to restart in default mode */
692
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_RESTART) != SUCCESS) {
693
      blinkSOS(1);
694
      msleep(10);
695
    }
696
  }
697

    
698
  /* morse 'OK' via the LED to signal that shutdown was successful */
699
  blinkOK(1);
700

    
701
  /* enter standby mode */
702
  PWR_EnterSTANDBYMode();
703

    
704
  /*
705
   * Even though this module will not restart the system by its own, the PowerManagement will reset the system.
706
   */
707

    
708
  return;
709
} /*** end of shutdownAndRestart***/
710

    
711
/*
712
 * Configures some GPIO pins as inputs for safety reasons.
713
 * Under certain circumstances, these pins might power hardware that is supposed to be shut down.
714
 */
715
void configGpioForShutdown() {
716
  /* setup the configuration */
717
  GPIO_InitTypeDef gpio_init;
718
  gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
719
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
720

    
721
  /* configure SYS_UART_TX */
722
  gpio_init.GPIO_Pin = SYS_UART_TX_PIN;
723
  GPIO_Init(SYS_UART_TX_GPIO, &gpio_init);
724

    
725
  /* configure CAN_TX */
726
  gpio_init.GPIO_Pin = CAN_TX_PIN;
727
  GPIO_Init(CAN_TX_GPIO, &gpio_init);
728

    
729
  /* configure all MOTION (SPI) signals */
730
  gpio_init.GPIO_Pin = MOTION_SCLK_PIN;
731
  GPIO_Init(MOTION_SCLK_GPIO, &gpio_init);
732
  gpio_init.GPIO_Pin = MOTION_MISO_PIN;
733
  GPIO_Init(MOTION_MISO_GPIO, &gpio_init);
734
  gpio_init.GPIO_Pin = MOTION_MOSI_PIN;
735
  GPIO_Init(MOTION_MOSI_GPIO, &gpio_init);
736
  gpio_init.GPIO_Pin = ACCEL_SS_N_PIN;
737
  GPIO_Init(ACCEL_SS_N_GPIO, &gpio_init);
738
  gpio_init.GPIO_Pin = GYRO_SS_N_PIN;
739
  GPIO_Init(GYRO_SS_N_GPIO, &gpio_init);
740

    
741
  return;
742
} /*** end of configGpioForShutdown ***/
743

    
744
/*
745
 * System was reset via the NRST pin or the reason could not be detected.
746
 * In this case, there are three possibilities how to act:
747
 * 1) When the SYS_WARMRST_N signal becomes inactive, flashing mode is entered and the system will try to load the OS.
748
 * 2) When the SYS_UART_UP signal becomes active (low), the system will enter hibernate mode to enable charging via the pins.
749
 * 3) If none of both happens and a timeout occurs, the system enters deepsleep mode.
750
 */
751
ErrorStatus handleColdReset() {
752
  /* wait until either the SYS_WARMRST_N signal goes up, or SYS_UART_UP goes down */
753
  enum CRST_SIG {CRST_SIG_SYS_WARMRST_N,
754
                 CRST_SIG_SYS_UART_UP,
755
                 CRST_SIG_TIMEOUT
756
                } sig;
757
  uint32_t loopStartTime = 0;
758
  saTimerUpdate(&loopStartTime);
759
  uint32_t currentTime = loopStartTime;
760
  setLed(BLT_TRUE);
761
  while (1) {
762
    /* read the input signals */
763
    if (GPIO_ReadInputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET &&
764
        GPIO_ReadInputDataBit(SYS_WARMRST_N_GPIO, SYS_WARMRST_N_PIN) == Bit_SET) {
765
      sig = CRST_SIG_SYS_WARMRST_N;
766
      break;
767
    }
768
    if (GPIO_ReadInputDataBit(SYS_UART_UP_GPIO, SYS_UART_UP_PIN) == Bit_RESET) {
769
      sig = CRST_SIG_SYS_UART_UP;
770
      break;
771
    }
772

    
773
    /* check for a timeout */
774
    saTimerUpdate(&currentTime);
775
    if (currentTime > loopStartTime + RESET_TIMEOUT_MS) {
776
      sig = CRST_SIG_TIMEOUT;
777
      break;
778
    }
779
  }
780
  setLed(BLT_FALSE);
781

    
782
  /* depending on the signal, react accordingly */
783
  switch (sig) {
784
    /* activation of the slave modules signales to boot the OS */
785
    case CRST_SIG_SYS_WARMRST_N:
786
    {
787
      /* enable CAN clock */
788
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
789

    
790
      /* initialize the bootloader */
791
      BootInit();
792

    
793
      /* start the infinite program loop */
794
      uint32_t loopStartTime = 0;
795
      saTimerUpdate(&loopStartTime);
796
      uint32_t currentTime = loopStartTime;
797
      while (1)
798
      {
799
//        /* make the LED "double-blink" */
800
//        saTimerUpdate(&currentTime);
801
//        if (currentTime < loopStartTime + 50) {
802
//          setLed(BLT_TRUE);
803
//        } else if (currentTime < loopStartTime + 50+100) {
804
//          setLed(BLT_FALSE);
805
//        } else if (currentTime < loopStartTime + 50+100+50) {
806
//          setLed(BLT_TRUE);
807
//        } else if ( currentTime < loopStartTime + 50+100+50+300) {
808
//          setLed(BLT_FALSE);
809
//        } else {
810
//          loopStartTime = currentTime;
811
//        }
812

    
813
        /* run the bootloader task */
814
        BootTask();
815

    
816
        /* check the SYS_PD_N signal */
817
        if (GPIO_ReadInputDataBit(SYS_PD_N_GPIO, SYS_PD_N_PIN) == Bit_RESET) {
818
          blCallbackHandleShutdownRequest();
819
          return SUCCESS;
820
        }
821
      }
822

    
823
      break;
824
    }
825
    /* activation of the UART_UP signal indicates that this module shall enter hibernate mode */
826
    case CRST_SIG_SYS_UART_UP:
827
    {
828
      /* indicate that the MCU is busy */
829
      GPIO_ResetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
830

    
831
      /* enable the charging pins */
832
      GPIO_SetBits(PATH_DCEN_GPIO, PATH_DCEN_PIN);
833

    
834
      /* wait some time so the systen voltage (VSYS) is stable if it is supplied via the pins */
835
      msleep(10);
836

    
837
      /* indicate that the MCU is not busy anymore */
838
      GPIO_SetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
839

    
840
      /* configure the accelerometer external interrupt as event */
841
      EXTI_InitTypeDef exti;
842
      exti.EXTI_Line = EXTI_Line15;
843
      exti.EXTI_Mode = EXTI_Mode_Event;
844
      exti.EXTI_Trigger = EXTI_Trigger_Falling;
845
      exti.EXTI_LineCmd = ENABLE;
846
      EXTI_Init(&exti);
847

    
848
      /* sleep until something happens */
849
      __WFE();
850

    
851
      /* clear all pending EXTI events */
852
      EXTI_DeInit();
853
      EXTI_ClearFlag(EXTI_Line15);
854

    
855
      /* handle accelerometer wakeup
856
       * note: In fact, the only events that will occur at this point are an interrupt event from the accelerometer, or a
857
       * system reset from the PowerManagement via the NRST pin. Thus, if the following code is reached, it must have
858
       * been the accelerometer.
859
       */
860

    
861
      /* as as after a normal wakeup from the accelerometer */
862
      return handleAccelWakeup();
863

    
864
      break;
865
    }
866
    /* if a timeout occurred, the system enters deepsleep mode */
867
    case CRST_SIG_TIMEOUT:
868
    {
869
      /* reconfigure the LED_GPIO as input so it will not light up (and thus save energy) */
870
      GPIO_InitTypeDef gpio_init;
871
      gpio_init.GPIO_Pin    = LED_PIN;
872
      gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
873
      gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
874
      GPIO_Init(LED_GPIO, &gpio_init);
875

    
876
      /* reconfigure SYS_PD_N as input so the callback will not indicate a shutdown */
877
      gpio_init.GPIO_Pin    = SYS_PD_N_PIN;
878
      gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
879
      gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
880
      GPIO_Init(SYS_PD_N_GPIO, &gpio_init);
881

    
882
      blCallbackShutdownDeepsleep();
883
      break;
884
    }
885
    default:
886
      break;
887
  }
888

    
889
  return ERROR;
890
} /*** end of handleColdReset ***/
891

    
892
/*
893
 * System was woken up via the WKUP pin and the SYS_UART_UP signal was found to be responsible.
894
 * In this case, the system starts as after a cold reset.
895
 */
896
ErrorStatus handleUartWakeup() {
897
  return handleColdReset();
898
} /*** end of handleUartWakeup ***/
899

    
900
/*
901
 * System was woken up via the WKUP pin and the ACCEL_INT_N signal was found to be responsible.
902
 * The SYS_UART_UP signal is used to wake the PowerManagement before a normal cold reset is performed.
903
 */
904
ErrorStatus handleAccelWakeup() {
905
  /* wakeup the PowerManegement (ensure that the pulse is detected) */
906
  GPIO_ResetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
907
  msleep(1);
908
  GPIO_SetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
909

    
910
  return handleColdReset();
911
} /*** end of handleAccelWakeu ***/
912

    
913
/*
914
 * Callback function that handles the system shutdown and enters transportation mode.
915
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
916
 * In transportation low-power mode the system can only be woken up by pulling down the NRST signal.
917
 * Furthermore, the system can not be charged when in transportation mode.
918
 */
919
void blCallbackShutdownTransportation(void) {
920
  /* make sure that the required clocks are activated */
921
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
922
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
923

    
924
  /* set/keep the SYS_SYNC and SYS_PD signals active */
925
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
926
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
927

    
928
  setLed(BLT_TRUE);
929
  saTimerInit();
930

    
931
  shutdownToTransportation(BLT_TRUE);
932

    
933
  return;
934
} /*** end of blCallbackShutdownTransportation ***/
935

    
936
/*
937
 * Callback function that handles the system shutdown and enters deepsleep mode.
938
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
939
 * In deepsleep low-power mode the system can only be woken up via the NRST or the WKUP signal, or the RTC or IWDG, if configured.
940
 */
941
void blCallbackShutdownDeepsleep(void) {
942
  /* make sure that the required clocks are activated */
943
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
944
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
945

    
946
  /* set/keep the SYS_SYNC and SYS_PD signals active */
947
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
948
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
949

    
950
  saTimerInit();
951

    
952
  shutdownToDeepsleep(BLT_TRUE);
953

    
954
  return;
955
} /*** end of blCallbackShutdownDeepsleep ***/
956

    
957
/*
958
 * Callback function that handles the system shutdown and enters hibernate mode.
959
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
960
 */
961
void blCallbackShutdownHibernate(void) {
962
  /* make sure that the required clocks are activated */
963
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
964
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
965

    
966
  /* set/keep the SYS_SYNC and SYS_PD signals active */
967
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
968
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
969

    
970
  saTimerInit();
971

    
972
  shutdownToHibernate(BLT_TRUE);
973

    
974
  return;
975
} /*** end of blCallbackShutdownHibernate ***/
976

    
977
/*
978
 * Callback function that handles the system shutdown and initializes a restart.
979
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
980
 */
981
void blCallbackShutdownRestart(void) {
982
  /* make sure that the required clocks are activated */
983
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
984
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
985

    
986
  /* set/keep the SYS_SYNC and SYS_PD signal active */
987
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
988
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
989

    
990
  /* ensure that all modules had a chance to detect the pulse on SYS_PD_N */
991
  saTimerInit();
992
  msleep(1);
993
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
994
  msleep(1);
995

    
996
  shutdownAndRestart(BLT_TRUE);
997

    
998
  return;
999
} /*** end of blCallbackRestart ***/
1000

    
1001
/*
1002
 * Callback function that handles a system shutdown/restart request from another module.
1003
 * Depending on the result of the disambiguation procedure, the module will enter the according low-power mode or restart.
1004
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
1005
 */
1006
void blCallbackHandleShutdownRequest(void) {
1007
  /* make sure that the required clocks are activated */
1008
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
1009
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
1010

    
1011
  /* set/keep the SYS_SYNC and SYS_PD signal active */
1012
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
1013
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
1014

    
1015
  /* initialized the standalone timer */
1016
  saTimerInit();
1017

    
1018
  setLed(BLT_TRUE);
1019

    
1020
  /* deactivate SYS_PD_N and ensure that all modules had a chance to detect the falling edge */
1021
  msleep(1);
1022
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
1023
  msleep(1);
1024

    
1025
  /* wait for all boards to be ready for shutdown */
1026
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
1027
  if (GPIO_ReadOutputDataBit(SYS_REG_EN_GPIO, SYS_REG_EN_PIN) == Bit_SET) {
1028
    // this must skipped if the pullup voltage (VIO3.3) is not active
1029
    setLed(BLT_TRUE);
1030
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
1031
    setLed(BLT_FALSE);
1032
  }
1033

    
1034
  /* check ths SYS_PD_N signal, whether the system shall shutdown or restart */
1035
  blt_bool shutdown_nrestart = (GPIO_ReadInputDataBit(SYS_PD_N_GPIO, SYS_PD_N_PIN) == Bit_RESET) ? BLT_TRUE : BLT_FALSE;
1036

    
1037
  /* disambiguation procedure (passive) */
1038
  uint32_t pulse_counter = 0;
1039
  while (waitForSignalTimeout(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_RESET, 10)) {
1040
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
1041
    ++pulse_counter;
1042
  }
1043

    
1044
  /* evaluate and hanlde disambiguation result */
1045
  if (shutdown_nrestart == BLT_TRUE) {
1046
    /* shutdown request */
1047

    
1048
    /* handle special cases */
1049
    if (pulse_counter == BL_SHUTDOWN_PRI_RSN_UNKNOWN) {
1050
      /* no pulse at all was received */
1051
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
1052
    } else if (pulse_counter != BL_SHUTDOWN_PRI_RSN_HIBERNATE &&
1053
               pulse_counter != BL_SHUTDOWN_PRI_RSN_DEEPSLEEP &&
1054
               pulse_counter != BL_SHUTDOWN_PRI_RSN_TRANSPORT) {
1055
      /* invalid number of pulses received */
1056
      blinkSOS(1);
1057
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
1058
    }
1059

    
1060
    switch (pulse_counter) {
1061
      case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
1062
        shutdownToHibernate(BLT_FALSE);
1063
        break;
1064
      case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
1065
        shutdownToDeepsleep(BLT_FALSE);
1066
        break;
1067
      case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
1068
        shutdownToTransportation(BLT_FALSE);
1069
        break;
1070
    }
1071
  } else {
1072
    /* restart request */
1073

    
1074
    /* there is no ambiguity for restart, so it is ignored */
1075
    shutdownAndRestart(BLT_FALSE);
1076
  }
1077

    
1078
  /* if this code is reached, the system did neither shut down, nor restart.
1079
   * This must never be the case!
1080
   */
1081
  blinkSOSinf();
1082
  return;
1083
} /*** end of blCallbackHandleShutdownRequest ***/
1084

    
1085
/*********************************** end of main.c *************************************/