Statistics
| Branch: | Tag: | Revision:

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

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

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

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

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

    
139
#define RESET_TIMEOUT_MS    100
140

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

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

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

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

    
160
volatile blBackupRegister_t backup_reg;
161

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

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

    
190

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

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

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

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

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

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

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

    
239
  setLed(BLT_FALSE);
240

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

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

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

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

    
277

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

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

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

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

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

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

    
403
} /*** end of Init ***/
404

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

    
411
  /*
412
   * OUTPUTS
413
   */
414

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

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

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

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

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

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

    
457
  /*
458
   * INPUTS
459
   */
460

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

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

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

    
486
  return;
487
}
488

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
932
  shutdownToTransportation(BLT_TRUE);
933

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

    
937
/*
938
 * Callback function that handles the system shutdown and enters deepsleep mode.
939
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
940
 * 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.
941
 */
942
void blCallbackShutdownDeepsleep(void) {
943
  /* make sure that the required clocks are activated */
944
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
945
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
946

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

    
951
  saTimerInit();
952

    
953
  shutdownToDeepsleep(BLT_TRUE);
954

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

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

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

    
971
  saTimerInit();
972

    
973
  shutdownToHibernate(BLT_TRUE);
974

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

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

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

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

    
997
  shutdownAndRestart(BLT_TRUE);
998

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

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

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

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

    
1019
  setLed(BLT_TRUE);
1020

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

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

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

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

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

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

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

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

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

    
1086
/*********************************** end of main.c *************************************/