Statistics
| Branch: | Tag: | Revision:

amiro-blt / Target / Modules / LightRing_1-0 / Boot / main.c @ 03906dc3

History | View | Annotate | Download (29.847 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 "timer.h"
39
#include "ARMCM3_STM32/types.h"
40
#include "AMiRo/amiroblt.h"
41
#include "helper.h"
42
#include "iodef.h"
43

    
44
/****************************************************************************************
45
* Defines
46
****************************************************************************************/
47

    
48
/****************************************************************************************
49
* Function prototypes
50
****************************************************************************************/
51
static void Init(void);
52

    
53
static void initGpio();
54
static void initExti();
55
void configGpioForShutdown();
56

    
57
ErrorStatus handleWarmReset();
58

    
59
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type);
60
void shutdownToTransportation(const blt_bool exec_disambiguation);
61
void shutdownToDeepsleep(const blt_bool exec_disambiguation);
62
void shutdownToHibernate(const blt_bool exec_disambiguation);
63
void shutdownAndRestart(const blt_bool exec_disambiguation);
64

    
65
volatile blBackupRegister_t backup_reg;
66

    
67
/****************************************************************************************
68
* Callback configuration
69
****************************************************************************************/
70
void blCallbackShutdownTransportation(void);
71
void blCallbackShutdownDeepsleep(void);
72
void blCallbackShutdownHibernate(void);
73
void blCallbackShutdownRestart(void);
74
void blCallbackHandleShutdownRequest(void);
75

    
76
const blCallbackTable_t cbtable __attribute__ ((section ("_callback_table"))) = {
77
  .magicNumber = BL_MAGIC_NUMBER,
78
  .vBootloader = {BL_VERSION_ID_AMiRoBLT_Release, BL_VERSION_MAJOR, BL_VERSION_MINOR, 1},
79
  .vSSSP = {BL_VERSION_ID_SSSP, BL_SSSP_VERSION_MAJOR, BL_SSSP_VERSION_MINOR, 0},
80
  .vCompiler = {BL_VERSION_ID_GCC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__},  // currently only GCC is supported
81
  .cbShutdownHibernate = blCallbackShutdownHibernate,
82
  .cbShutdownDeepsleep = blCallbackShutdownDeepsleep,
83
  .cbShutdownTransportation = blCallbackShutdownTransportation,
84
  .cbShutdownRestart = blCallbackShutdownRestart,
85
  .cbHandleShutdownRequest = blCallbackHandleShutdownRequest,
86
  .cb5 = (void*)0,
87
  .cb6 = (void*)0,
88
  .cb7 = (void*)0,
89
  .cb8 = (void*)0,
90
  .cb9 = (void*)0,
91
  .cb10 = (void*)0,
92
  .cb11 = (void*)0
93
};
94

    
95
/************************************************************************************//**
96
** \brief     This is the entry point for the bootloader application and is called
97
**            by the reset interrupt vector after the C-startup routines executed.
98
** \return    Program return code.
99
**
100
****************************************************************************************/
101
int main(void)
102
{
103
  /* initialize the microcontroller */
104
  Init();
105

    
106
  /* activate some required cocks */
107
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
108
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
109

    
110
  /* initialize GPIOs and EXTI lines */
111
  initGpio();
112
  setLed(BLT_TRUE);
113
  initExti();
114

    
115
  /* initialize the timer */
116
  TimerInit();
117

    
118
  /* detect the primary reason for this wakeup/restart */
119
  backup_reg.wakeup_pri_reason =
120
      ((RCC_GetFlagStatus(RCC_FLAG_LPWRRST) == SET) ? BL_WAKEUP_PRI_RSN_LPWRRST : 0) |
121
      ((RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) ? BL_WAKEUP_PRI_RSN_WWDGRST : 0) |
122
      ((RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) ? BL_WAKEUP_PRI_RSN_IWDGRST : 0) |
123
      ((RCC_GetFlagStatus(RCC_FLAG_SFTRST) == SET) ? BL_WAKEUP_PRI_RSN_SFTRST : 0)   |
124
      ((RCC_GetFlagStatus(RCC_FLAG_PORRST) == SET) ? BL_WAKEUP_PRI_RSN_PORRST : 0)   |
125
      ((RCC_GetFlagStatus(RCC_FLAG_PINRST) == SET) ? BL_WAKEUP_PRI_RSN_PINRST : 0)   |
126
      ((PWR_GetFlagStatus(PWR_FLAG_WU) == SET) ? BL_WAKEUP_PRI_RSN_WKUP : 0);
127
  /* for this module there is no secondary wakeup reason */
128
  backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UNKNOWN;
129

    
130
  /* clear the flags */
131
  RCC_ClearFlag();
132
  PWR_ClearFlag(PWR_FLAG_WU);
133

    
134
  setLed(BLT_FALSE);
135

    
136
  /* hanlde different wakeup/reset reasons */
137
  ErrorStatus status = ERROR;
138
  if (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_PINRST) {
139
    /* system was woken via NRST pin */
140
    status = handleWarmReset();
141
  } else {
142
    /* system was woken/reset for an unexpected reason */
143
    blinkSOS(1);
144
    status = handleWarmReset();
145
  }
146

    
147
  /* if something went wrong, signal this failure */
148
  if (status != SUCCESS) {
149
    blinkSOSinf();
150
  }
151

    
152
  return 0;
153
} /*** end of main ***/
154

    
155

    
156
/************************************************************************************//**
157
** \brief     Initializes the microcontroller.
158
** \return    none.
159
**
160
****************************************************************************************/
161
static void Init(void)
162
{
163
  volatile blt_int32u StartUpCounter = 0, HSEStatus = 0;
164
  blt_int32u pll_multiplier;
165
#if (BOOT_FILE_LOGGING_ENABLE > 0) && (BOOT_COM_UART_ENABLE == 0) && (BOOT_GATE_UART_ENABLE == 0)
166
  GPIO_InitTypeDef  GPIO_InitStruct;
167
  USART_InitTypeDef USART_InitStruct;
168
#endif
169

    
170
  /* reset the RCC clock configuration to the default reset state (for debug purpose) */
171
  /* set HSION bit */
172
  RCC->CR |= (blt_int32u)0x00000001;
173
  /* reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
174
  RCC->CFGR &= (blt_int32u)0xF8FF0000;
175
  /* reset HSEON, CSSON and PLLON bits */
176
  RCC->CR &= (blt_int32u)0xFEF6FFFF;
177
  /* reset HSEBYP bit */
178
  RCC->CR &= (blt_int32u)0xFFFBFFFF;
179
  /* reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
180
  RCC->CFGR &= (blt_int32u)0xFF80FFFF;
181
  /* disable all interrupts and clear pending bits  */
182
  RCC->CIR = 0x009F0000;
183
  /* enable HSE */
184
  RCC->CR |= ((blt_int32u)RCC_CR_HSEON);
185
  /* wait till HSE is ready and if Time out is reached exit */
186
  do
187
  {
188
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
189
    StartUpCounter++;
190
  }
191
  while((HSEStatus == 0) && (StartUpCounter != 1500));
192
  /* check if time out was reached */
193
  if ((RCC->CR & RCC_CR_HSERDY) == RESET)
194
  {
195
    /* cannot continue when HSE is not ready */
196
    ASSERT_RT(BLT_FALSE);
197
  }
198
  /* enable flash prefetch buffer */
199
  FLASH->ACR |= FLASH_ACR_PRFTBE;
200
  /* reset flash wait state configuration to default 0 wait states */
201
  FLASH->ACR &= (blt_int32u)((blt_int32u)~FLASH_ACR_LATENCY);
202
#if (BOOT_CPU_SYSTEM_SPEED_KHZ > 48000)
203
  /* configure 2 flash wait states */
204
  FLASH->ACR |= (blt_int32u)FLASH_ACR_LATENCY_2;
205
#elif (BOOT_CPU_SYSTEM_SPEED_KHZ > 24000)
206
  /* configure 1 flash wait states */
207
  FLASH->ACR |= (blt_int32u)FLASH_ACR_LATENCY_1;
208
#endif
209
  /* HCLK = SYSCLK */
210
  RCC->CFGR |= (blt_int32u)RCC_CFGR_HPRE_DIV1;
211
  /* PCLK2 = HCLK/2 */
212
  RCC->CFGR |= (blt_int32u)RCC_CFGR_PPRE2_DIV2;
213
  /* PCLK1 = HCLK/2 */
214
  RCC->CFGR |= (blt_int32u)RCC_CFGR_PPRE1_DIV2;
215
  /* reset PLL configuration */
216
  RCC->CFGR &= (blt_int32u)((blt_int32u)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | \
217
                                          RCC_CFGR_PLLMULL));
218
  /* assert that the pll_multiplier is between 2 and 16 */
219
  ASSERT_CT((BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ) >= 2);
220
  ASSERT_CT((BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ) <= 16);
221
  /* calculate multiplier value */
222
  pll_multiplier = BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ;
223
  /* convert to register value */
224
  pll_multiplier = (blt_int32u)((pll_multiplier - 2) << 18);
225
  /* set the PLL multiplier and clock source */
226
  RCC->CFGR |= (blt_int32u)(RCC_CFGR_PLLSRC_HSE | pll_multiplier);
227
  /* enable PLL */
228
  RCC->CR |= RCC_CR_PLLON;
229
  /* wait till PLL is ready */
230
  while((RCC->CR & RCC_CR_PLLRDY) == 0)
231
  {
232
  }
233
  /* select PLL as system clock source */
234
  RCC->CFGR &= (blt_int32u)((blt_int32u)~(RCC_CFGR_SW));
235
  RCC->CFGR |= (blt_int32u)RCC_CFGR_SW_PLL;
236
  /* wait till PLL is used as system clock source */
237
  while ((RCC->CFGR & (blt_int32u)RCC_CFGR_SWS) != (blt_int32u)0x08)
238
  {
239
  }
240
#if (BOOT_COM_CAN_ENABLE > 0 || BOOT_GATE_CAN_ENABLE > 0)
241
  /* enable clocks for CAN transmitter and receiver pins (GPIOB and AFIO) */
242
  RCC->APB2ENR |= (blt_int32u)(0x00000004 | 0x00000001);
243
  /* configure CAN Rx (GPIOA11) as alternate function input */
244
  /* first reset the configuration */
245
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 12);
246
  /* CNF8[1:0] = %01 and MODE8[1:0] = %00 */
247
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0x4 << 12);
248
  /* configure CAN Tx (GPIOA12) as alternate function push-pull */
249
  /* first reset the configuration */
250
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 16);
251
  /* CNF9[1:0] = %11 and MODE9[1:0] = %11 */
252
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0xb << 16);
253

    
254
  /* remap CAN1 pins to PortA */
255
  AFIO->MAPR &= ~(blt_int32u)((blt_int32u)0x3 << 13);
256
  AFIO->MAPR |=  (blt_int32u)((blt_int32u)0x0 << 13);
257
  /* enable clocks for CAN controller peripheral */
258
  RCC->APB1ENR |= (blt_int32u)0x02000000;
259
#endif
260
#if (BOOT_COM_UART_ENABLE > 0 || BOOT_GATE_UART_ENABLE > 0)
261
  /* enable clocks for USART1 peripheral, transmitter and receiver pins (GPIOA and AFIO) */
262
  RCC->APB2ENR |= (blt_int32u)(0x00004000 | 0x00000004 | 0x00000001);
263
  /* configure USART1 Tx (GPIOA9) as alternate function push-pull */
264
  /* first reset the configuration */
265
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 4);
266
  /* CNF2[1:0] = %10 and MODE2[1:0] = %11 */
267
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0xb << 4);
268
  /* configure USART1 Rx (GPIOA10) as alternate function input floating */
269
  /* first reset the configuration */
270
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 8);
271
  /* CNF2[1:0] = %01 and MODE2[1:0] = %00 */
272
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0x4 << 8);
273

    
274
#if (BOOT_DEBUGGING_UART2_ENABLE > 0)
275
  /* enable clocks for USART2 peripheral */
276
  RCC->APB1ENR |= (blt_int32u)(0x00020000);
277
  /* configure USART2 Tx (GPIOA2) as alternate function push-pull */
278
  /* first reset the configuration */
279
  GPIOA->CRL &= ~(blt_int32u)((blt_int32u)0xf << 8);
280
  /* CNF2[1:0] = %10 and MODE2[1:0] = %11 */
281
  GPIOA->CRL |= (blt_int32u)((blt_int32u)0xb << 8);
282
  /* configure USART2 Rx (GPIOA3) as alternate function input floating */
283
  /* first reset the configuration */
284
  GPIOA->CRL &= ~(blt_int32u)((blt_int32u)0xf << 12);
285
  /* CNF2[1:0] = %01 and MODE2[1:0] = %00 */
286
  GPIOA->CRL |= (blt_int32u)((blt_int32u)0x4 << 12);
287
#endif
288

    
289
#elif (BOOT_FILE_LOGGING_ENABLE > 0)
290
  /* enable UART peripheral clock */
291
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
292
  /* enable GPIO peripheral clock for transmitter and receiver pins */
293
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
294
  /* configure USART Tx as alternate function push-pull */
295
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
296
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
297
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
298
  GPIO_Init(GPIOA, &GPIO_InitStruct);
299
  /* Configure USART Rx as alternate function input floating */
300
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
301
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
302
  GPIO_Init(GPIOA, &GPIO_InitStruct);
303
  /* configure UART communcation parameters */
304
  USART_InitStruct.USART_BaudRate = BOOT_COM_UART_BAUDRATE;
305
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;
306
  USART_InitStruct.USART_StopBits = USART_StopBits_1;
307
  USART_InitStruct.USART_Parity = USART_Parity_No;
308
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
309
  USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
310
  USART_Init(USART2, &USART_InitStruct);
311
  /* enable UART */
312
  USART_Cmd(USART2, ENABLE);
313
#endif
314
} /*** end of Init ***/
315

    
316
/*
317
 * Initializes all GPIO used by the bootloader
318
 */
319
static void initGpio() {
320
  GPIO_InitTypeDef gpio_init;
321

    
322
  /*
323
   * OUTPUTS
324
   */
325

    
326
  /* initialize the pseudo LED and push it up (inactive) */
327
  GPIO_SetBits(PSEUDO_LED_GPIO, PSEUDO_LED_PIN);
328
  gpio_init.GPIO_Pin    = PSEUDO_LED_PIN;
329
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
330
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
331
  GPIO_Init(PSEUDO_LED_GPIO, &gpio_init);
332

    
333
  /* initialize SYS_PD_N and let it go (inactive) */
334
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
335
  gpio_init.GPIO_Pin    = SYS_PD_N_PIN;
336
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
337
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
338
  GPIO_Init(SYS_PD_N_GPIO, &gpio_init);
339

    
340
  /* initialize SYS_SYNC_N and pull it down (active) */
341
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
342
  gpio_init.GPIO_Pin    = SYS_SYNC_N_PIN;
343
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
344
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
345
  GPIO_Init(SYS_SYNC_N_GPIO, &gpio_init);
346

    
347
  /*
348
   * INPUTS
349
   */
350

    
351
} /*** end of initGpio ***/
352

    
353
/*
354
 * Initialize all EXTI lines
355
 */
356
static void initExti() {
357
  /* configure EXTI lines */
358
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource2); // SYS_SYNC_N
359
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource5); // LASER_OC_N
360
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource6); // SYS_UART_DN
361
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8); // WL_GDO2
362
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9); // WL_GDO0
363
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource14); // SYS_PD_N
364

    
365
  return;
366
} /*** end of initExti ***/
367

    
368
/*
369
 * Signals, which type of low-power mode the system shall enter after the shutdown sequence.
370
 */
371
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type) {
372
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
373
  ErrorStatus ret_val = ERROR;
374

    
375
  switch (type) {
376
    case BL_SHUTDOWN_PRI_RSN_UNKNOWN:
377
    case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
378
    case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
379
    case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
380
    {
381
      // broadcast a number of pulses, depending on the argument
382
      uint8_t pulse_counter = 0;
383
      for (pulse_counter = 0; pulse_counter < type; ++pulse_counter) {
384
        msleep(1);
385
        GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
386
        msleep(1);
387
        GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
388
      }
389
      // wait for timeout
390
      msleep(10);
391
      ret_val = SUCCESS;
392
      break;
393
    }
394
    case BL_SHUTDOWN_PRI_RSN_RESTART:
395
    {
396
      // since there is no ambiguity for restart requests, no pulses are generated
397
      msleep(10);
398
      ret_val = SUCCESS;
399
      break;
400
    }
401
    default:
402
      ret_val = ERROR;
403
      break;
404
  }
405

    
406
  return ret_val;
407
} /*** end of shutdownDisambiguationProcedure ***/
408

    
409
/*
410
 * Final shutdown of the system to enter transportation mode.
411
 */
412
void shutdownToTransportation(const blt_bool exec_disambiguation) {
413
  /* configure some criticpal GPIOs as input
414
   * This is required, because otherwise some hardware might be powered through these signals */
415
  configGpioForShutdown();
416

    
417
  /* wait for all boards to be ready for shutdown */
418
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
419
  // this must no be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
420
  setLed(BLT_TRUE);
421
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
422
  setLed(BLT_FALSE);
423

    
424
  if (exec_disambiguation == BLT_TRUE) {
425
    /* execute disambiguation procedure and signal all modules to enter transportation mode */
426
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_TRANSPORT) != SUCCESS) {
427
      blinkSOS(1);
428
      msleep(10);
429
    }
430
  }
431

    
432
  /* morse 'OK' via the LED to signal that shutdown was successful */
433
  blinkOK(1);
434

    
435
  /* enter standby mode */
436
  PWR_EnterSTANDBYMode();
437

    
438
  return;
439
} /*** end of shutdownToTransportation ***/
440

    
441
/*
442
 * Final shutdown of the system to enter deepsleep mode.
443
 */
444
void shutdownToDeepsleep(const blt_bool exec_disambiguation) {
445
  /* configure some criticpal GPIOs as input
446
   * This is required, because otherwise some hardware might be powered through these signals */
447
  configGpioForShutdown();
448

    
449
  /* wait for all boards to be ready for shutdown */
450
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
451
  // this must no be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
452
  setLed(BLT_TRUE);
453
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
454
  setLed(BLT_FALSE);
455

    
456
  if (exec_disambiguation == BLT_TRUE) {
457
    /* execute disambiguation procedure and signal all modules to enter deepsleep mode */
458
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_DEEPSLEEP) != SUCCESS) {
459
      blinkSOS(1);
460
      msleep(10);
461
    }
462
  }
463

    
464
  /* morse 'OK' via the LED to signal that shutdown was successful */
465
  blinkOK(1);
466

    
467
  /* enter standby mode */
468
  PWR_EnterSTANDBYMode();
469

    
470
  return;
471
} /*** end of shutdownToDeepsleep ***/
472

    
473
/*
474
 * Final shutdown of the system to enter hibernate mode.
475
 */
476
void shutdownToHibernate(const blt_bool exec_disambiguation) {
477
  /* configure some criticpal GPIOs as input
478
   * This is required, because otherwise some hardware might be powered through these signals */
479
  configGpioForShutdown();
480

    
481
  /* wait for all boards to be ready for shutdown */
482
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
483
  // this must no be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
484
  setLed(BLT_TRUE);
485
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
486
  setLed(BLT_FALSE);
487

    
488
  if (exec_disambiguation == BLT_TRUE) {
489
    /* execute disambiguation procedure and signal all modules to enter hibernate mode */
490
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_HIBERNATE) != SUCCESS) {
491
      blinkSOS(1);
492
      msleep(10);
493
    }
494
  }
495

    
496
  /* morse 'OK' via the LED to signal that shutdown was successful */
497
  blinkOK(1);
498

    
499
  /* enter standby mode */
500
  PWR_EnterSTANDBYMode();
501

    
502
  return;
503
} /*** end of shutdownToHibernate ***/
504

    
505
void shutdownAndRestart(const blt_bool exec_disambiguation) {
506
  /* configure some criticpal GPIOs as input
507
   * This is required, because otherwise some hardware might be powered through these signals */
508
  configGpioForShutdown();
509

    
510
  /* wait for all boards to be ready for shutdown */
511
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
512
  // this must no be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
513
  setLed(BLT_TRUE);
514
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
515
  setLed(BLT_FALSE);
516

    
517
  if (exec_disambiguation == BLT_TRUE) {
518
    /* execute disambiguation procedure and signal all modules to restart in default mode */
519
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_RESTART) != SUCCESS) {
520
      blinkSOS(1);
521
      msleep(10);
522
    }
523
  }
524

    
525
  /* morse 'OK' via the LED to signal that shutdown was successful */
526
  blinkOK(1);
527

    
528
  /* enter standby mode */
529
  PWR_EnterSTANDBYMode();
530

    
531
  /*
532
   * Even though this module will not restart the system by its own, the PowerManagement will reset the system.
533
   */
534

    
535
  return;
536
}
537

    
538
/*
539
 * Configures some GPIO pins as inputs for safety reasons.
540
 * Under certain circumstances, these pins might power hardware that is supposed to be shut down.
541
 */
542
void configGpioForShutdown() {
543
  /* setup the configuration */
544
  GPIO_InitTypeDef gpio_init;
545
  gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
546
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
547

    
548
  /* configure SYS_UART_TX */
549
  gpio_init.GPIO_Pin = SYS_UART_TX_PIN;
550
  GPIO_Init(SYS_UART_TX_GPIO, &gpio_init);
551

    
552
  /* configure CAN_TX */
553
  gpio_init.GPIO_Pin = CAN_TX_PIN;
554
  GPIO_Init(CAN_TX_GPIO, &gpio_init);
555

    
556
  /* configure all LASER signals */
557
  gpio_init.GPIO_Pin = LASER_EN_PIN;
558
  GPIO_Init(LASER_EN_GPIO, &gpio_init);
559
  gpio_init.GPIO_Pin = LASER_TX_PIN;
560
  GPIO_Init(LASER_TX_GPIO, &gpio_init);
561

    
562
  /* configure all LIGHT (SPI) signals */
563
  gpio_init.GPIO_Pin = LIGHT_SCLK_PIN;
564
  GPIO_Init(LIGHT_SCLK_GPIO, &gpio_init);
565
  gpio_init.GPIO_Pin = LIGHT_MOSI_PIN;
566
  GPIO_Init(LIGHT_MOSI_GPIO, &gpio_init);
567
  gpio_init.GPIO_Pin = LIGHT_XLAT_PIN;
568
  GPIO_Init(LIGHT_XLAT_GPIO, &gpio_init);
569
  gpio_init.GPIO_Pin = LIGHT_BLANK_PIN;
570
  GPIO_Init(LIGHT_BLANK_GPIO, &gpio_init);
571

    
572
  /* configure all WL (SPI) signals */
573
  gpio_init.GPIO_Pin = WL_SS_N_PIN;
574
  GPIO_Init(WL_SS_N_GPIO, &gpio_init);
575
  gpio_init.GPIO_Pin = WL_SCLK_PIN;
576
  GPIO_Init(WL_SCLK_GPIO, &gpio_init);
577
  gpio_init.GPIO_Pin = WL_MOSI_PIN;
578
  GPIO_Init(WL_MOSI_GPIO, &gpio_init);
579

    
580
  return;
581
} /*** end of configGpioForShutdown ***/
582

    
583
/*
584
 * System was reset via the NRST pin or the reason could not be detected.
585
 * In this case, the system enters the boot loop and starts the OS.
586
 */
587
ErrorStatus handleWarmReset() {
588
  /* initialize the bootloader */
589
  BootInit();
590

    
591
  /* start the infinite program loop */
592
  uint32_t loopStartTime = 0;
593
  saTimerUpdate(&loopStartTime);
594
  uint32_t currentTime = loopStartTime;
595
  while (1)
596
  {
597
//    /* make the pseudo LED "double-blink" */
598
//    saTimerUpdate(&currentTime);
599
//    if (currentTime < loopStartTime + 50) {
600
//      setLed(BLT_TRUE);
601
//    } else if (currentTime < loopStartTime + 50+100) {
602
//      setLed(BLT_FALSE);
603
//    } else if (currentTime < loopStartTime + 50+100+50) {
604
//      setLed(BLT_TRUE);
605
//    } else if ( currentTime < loopStartTime + 50+100+50+300) {
606
//      setLed(BLT_FALSE);
607
//    } else {
608
//      loopStartTime = currentTime;
609
//    }
610

    
611
    /* run the bootloader task */
612
    BootTask();
613

    
614
    /* check the SYS_PD_N signal */
615
    if (GPIO_ReadInputDataBit(SYS_PD_N_GPIO, SYS_PD_N_PIN) == Bit_RESET) {
616
      blCallbackHandleShutdownRequest();
617
      return SUCCESS;
618
    }
619
  }
620

    
621
  return ERROR;
622
} /*** end of handleWarmReset ***/
623

    
624
/*
625
 * Callback function that handles the system shutdown and enters transportation mode.
626
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
627
 * In transportation low-power mode the system can only be woken up by pulling down the NRST signal.
628
 * Furthermore, the system can not be charged when in transportation mode.
629
 */
630
void blCallbackShutdownTransportation() {
631
  /* make sure that the required clocks are activated */
632
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
633
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
634

    
635
  /* set/keep the SYS_SYNC and SYS_PD signals active */
636
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
637
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
638

    
639
  saTimerInit();
640

    
641
  setLed(BLT_TRUE);
642

    
643
  shutdownToTransportation(BLT_TRUE);
644

    
645
  return;
646
} /*** end of blCallbackShutdownTransportation ***/
647

    
648
/*
649
 * Callback function that handles the system shutdown and enters deepsleep mode.
650
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
651
 * 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.
652
 */
653
void blCallbackShutdownDeepsleep(void) {
654
  /* make sure that the required clocks are activated */
655
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
656
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
657

    
658
  /* set/keep the SYS_SYNC and SYS_PD signals active */
659
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
660
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
661

    
662
  saTimerInit();
663

    
664
  setLed(BLT_TRUE);
665

    
666
  shutdownToDeepsleep(BLT_TRUE);
667

    
668
  return;
669
} /*** end of blCallbackShutdownDeepsleep ***/
670

    
671
/*
672
 * Callback function that handles the system shutdown and enters hibernate mode.
673
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
674
 */
675
void blCallbackShutdownHibernate(void) {
676
  /* make sure that the required clocks are activated */
677
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
678
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
679

    
680
  /* set/keep the SYS_SYNC and SYS_PD signals active */
681
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
682
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
683

    
684
  saTimerInit();
685

    
686
  setLed(BLT_TRUE);
687

    
688
  shutdownToHibernate(BLT_TRUE);
689

    
690
  return;
691
} /*** end of blCallbackShutdownHibernate ***/
692

    
693
/*
694
 * Callback function that handles the system shutdown and initializes a restart.
695
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
696
 */
697
void blCallbackShutdownRestart(void) {
698
  /* make sure that the required clocks are activated */
699
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
700
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
701

    
702
  /* set/keep the SYS_SYNC and SYS_PD signals active */
703
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
704
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
705

    
706
  /* ensure that all modules had a chance to detect the pulse on SYS_PD_N */
707
  saTimerInit();
708
  msleep(1);
709
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
710
  msleep(1);
711

    
712
  shutdownAndRestart(BLT_TRUE);
713

    
714
  return;
715
} /** end of blCallbackShutdownRestart ***/
716

    
717
/*
718
 * Callback function that handles a system shutdown/restart request from another module.
719
 * Depending on the result of the disambiguation procedure, the module will enter the according low-power mode or restart.
720
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
721
 */
722
void blCallbackHandleShutdownRequest(void) {
723
  /* make sure that the required clocks are activated */
724
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
725
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
726

    
727
  /* set/keep the SYS_SYNC and SYS_PD signals active */
728
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
729
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
730

    
731
  /* ensure that all modules had a chance to detect the pulse on SYS_PD_N */
732
  saTimerInit();
733
  msleep(1);
734
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
735
  msleep(1);
736

    
737
  /* wait for all boards to be ready for shutdown */
738
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
739
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
740
  setLed(BLT_TRUE);
741
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
742
  setLed(BLT_FALSE);
743

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

    
747
  /* disambiguation procedure (passive) */
748
  uint32_t pulse_counter = 0;
749
  while (waitForSignalTimeout(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_RESET, 10)) {
750
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
751
    ++pulse_counter;
752
  }
753

    
754
  /* evaluate and hanlde disambiguation result */
755
  if (shutdown_nrestart == BLT_TRUE) {
756
    /* shutdown request */
757

    
758
    /* handle special cases */
759
    if (pulse_counter == BL_SHUTDOWN_PRI_RSN_UNKNOWN) {
760
      /* no pulse at all was received */
761
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
762
    } else if (pulse_counter != BL_SHUTDOWN_PRI_RSN_HIBERNATE &&
763
               pulse_counter != BL_SHUTDOWN_PRI_RSN_DEEPSLEEP &&
764
               pulse_counter != BL_SHUTDOWN_PRI_RSN_TRANSPORT) {
765
      /* invalid number of pulses received */
766
      blinkSOS(1);
767
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
768
    }
769

    
770
    switch (pulse_counter) {
771
      case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
772
        shutdownToHibernate(BLT_FALSE);
773
        break;
774
      case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
775
        shutdownToDeepsleep(BLT_FALSE);
776
        break;
777
      case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
778
        shutdownToTransportation(BLT_FALSE);
779
        break;
780
    }
781
  } else {
782
    /* restart request */
783

    
784
    /* there is no ambiguity for restart, so it is ignored */
785
    shutdownAndRestart(BLT_FALSE);
786
  }
787

    
788
  /* if this code is reached, the system did neither shut down, nor restart.
789
   * This must never be the case!
790
   */
791
  blinkSOSinf();
792
  return;
793
} /*** end of blCallbackHandleShutdownRequest ***/
794

    
795
/*********************************** end of main.c *************************************/