Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (30.536 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 and static variables
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, 0},
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 clocks */
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
  /* handle 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

    
261
#if (BOOT_COM_UART_ENABLE > 0 || BOOT_GATE_UART_ENABLE > 0)
262
  /* enable clocks for USART1 peripheral, transmitter and receiver pins (GPIOA and AFIO) */
263
  RCC->APB2ENR |= (blt_int32u)(0x00004000 | 0x00000004 | 0x00000001);
264
  /* configure USART1 Tx (GPIOA9) as alternate function push-pull */
265
  /* first reset the configuration */
266
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 4);
267
  /* CNF2[1:0] = %10 and MODE2[1:0] = %11 */
268
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0xb << 4);
269
  /* configure USART1 Rx (GPIOA10) as alternate function input floating */
270
  /* first reset the configuration */
271
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 8);
272
  /* CNF2[1:0] = %01 and MODE2[1:0] = %00 */
273
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0x4 << 8);
274

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

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

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

    
323
  /*
324
   * OUTPUTS
325
   */
326

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

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

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

    
348
  /* initialize SYS_UART_DN and let it go (inactive) */
349
  GPIO_SetBits(SYS_UART_DN_GPIO, SYS_UART_DN_PIN);
350
  gpio_init.GPIO_Pin    = SYS_UART_DN_PIN;
351
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
352
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
353
  GPIO_Init(SYS_UART_DN_GPIO, &gpio_init);
354

    
355
  /*
356
   * INPUTS
357
   */
358

    
359
} /*** end of initGpio ***/
360

    
361
/*
362
 * Initialize all EXTI lines
363
 */
364
static void initExti() {
365
  /* configure EXTI lines */
366
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource2); // SYS_SYNC_N
367
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource5); // LASER_OC_N
368
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource6); // SYS_UART_DN
369
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8); // WL_GDO2
370
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9); // WL_GDO0
371
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource14); // SYS_PD_N
372

    
373
  return;
374
} /*** end of initExti ***/
375

    
376
/*
377
 * Signals, which type of low-power mode the system shall enter after the shutdown sequence.
378
 */
379
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type) {
380
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
381
  ErrorStatus ret_val = ERROR;
382

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

    
414
  return ret_val;
415
} /*** end of shutdownDisambiguationProcedure ***/
416

    
417
/*
418
 * Final shutdown of the system to enter transportation mode.
419
 */
420
void shutdownToTransportation(const blt_bool exec_disambiguation) {
421
  /* configure some criticpal GPIOs as input
422
   * This is required, because otherwise some hardware might be powered through these signals */
423
  configGpioForShutdown();
424

    
425
  /* wait for all boards to be ready for shutdown */
426
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
427
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
428
  setLed(BLT_TRUE);
429
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
430
  setLed(BLT_FALSE);
431

    
432
  if (exec_disambiguation == BLT_TRUE) {
433
    /* execute disambiguation procedure and signal all modules to enter transportation mode */
434
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_TRANSPORT) != SUCCESS) {
435
      blinkSOS(1);
436
      msleep(10);
437
    }
438
  }
439

    
440
  /* morse 'OK' via the LED to signal that shutdown was successful */
441
  blinkOK(1);
442

    
443
  /* enter standby mode */
444
  PWR_EnterSTANDBYMode();
445

    
446
  return;
447
} /*** end of shutdownToTransportation ***/
448

    
449
/*
450
 * Final shutdown of the system to enter deepsleep mode.
451
 */
452
void shutdownToDeepsleep(const blt_bool exec_disambiguation) {
453
  /* configure some criticpal GPIOs as input
454
   * This is required, because otherwise some hardware might be powered through these signals */
455
  configGpioForShutdown();
456

    
457
  /* wait for all boards to be ready for shutdown */
458
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
459
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
460
  setLed(BLT_TRUE);
461
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
462
  setLed(BLT_FALSE);
463

    
464
  if (exec_disambiguation == BLT_TRUE) {
465
    /* execute disambiguation procedure and signal all modules to enter deepsleep mode */
466
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_DEEPSLEEP) != SUCCESS) {
467
      blinkSOS(1);
468
      msleep(10);
469
    }
470
  }
471

    
472
  /* morse 'OK' via the LED to signal that shutdown was successful */
473
  blinkOK(1);
474

    
475
  /* enter standby mode */
476
  PWR_EnterSTANDBYMode();
477

    
478
  return;
479
} /*** end of shutdownToDeepsleep ***/
480

    
481
/*
482
 * Final shutdown of the system to enter hibernate mode.
483
 */
484
void shutdownToHibernate(const blt_bool exec_disambiguation) {
485
  /* configure some criticpal GPIOs as input
486
   * This is required, because otherwise some hardware might be powered through these signals */
487
  configGpioForShutdown();
488

    
489
  /* wait for all boards to be ready for shutdown */
490
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
491
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
492
  setLed(BLT_TRUE);
493
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
494
  setLed(BLT_FALSE);
495

    
496
  if (exec_disambiguation == BLT_TRUE) {
497
    /* execute disambiguation procedure and signal all modules to enter hibernate mode */
498
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_HIBERNATE) != SUCCESS) {
499
      blinkSOS(1);
500
      msleep(10);
501
    }
502
  }
503

    
504
  /* morse 'OK' via the LED to signal that shutdown was successful */
505
  blinkOK(1);
506

    
507
  /* enter standby mode */
508
  PWR_EnterSTANDBYMode();
509

    
510
  return;
511
} /*** end of shutdownToHibernate ***/
512

    
513
/*
514
 * Final shutdown of the system and restart.
515
 */
516
void shutdownAndRestart(const blt_bool exec_disambiguation) {
517
  /* configure some criticpal GPIOs as input
518
   * This is required, because otherwise some hardware might be powered through these signals */
519
  configGpioForShutdown();
520

    
521
  /* wait for all boards to be ready for shutdown */
522
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
523
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
524
  setLed(BLT_TRUE);
525
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
526
  setLed(BLT_FALSE);
527

    
528
  if (exec_disambiguation == BLT_TRUE) {
529
    /* execute disambiguation procedure and signal all modules to restart in default mode */
530
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_RESTART) != SUCCESS) {
531
      blinkSOS(1);
532
      msleep(10);
533
    }
534
  }
535

    
536
  /* morse 'OK' via the LED to signal that shutdown was successful */
537
  blinkOK(1);
538

    
539
  /* enter standby mode */
540
  PWR_EnterSTANDBYMode();
541

    
542
  /*
543
   * Even though this module will not restart the system by its own, the PowerManagement will reset the system.
544
   */
545

    
546
  return;
547
} /*** end of shutdownAndRestart ***/
548

    
549
/*
550
 * Configures some GPIO pins as inputs for safety reasons.
551
 * Under certain circumstances, these pins might power hardware that is supposed to be shut down.
552
 */
553
void configGpioForShutdown() {
554
  /* setup the configuration */
555
  GPIO_InitTypeDef gpio_init;
556
  gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
557
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
558

    
559
  /* configure SYS_UART_TX */
560
  gpio_init.GPIO_Pin = SYS_UART_TX_PIN;
561
  GPIO_Init(SYS_UART_TX_GPIO, &gpio_init);
562

    
563
  /* configure CAN_TX */
564
  gpio_init.GPIO_Pin = CAN_TX_PIN;
565
  GPIO_Init(CAN_TX_GPIO, &gpio_init);
566

    
567
  /* configure all LASER signals */
568
  gpio_init.GPIO_Pin = LASER_EN_PIN;
569
  GPIO_Init(LASER_EN_GPIO, &gpio_init);
570
  gpio_init.GPIO_Pin = LASER_TX_PIN;
571
  GPIO_Init(LASER_TX_GPIO, &gpio_init);
572

    
573
  /* configure all LIGHT (SPI) signals */
574
  gpio_init.GPIO_Pin = LIGHT_SCLK_PIN;
575
  GPIO_Init(LIGHT_SCLK_GPIO, &gpio_init);
576
  gpio_init.GPIO_Pin = LIGHT_MOSI_PIN;
577
  GPIO_Init(LIGHT_MOSI_GPIO, &gpio_init);
578
  gpio_init.GPIO_Pin = LIGHT_XLAT_PIN;
579
  GPIO_Init(LIGHT_XLAT_GPIO, &gpio_init);
580
  gpio_init.GPIO_Pin = LIGHT_BLANK_PIN;
581
  GPIO_Init(LIGHT_BLANK_GPIO, &gpio_init);
582

    
583
  /* configure all WL (SPI) signals */
584
  gpio_init.GPIO_Pin = WL_SS_N_PIN;
585
  GPIO_Init(WL_SS_N_GPIO, &gpio_init);
586
  gpio_init.GPIO_Pin = WL_SCLK_PIN;
587
  GPIO_Init(WL_SCLK_GPIO, &gpio_init);
588
  gpio_init.GPIO_Pin = WL_MOSI_PIN;
589
  GPIO_Init(WL_MOSI_GPIO, &gpio_init);
590

    
591
  return;
592
} /*** end of configGpioForShutdown ***/
593

    
594
/*
595
 * System was reset via the NRST pin or the reason could not be detected.
596
 * In this case, the system enters the boot loop and starts the OS.
597
 */
598
ErrorStatus handleWarmReset() {
599
  /* initialize the bootloader */
600
  BootInit();
601

    
602
  /* start the infinite program loop */
603
  uint32_t loopStartTime = 0;
604
  saTimerUpdate(&loopStartTime);
605
  uint32_t currentTime = loopStartTime;
606
  while (1)
607
  {
608
//    /* make the pseudo LED "double-blink" */
609
//    saTimerUpdate(&currentTime);
610
//    if (currentTime < loopStartTime + 50) {
611
//      setLed(BLT_TRUE);
612
//    } else if (currentTime < loopStartTime + 50+100) {
613
//      setLed(BLT_FALSE);
614
//    } else if (currentTime < loopStartTime + 50+100+50) {
615
//      setLed(BLT_TRUE);
616
//    } else if (currentTime < loopStartTime + 50+100+50+300) {
617
//      setLed(BLT_FALSE);
618
//    } else {
619
//      loopStartTime = currentTime;
620
//    }
621

    
622
    /* run the bootloader task */
623
    BootTask();
624

    
625
    /* check the SYS_PD_N signal */
626
    if (GPIO_ReadInputDataBit(SYS_PD_N_GPIO, SYS_PD_N_PIN) == Bit_RESET) {
627
      blCallbackHandleShutdownRequest();
628
      return SUCCESS;
629
    }
630
  }
631

    
632
  return ERROR;
633
} /*** end of handleWarmReset ***/
634

    
635
/*
636
 * Callback function that handles the system shutdown and enters transportation mode.
637
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
638
 * In transportation low-power mode the system can only be woken up by pulling down the NRST signal.
639
 * Furthermore, the system can not be charged when in transportation mode.
640
 */
641
void blCallbackShutdownTransportation() {
642
  /* make sure that the required clocks are activated */
643
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
644
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
645

    
646
  /* set/keep the SYS_SYNC and SYS_PD signals active */
647
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
648
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
649

    
650
  /* initialized the standalone timer */
651
  saTimerInit();
652

    
653
  setLed(BLT_TRUE);
654

    
655
  shutdownToTransportation(BLT_TRUE);
656

    
657
  return;
658
} /*** end of blCallbackShutdownTransportation ***/
659

    
660
/*
661
 * Callback function that handles the system shutdown and enters deepsleep mode.
662
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
663
 * 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.
664
 */
665
void blCallbackShutdownDeepsleep(void) {
666
  /* make sure that the required clocks are activated */
667
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
668
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
669

    
670
  /* set/keep the SYS_SYNC and SYS_PD signals active */
671
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
672
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
673

    
674
  /* initialized the standalone timer */
675
  saTimerInit();
676

    
677
  setLed(BLT_TRUE);
678

    
679
  shutdownToDeepsleep(BLT_TRUE);
680

    
681
  return;
682
} /*** end of blCallbackShutdownDeepsleep ***/
683

    
684
/*
685
 * Callback function that handles the system shutdown and enters hibernate mode.
686
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
687
 */
688
void blCallbackShutdownHibernate(void) {
689
  /* make sure that the required clocks are activated */
690
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
691
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
692

    
693
  /* set/keep the SYS_SYNC and SYS_PD signals active */
694
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
695
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
696

    
697
  /* initialized the standalone timer */
698
  saTimerInit();
699

    
700
  setLed(BLT_TRUE);
701

    
702
  shutdownToHibernate(BLT_TRUE);
703

    
704
  return;
705
} /*** end of blCallbackShutdownHibernate ***/
706

    
707
/*
708
 * Callback function that handles the system shutdown and initializes a restart.
709
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
710
 */
711
void blCallbackShutdownRestart(void) {
712
  /* make sure that the required clocks are activated */
713
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
714
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
715

    
716
  /* set/keep the SYS_SYNC and SYS_PD signals active */
717
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
718
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
719

    
720
  /* initialized the standalone timer */
721
  saTimerInit();
722

    
723
  setLed(BLT_TRUE);
724

    
725
  /* deactivate SYS_PD_N and ensure that all modules had a chance to detect the falling edge */
726
  msleep(1);
727
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
728
  msleep(1);
729

    
730
  shutdownAndRestart(BLT_TRUE);
731

    
732
  return;
733
} /*** end of blCallbackShutdownRestart ***/
734

    
735
/*
736
 * Callback function that handles a system shutdown/restart request from another module.
737
 * Depending on the result of the disambiguation procedure, the module will enter the according low-power mode or restart.
738
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
739
 */
740
void blCallbackHandleShutdownRequest(void) {
741
  /* make sure that the required clocks are activated */
742
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
743
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
744

    
745
  /* set/keep the SYS_SYNC and SYS_PD signals active */
746
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
747
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
748

    
749
  /* initialized the standalone timer */
750
  saTimerInit();
751

    
752
  setLed(BLT_TRUE);
753

    
754
  /* deactivate SYS_PD_N and ensure that all modules had a chance to detect the falling edge */
755
  msleep(1);
756
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
757
  msleep(1);
758

    
759
  /* wait for all boards to be ready for shutdown */
760
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
761
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
762
  setLed(BLT_TRUE);
763
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
764
  setLed(BLT_FALSE);
765

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

    
769
  /* disambiguation procedure (passive) */
770
  uint32_t pulse_counter = 0;
771
  while (waitForSignalTimeout(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_RESET, 10)) {
772
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
773
    ++pulse_counter;
774
  }
775

    
776
  /* evaluate and hanlde disambiguation result */
777
  if (shutdown_nrestart == BLT_TRUE) {
778
    /* shutdown request */
779

    
780
    /* handle special cases */
781
    if (pulse_counter == BL_SHUTDOWN_PRI_RSN_UNKNOWN) {
782
      /* no pulse at all was received */
783
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
784
    } else if (pulse_counter != BL_SHUTDOWN_PRI_RSN_HIBERNATE &&
785
               pulse_counter != BL_SHUTDOWN_PRI_RSN_DEEPSLEEP &&
786
               pulse_counter != BL_SHUTDOWN_PRI_RSN_TRANSPORT) {
787
      /* invalid number of pulses received */
788
      blinkSOS(1);
789
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
790
    }
791

    
792
    switch (pulse_counter) {
793
      case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
794
        shutdownToHibernate(BLT_FALSE);
795
        break;
796
      case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
797
        shutdownToDeepsleep(BLT_FALSE);
798
        break;
799
      case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
800
        shutdownToTransportation(BLT_FALSE);
801
        break;
802
    }
803
  } else {
804
    /* restart request */
805

    
806
    /* there is no ambiguity for restart, so it is ignored */
807
    shutdownAndRestart(BLT_FALSE);
808
  }
809

    
810
  /* if this code is reached, the system did neither shut down, nor restart.
811
   * This must never be the case!
812
   */
813
  blinkSOSinf();
814
  return;
815
} /*** end of blCallbackHandleShutdownRequest ***/
816

    
817
/*********************************** end of main.c *************************************/