Statistics
| Branch: | Tag: | Revision:

amiro-blt / Target / Demo / ARMCM3_STM32F103_LightRing_GCC / Boot / main.c @ 69661903

History | View | Annotate | Download (32 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/interfaces.h"
43
#include "AMiRo/helper.h"
44

    
45

    
46
/****************************************************************************************
47
* Defines
48
****************************************************************************************/
49
#define PSEUDO_LED_GPIO     GPIOA
50
#define PSEUDO_LED_PIN      GPIO_Pin_1
51
#define LASER_RX_GPIO       GPIOA
52
#define LASER_RX_PIN        GPIO_Pin_2
53
#define LASER_TX_GPIO       GPIOA
54
#define LASER_TX_PIN        GPIO_Pin_3
55
#define LIGHT_BLANK_GPIO    GPIOA
56
#define LIGHT_BLANK_PIN     GPIO_Pin_4
57
#define LIGHT_SCLK_GPIO     GPIOA
58
#define LIGHT_SCLK_PIN      GPIO_Pin_5
59
#define LIGHT_MOSI_GPIO     GPIOA
60
#define LIGHT_MOSI_PIN      GPIO_Pin_7
61
#define PROG_RX_GPIO        GPIOA
62
#define PROG_RX_PIN         GPIO_Pin_9
63
#define PROG_TX_GPIO        GPIOA
64
#define PROG_TX_PIN         GPIO_Pin_10
65
#define CAN_RX_GPIO         GPIOA
66
#define CAN_RX_PIN          GPIO_Pin_11
67
#define CAN_TX_GPIO         GPIOA
68
#define CAN_TX_PIN          GPIO_Pin_12
69
#define SWDIO_GPIO          GPIOA
70
#define SWDIO_PIN           GPIO_Pin_13
71
#define SWCLK_GPIO          GPIOA
72
#define SWCLK_PIN           GPIO_Pin_14
73

    
74
#define LASER_EN_GPIO       GPIOB
75
#define LASER_EN_PIN        GPIO_Pin_2
76
#define LASER_OC_N_GPIO     GPIOB
77
#define LASER_OC_N_PIN      GPIO_Pin_5
78
#define SYS_UART_DN_GPIO    GPIOB
79
#define SYS_UART_DN_PIN     GPIO_Pin_6
80
#define WL_GDO2_GPIO        GPIOB
81
#define WL_GDO2_PIN         GPIO_Pin_8
82
#define WL_GDO0_GPIO        GPIOB
83
#define WL_GDO0_PIN         GPIO_Pin_9
84
#define MEM_SCL_GPIO        GPIOB
85
#define MEM_SCL_PIN         GPIO_Pin_10
86
#define MEM_SDA_GPIO        GPIOB
87
#define MEM_SDA_PIN         GPIO_Pin_11
88
#define WL_SS_N_GPIO        GPIOB
89
#define WL_SS_N_PIN         GPIO_Pin_12
90
#define WL_SCLK_GPIO        GPIOB
91
#define WL_SCLK_PIN         GPIO_Pin_13
92
#define WL_MISO_GPIO        GPIOB
93
#define WL_MISO_PIN         GPIO_Pin_14
94
#define WL_MOSI_GPIO        GPIOB
95
#define WL_MOSI_PIN         GPIO_Pin_15
96

    
97
#define LIGHT_XLAT_GPIO     GPIOC
98
#define LIGHT_XLAT_PIN      GPIO_Pin_4
99
#define SYS_UART_RX_GPIO    GPIOC
100
#define SYS_UART_RX_PIN     GPIO_Pin_10
101
#define SYS_UART_TX_GPIO    GPIOC
102
#define SYS_UART_TX_PIN     GPIO_Pin_11
103
#define SYS_PD_N_GPIO       GPIOC
104
#define SYS_PD_N_PIN        GPIO_Pin_14
105

    
106
#define OSC_IN_GPIO         GPIOD
107
#define OSC_IN_PIN          GPIO_Pin_0
108
#define OSC_OUT_GPIO        GPIOD
109
#define OSC_OUT_PIN         GPIO_Pin_1
110
#define SYS_SYNC_N_GPIO     GPIOD
111
#define SYS_SYNC_N_PIN      GPIO_Pin_2
112

    
113
/****************************************************************************************
114
* Function prototypes
115
****************************************************************************************/
116
static void Init(void);
117

    
118
static void initGpio();
119
static void initExti();
120
void configGpioForShutdown();
121

    
122
ErrorStatus handleWarmReset();
123

    
124
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type);
125
void shutdownToTransportation(const blt_bool exec_disambiguation);
126
void shutdownToDeepsleep(const blt_bool exec_disambiguation);
127
void shutdownToHibernate(const blt_bool exec_disambiguation);
128
void shutdownAndRestart(const blt_bool exec_disambiguation);
129

    
130
volatile BlBackupRegister backup_reg;
131

    
132
/****************************************************************************************
133
* Callback configuration
134
****************************************************************************************/
135
void blCallbackShutdownTransportation(void);
136
void blCallbackShutdownDeepsleep(void);
137
void blCallbackShutdownHibernate(void);
138
void blCallbackShutdownRestart(void);
139
void blCallbackHandleShutdownRequest(void);
140

    
141
const BlCallbackTable cbtable __attribute__ ((section ("_callback_table"))) = {
142
  .magicNumber = BL_MAGIC_NUMBER,
143
  .versionMajor = BL_VERSION_MAJOR,
144
  .versionMinor = BL_VERSION_MINOR,
145
  .versionHotfix = 0,
146
  .cbShutdownHibernate = blCallbackShutdownHibernate,
147
  .cbShutdownDeepsleep = blCallbackShutdownDeepsleep,
148
  .cbShutdownTransportation = blCallbackShutdownTransportation,
149
  .cbShutdownRestart = blCallbackShutdownRestart,
150
  .cbHandleShutdownRequest = blCallbackHandleShutdownRequest,
151
  .cb5 = (void*)0,
152
  .cb6 = (void*)0,
153
  .cb7 = (void*)0,
154
  .cb8 = (void*)0,
155
  .cb9 = (void*)0,
156
  .cb10 = (void*)0,
157
  .cb11 = (void*)0
158
};
159

    
160
/************************************************************************************//**
161
** \brief     This is the entry point for the bootloader application and is called 
162
**            by the reset interrupt vector after the C-startup routines executed.
163
** \return    Program return code.
164
**
165
****************************************************************************************/
166
int main(void)
167
{
168
  /* initialize the microcontroller */
169
  Init();
170

    
171
  /* activate some required cocks */
172
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
173
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
174

    
175
  /* initialize GPIOs and EXTI lines */
176
  initGpio();
177
  setLed(BLT_TRUE);
178
  initExti();
179

    
180
  /* initialize the timer */
181
  TimerInit();
182

    
183
  /* detect the primary reason for this wakeup/restart */
184
  backup_reg.wakeup_pri_reason =
185
      ((RCC_GetFlagStatus(RCC_FLAG_LPWRRST) == SET) ? BL_WAKEUP_PRI_RSN_LPWRRST : 0) |
186
      ((RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) ? BL_WAKEUP_PRI_RSN_WWDGRST : 0) |
187
      ((RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) ? BL_WAKEUP_PRI_RSN_IWDGRST : 0) |
188
      ((RCC_GetFlagStatus(RCC_FLAG_SFTRST) == SET) ? BL_WAKEUP_PRI_RSN_SFTRST : 0)   |
189
      ((RCC_GetFlagStatus(RCC_FLAG_PORRST) == SET) ? BL_WAKEUP_PRI_RSN_PORRST : 0)   |
190
      ((RCC_GetFlagStatus(RCC_FLAG_PINRST) == SET) ? BL_WAKEUP_PRI_RSN_PINRST : 0)   |
191
      ((PWR_GetFlagStatus(PWR_FLAG_WU) == SET) ? BL_WAKEUP_PRI_RSN_WKUP : 0);
192
  /* for this module there is no secondary wakeup reason */
193
  backup_reg.wakeup_sec_reason = BL_WAKEUP_SEC_RSN_UNKNOWN;
194

    
195
  /* clear the flags */
196
  RCC_ClearFlag();
197
  PWR_ClearFlag(PWR_FLAG_WU);
198

    
199
  setLed(BLT_FALSE);
200

    
201
  /* hanlde different wakeup/reset reasons */
202
  ErrorStatus status = ERROR;
203
  if (backup_reg.wakeup_pri_reason & BL_WAKEUP_PRI_RSN_PINRST) {
204
    /* system was woken via NRST pin */
205
    status = handleWarmReset();
206
  } else {
207
    /* system was woken/reset for an unexpected reason */
208
    blinkSOS(1);
209
    status = handleWarmReset();
210
  }
211

    
212
  /* if something went wrong, signal this failure */
213
  if (status != SUCCESS) {
214
    blinkSOSinf();
215
  }
216

    
217
  return 0;
218
} /*** end of main ***/
219

    
220

    
221
/************************************************************************************//**
222
** \brief     Initializes the microcontroller. 
223
** \return    none.
224
**
225
****************************************************************************************/
226
static void Init(void)
227
{
228
  volatile blt_int32u StartUpCounter = 0, HSEStatus = 0;
229
  blt_int32u pll_multiplier;
230
#if (BOOT_FILE_LOGGING_ENABLE > 0) && (BOOT_COM_UART_ENABLE == 0) && (BOOT_GATE_UART_ENABLE == 0)
231
  GPIO_InitTypeDef  GPIO_InitStruct;
232
  USART_InitTypeDef USART_InitStruct;  
233
#endif  
234

    
235
  /* reset the RCC clock configuration to the default reset state (for debug purpose) */
236
  /* set HSION bit */
237
  RCC->CR |= (blt_int32u)0x00000001;
238
  /* reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
239
  RCC->CFGR &= (blt_int32u)0xF8FF0000;
240
  /* reset HSEON, CSSON and PLLON bits */
241
  RCC->CR &= (blt_int32u)0xFEF6FFFF;
242
  /* reset HSEBYP bit */
243
  RCC->CR &= (blt_int32u)0xFFFBFFFF;
244
  /* reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
245
  RCC->CFGR &= (blt_int32u)0xFF80FFFF;
246
  /* disable all interrupts and clear pending bits  */
247
  RCC->CIR = 0x009F0000;
248
  /* enable HSE */    
249
  RCC->CR |= ((blt_int32u)RCC_CR_HSEON);
250
  /* wait till HSE is ready and if Time out is reached exit */
251
  do
252
  {
253
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
254
    StartUpCounter++;  
255
  } 
256
  while((HSEStatus == 0) && (StartUpCounter != 1500));
257
  /* check if time out was reached */
258
  if ((RCC->CR & RCC_CR_HSERDY) == RESET)
259
  {
260
    /* cannot continue when HSE is not ready */
261
    ASSERT_RT(BLT_FALSE);
262
  }
263
  /* enable flash prefetch buffer */
264
  FLASH->ACR |= FLASH_ACR_PRFTBE;
265
  /* reset flash wait state configuration to default 0 wait states */
266
  FLASH->ACR &= (blt_int32u)((blt_int32u)~FLASH_ACR_LATENCY);
267
#if (BOOT_CPU_SYSTEM_SPEED_KHZ > 48000)
268
  /* configure 2 flash wait states */
269
  FLASH->ACR |= (blt_int32u)FLASH_ACR_LATENCY_2;    
270
#elif (BOOT_CPU_SYSTEM_SPEED_KHZ > 24000)  
271
  /* configure 1 flash wait states */
272
  FLASH->ACR |= (blt_int32u)FLASH_ACR_LATENCY_1;    
273
#endif
274
  /* HCLK = SYSCLK */
275
  RCC->CFGR |= (blt_int32u)RCC_CFGR_HPRE_DIV1;
276
  /* PCLK2 = HCLK/2 */
277
  RCC->CFGR |= (blt_int32u)RCC_CFGR_PPRE2_DIV2;
278
  /* PCLK1 = HCLK/2 */
279
  RCC->CFGR |= (blt_int32u)RCC_CFGR_PPRE1_DIV2;
280
  /* reset PLL configuration */
281
  RCC->CFGR &= (blt_int32u)((blt_int32u)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | \
282
                                          RCC_CFGR_PLLMULL));
283
  /* assert that the pll_multiplier is between 2 and 16 */
284
  ASSERT_CT((BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ) >= 2);
285
  ASSERT_CT((BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ) <= 16);
286
  /* calculate multiplier value */
287
  pll_multiplier = BOOT_CPU_SYSTEM_SPEED_KHZ/BOOT_CPU_XTAL_SPEED_KHZ;
288
  /* convert to register value */
289
  pll_multiplier = (blt_int32u)((pll_multiplier - 2) << 18);
290
  /* set the PLL multiplier and clock source */
291
  RCC->CFGR |= (blt_int32u)(RCC_CFGR_PLLSRC_HSE | pll_multiplier);
292
  /* enable PLL */
293
  RCC->CR |= RCC_CR_PLLON;
294
  /* wait till PLL is ready */
295
  while((RCC->CR & RCC_CR_PLLRDY) == 0)
296
  {
297
  }
298
  /* select PLL as system clock source */
299
  RCC->CFGR &= (blt_int32u)((blt_int32u)~(RCC_CFGR_SW));
300
  RCC->CFGR |= (blt_int32u)RCC_CFGR_SW_PLL;    
301
  /* wait till PLL is used as system clock source */
302
  while ((RCC->CFGR & (blt_int32u)RCC_CFGR_SWS) != (blt_int32u)0x08)
303
  {
304
  }
305
#if (BOOT_COM_CAN_ENABLE > 0 || BOOT_GATE_CAN_ENABLE > 0)
306
  /* enable clocks for CAN transmitter and receiver pins (GPIOB and AFIO) */
307
  RCC->APB2ENR |= (blt_int32u)(0x00000004 | 0x00000001);
308
  /* configure CAN Rx (GPIOA11) as alternate function input */
309
  /* first reset the configuration */
310
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 12);
311
  /* CNF8[1:0] = %01 and MODE8[1:0] = %00 */
312
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0x4 << 12);
313
  /* configure CAN Tx (GPIOA12) as alternate function push-pull */
314
  /* first reset the configuration */
315
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 16);
316
  /* CNF9[1:0] = %11 and MODE9[1:0] = %11 */
317
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0xb << 16);
318

    
319
  /* remap CAN1 pins to PortA */
320
  AFIO->MAPR &= ~(blt_int32u)((blt_int32u)0x3 << 13);
321
  AFIO->MAPR |=  (blt_int32u)((blt_int32u)0x0 << 13);
322
  /* enable clocks for CAN controller peripheral */
323
  RCC->APB1ENR |= (blt_int32u)0x02000000;
324
#endif
325
#if (BOOT_COM_UART_ENABLE > 0 || BOOT_GATE_UART_ENABLE > 0)
326
  /* enable clocks for USART1 peripheral, transmitter and receiver pins (GPIOA and AFIO) */
327
  RCC->APB2ENR |= (blt_int32u)(0x00004000 | 0x00000004 | 0x00000001);
328
  /* configure USART1 Tx (GPIOA9) as alternate function push-pull */
329
  /* first reset the configuration */
330
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 4);
331
  /* CNF2[1:0] = %10 and MODE2[1:0] = %11 */
332
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0xb << 4);
333
  /* configure USART1 Rx (GPIOA10) as alternate function input floating */
334
  /* first reset the configuration */
335
  GPIOA->CRH &= ~(blt_int32u)((blt_int32u)0xf << 8);
336
  /* CNF2[1:0] = %01 and MODE2[1:0] = %00 */
337
  GPIOA->CRH |= (blt_int32u)((blt_int32u)0x4 << 8);
338

    
339
#if (BOOT_DEBUGGING_UART2_ENABLE > 0)
340
  /* enable clocks for USART2 peripheral */
341
  RCC->APB1ENR |= (blt_int32u)(0x00020000);
342
  /* configure USART2 Tx (GPIOA2) as alternate function push-pull */
343
  /* first reset the configuration */
344
  GPIOA->CRL &= ~(blt_int32u)((blt_int32u)0xf << 8);
345
  /* CNF2[1:0] = %10 and MODE2[1:0] = %11 */
346
  GPIOA->CRL |= (blt_int32u)((blt_int32u)0xb << 8);
347
  /* configure USART2 Rx (GPIOA3) as alternate function input floating */
348
  /* first reset the configuration */
349
  GPIOA->CRL &= ~(blt_int32u)((blt_int32u)0xf << 12);
350
  /* CNF2[1:0] = %01 and MODE2[1:0] = %00 */
351
  GPIOA->CRL |= (blt_int32u)((blt_int32u)0x4 << 12);
352
#endif
353

    
354
#elif (BOOT_FILE_LOGGING_ENABLE > 0)
355
  /* enable UART peripheral clock */
356
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
357
  /* enable GPIO peripheral clock for transmitter and receiver pins */
358
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
359
  /* configure USART Tx as alternate function push-pull */
360
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
361
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
362
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
363
  GPIO_Init(GPIOA, &GPIO_InitStruct);
364
  /* Configure USART Rx as alternate function input floating */
365
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
366
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
367
  GPIO_Init(GPIOA, &GPIO_InitStruct);
368
  /* configure UART communcation parameters */  
369
  USART_InitStruct.USART_BaudRate = BOOT_COM_UART_BAUDRATE;
370
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;
371
  USART_InitStruct.USART_StopBits = USART_StopBits_1;
372
  USART_InitStruct.USART_Parity = USART_Parity_No;
373
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
374
  USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
375
  USART_Init(USART2, &USART_InitStruct);
376
  /* enable UART */
377
  USART_Cmd(USART2, ENABLE);
378
#endif
379
} /*** end of Init ***/
380

    
381
/*
382
 * Initializes all GPIO used by the bootloader
383
 */
384
static void initGpio() {
385
  GPIO_InitTypeDef gpio_init;
386

    
387
  /*
388
   * OUTPUTS
389
   */
390

    
391
  /* initialize the pseudo LED and push it up (inactive) */
392
  GPIO_SetBits(PSEUDO_LED_GPIO, PSEUDO_LED_PIN);
393
  gpio_init.GPIO_Pin    = PSEUDO_LED_PIN;
394
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
395
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
396
  GPIO_Init(PSEUDO_LED_GPIO, &gpio_init);
397

    
398
  /* initialize SYS_PD_N and let it go (inactive) */
399
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
400
  gpio_init.GPIO_Pin    = SYS_PD_N_PIN;
401
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
402
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
403
  GPIO_Init(SYS_PD_N_GPIO, &gpio_init);
404

    
405
  /* initialize SYS_SYNC_N and pull it down (active) */
406
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
407
  gpio_init.GPIO_Pin    = SYS_SYNC_N_PIN;
408
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
409
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
410
  GPIO_Init(SYS_SYNC_N_GPIO, &gpio_init);
411

    
412
  /*
413
   * INPUTS
414
   */
415

    
416
} /*** end of initGpio ***/
417

    
418
/*
419
 * Initialize all EXTI lines
420
 */
421
static void initExti() {
422
  /* configure EXTI lines */
423
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource2); // SYS_SYNC_N
424
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource5); // LASER_OC_N
425
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource6); // SYS_UART_DN
426
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8); // WL_GDO2
427
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9); // WL_GDO0
428
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource14); // SYS_PD_N
429

    
430
  return;
431
} /*** end of initExti ***/
432

    
433
/*
434
 * Signals, which type of low-power mode the system shall enter after the shutdown sequence.
435
 */
436
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type) {
437
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
438
  ErrorStatus ret_val = ERROR;
439

    
440
  switch (type) {
441
    case BL_SHUTDOWN_PRI_RSN_UNKNOWN:
442
    case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
443
    case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
444
    case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
445
    {
446
      // broadcast a number of pulses, depending on the argument
447
      uint8_t pulse_counter = 0;
448
      for (pulse_counter = 0; pulse_counter < type; ++pulse_counter) {
449
        msleep(1);
450
        GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
451
        msleep(1);
452
        GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
453
      }
454
      // wait for timeout
455
      msleep(10);
456
      ret_val = SUCCESS;
457
      break;
458
    }
459
    case BL_SHUTDOWN_PRI_RSN_RESTART:
460
    {
461
      // since there is no ambiguity for restart requests, no pulses are generated
462
      msleep(10);
463
      ret_val = SUCCESS;
464
      break;
465
    }
466
    default:
467
      ret_val = ERROR;
468
      break;
469
  }
470

    
471
  return ret_val;
472
} /*** end of shutdownDisambiguationProcedure ***/
473

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

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

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

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

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

    
503
  return;
504
} /*** end of shutdownToTransportation ***/
505

    
506
/*
507
 * Final shutdown of the system to enter deepsleep mode.
508
 */
509
void shutdownToDeepsleep(const blt_bool exec_disambiguation) {
510
  /* configure some criticpal GPIOs as input
511
   * This is required, because otherwise some hardware might be powered through these signals */
512
  configGpioForShutdown();
513

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

    
521
  if (exec_disambiguation == BLT_TRUE) {
522
    /* execute disambiguation procedure and signal all modules to enter deepsleep mode */
523
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_DEEPSLEEP) != SUCCESS) {
524
      blinkSOS(1);
525
      msleep(10);
526
    }
527
  }
528

    
529
  /* morse 'OK' via the LED to signal that shutdown was successful */
530
  blinkOK(1);
531

    
532
  /* enter standby mode */
533
  PWR_EnterSTANDBYMode();
534

    
535
  return;
536
} /*** end of shutdownToDeepsleep ***/
537

    
538
/*
539
 * Final shutdown of the system to enter hibernate mode.
540
 */
541
void shutdownToHibernate(const blt_bool exec_disambiguation) {
542
  /* configure some criticpal GPIOs as input
543
   * This is required, because otherwise some hardware might be powered through these signals */
544
  configGpioForShutdown();
545

    
546
  /* wait for all boards to be ready for shutdown */
547
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
548
  // this must no be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
549
  setLed(BLT_TRUE);
550
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
551
  setLed(BLT_FALSE);
552

    
553
  if (exec_disambiguation == BLT_TRUE) {
554
    /* execute disambiguation procedure and signal all modules to enter hibernate mode */
555
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_HIBERNATE) != SUCCESS) {
556
      blinkSOS(1);
557
      msleep(10);
558
    }
559
  }
560

    
561
  /* morse 'OK' via the LED to signal that shutdown was successful */
562
  blinkOK(1);
563

    
564
  /* enter standby mode */
565
  PWR_EnterSTANDBYMode();
566

    
567
  return;
568
} /*** end of shutdownToHibernate ***/
569

    
570
void shutdownAndRestart(const blt_bool exec_disambiguation) {
571
  /* configure some criticpal GPIOs as input
572
   * This is required, because otherwise some hardware might be powered through these signals */
573
  configGpioForShutdown();
574

    
575
  /* wait for all boards to be ready for shutdown */
576
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
577
  // this must no be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
578
  setLed(BLT_TRUE);
579
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
580
  setLed(BLT_FALSE);
581

    
582
  if (exec_disambiguation == BLT_TRUE) {
583
    /* execute disambiguation procedure and signal all modules to restart in default mode */
584
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_RESTART) != SUCCESS) {
585
      blinkSOS(1);
586
      msleep(10);
587
    }
588
  }
589

    
590
  /* morse 'OK' via the LED to signal that shutdown was successful */
591
  blinkOK(1);
592

    
593
  /* enter standby mode */
594
  PWR_EnterSTANDBYMode();
595

    
596
  /*
597
   * Even though this module will not restart the system by its own, the PowerManagement will reset the system.
598
   */
599

    
600
  return;
601
}
602

    
603
/*
604
 * Configures some GPIO pins as inputs for safety reasons.
605
 * Under certain circumstances, these pins might power hardware that is supposed to be shut down.
606
 */
607
void configGpioForShutdown() {
608
  /* setup the configuration */
609
  GPIO_InitTypeDef gpio_init;
610
  gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
611
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
612

    
613
  /* configure SYS_UART_TX */
614
  gpio_init.GPIO_Pin = SYS_UART_TX_PIN;
615
  GPIO_Init(SYS_UART_TX_GPIO, &gpio_init);
616

    
617
  /* configure CAN_TX */
618
  gpio_init.GPIO_Pin = CAN_TX_PIN;
619
  GPIO_Init(CAN_TX_GPIO, &gpio_init);
620

    
621
  /* configure all LASER signals */
622
  gpio_init.GPIO_Pin = LASER_EN_PIN;
623
  GPIO_Init(LASER_EN_GPIO, &gpio_init);
624
  gpio_init.GPIO_Pin = LASER_TX_PIN;
625
  GPIO_Init(LASER_TX_GPIO, &gpio_init);
626

    
627
  /* configure all LIGHT (SPI) signals */
628
  gpio_init.GPIO_Pin = LIGHT_SCLK_PIN;
629
  GPIO_Init(LIGHT_SCLK_GPIO, &gpio_init);
630
  gpio_init.GPIO_Pin = LIGHT_MOSI_PIN;
631
  GPIO_Init(LIGHT_MOSI_GPIO, &gpio_init);
632
  gpio_init.GPIO_Pin = LIGHT_XLAT_PIN;
633
  GPIO_Init(LIGHT_XLAT_GPIO, &gpio_init);
634
  gpio_init.GPIO_Pin = LIGHT_BLANK_PIN;
635
  GPIO_Init(LIGHT_BLANK_GPIO, &gpio_init);
636

    
637
  /* configure all WL (SPI) signals */
638
  gpio_init.GPIO_Pin = WL_SS_N_PIN;
639
  GPIO_Init(WL_SS_N_GPIO, &gpio_init);
640
  gpio_init.GPIO_Pin = WL_SCLK_PIN;
641
  GPIO_Init(WL_SCLK_GPIO, &gpio_init);
642
  gpio_init.GPIO_Pin = WL_MOSI_PIN;
643
  GPIO_Init(WL_MOSI_GPIO, &gpio_init);
644

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

    
648
/*
649
 * System was reset via the NRST pin or the reason could not be detected.
650
 * In this case, the system enters the boot loop and starts the OS.
651
 */
652
ErrorStatus handleWarmReset() {
653
  /* initialize the bootloader */
654
  BootInit();
655

    
656
  /* start the infinite program loop */
657
  uint32_t loopStartTime = 0;
658
  saTimerUpdate(&loopStartTime);
659
  uint32_t currentTime = loopStartTime;
660
  while (1)
661
  {
662
    /* make the pseudo LED "double-blink" */
663
    saTimerUpdate(&currentTime);
664
    if (currentTime < loopStartTime + 50) {
665
      setLed(BLT_TRUE);
666
    } else if (currentTime < loopStartTime + 50+100) {
667
      setLed(BLT_FALSE);
668
    } else if (currentTime < loopStartTime + 50+100+50) {
669
      setLed(BLT_TRUE);
670
    } else if ( currentTime < loopStartTime + 50+100+50+300) {
671
      setLed(BLT_FALSE);
672
    } else {
673
      loopStartTime = currentTime;
674
    }
675

    
676
    /* run the bootloader task */
677
    BootTask();
678

    
679
    /* check the SYS_PD_N signal */
680
    if (GPIO_ReadInputDataBit(SYS_PD_N_GPIO, SYS_PD_N_PIN) == Bit_RESET) {
681
      blCallbackHandleShutdownRequest();
682
      return SUCCESS;
683
    }
684
  }
685

    
686
  return ERROR;
687
} /*** end of handleWarmReset ***/
688

    
689
/*
690
 * Callback function that handles the system shutdown and enters transportation mode.
691
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
692
 * In transportation low-power mode the system can only be woken up by pulling down the NRST signal.
693
 * Furthermore, the system can not be charged when in transportation mode.
694
 */
695
void blCallbackShutdownTransportation() {
696
  /* make sure that the required clocks are activated */
697
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
698
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
699

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

    
704
  saTimerInit();
705

    
706
  setLed(BLT_TRUE);
707

    
708
  shutdownToTransportation(BLT_TRUE);
709

    
710
  return;
711
} /*** end of blCallbackShutdownTransportation ***/
712

    
713
/*
714
 * Callback function that handles the system shutdown and enters deepsleep mode.
715
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
716
 * 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.
717
 */
718
void blCallbackShutdownDeepsleep(void) {
719
  /* make sure that the required clocks are activated */
720
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
721
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
722

    
723
  /* set/keep the SYS_SYNC and SYS_PD signals active */
724
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
725
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
726

    
727
  saTimerInit();
728

    
729
  setLed(BLT_TRUE);
730

    
731
  shutdownToDeepsleep(BLT_TRUE);
732

    
733
  return;
734
} /*** end of blCallbackShutdownDeepsleep ***/
735

    
736
/*
737
 * Callback function that handles the system shutdown and enters hibernate mode.
738
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
739
 */
740
void blCallbackShutdownHibernate(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
  saTimerInit();
750

    
751
  setLed(BLT_TRUE);
752

    
753
  shutdownToHibernate(BLT_TRUE);
754

    
755
  return;
756
} /*** end of blCallbackShutdownHibernate ***/
757

    
758
/*
759
 * Callback function that handles the system shutdown and initializes a restart.
760
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
761
 */
762
void blCallbackShutdownRestart(void) {
763
  /* make sure that the required clocks are activated */
764
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
765
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
766

    
767
  /* set/keep the SYS_SYNC and SYS_PD signals active */
768
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
769
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
770

    
771
  /* ensure that all modules had a chance to detect the pulse on SYS_PD_N */
772
  saTimerInit();
773
  msleep(1);
774
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
775
  msleep(1);
776

    
777
  shutdownAndRestart(BLT_TRUE);
778

    
779
  return;
780
} /** end of blCallbackShutdownRestart ***/
781

    
782
/*
783
 * Callback function that handles a system shutdown/restart request from another module.
784
 * Depending on the result of the disambiguation procedure, the module will enter the according low-power mode or restart.
785
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
786
 */
787
void blCallbackHandleShutdownRequest(void) {
788
  /* make sure that the required clocks are activated */
789
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
790
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
791

    
792
  /* set/keep the SYS_SYNC and SYS_PD signals active */
793
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
794
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
795

    
796
  /* ensure that all modules had a chance to detect the pulse on SYS_PD_N */
797
  saTimerInit();
798
  msleep(1);
799
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
800
  msleep(1);
801

    
802
  /* wait for all boards to be ready for shutdown */
803
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
804
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
805
  setLed(BLT_TRUE);
806
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
807
  setLed(BLT_FALSE);
808

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

    
812
  /* disambiguation procedure (passive) */
813
  uint32_t pulse_counter = 0;
814
  while (waitForSignalTimeout(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_RESET, 10)) {
815
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
816
    ++pulse_counter;
817
  }
818

    
819
  /* evaluate and hanlde disambiguation result */
820
  if (shutdown_nrestart == BLT_TRUE) {
821
    /* shutdown request */
822

    
823
    /* handle special cases */
824
    if (pulse_counter == BL_SHUTDOWN_PRI_RSN_UNKNOWN) {
825
      /* no pulse at all was received */
826
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
827
    } else if (pulse_counter != BL_SHUTDOWN_PRI_RSN_HIBERNATE &&
828
               pulse_counter != BL_SHUTDOWN_PRI_RSN_DEEPSLEEP &&
829
               pulse_counter != BL_SHUTDOWN_PRI_RSN_TRANSPORT) {
830
      /* invalid number of pulses received */
831
      blinkSOS(1);
832
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
833
    }
834

    
835
    switch (pulse_counter) {
836
      case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
837
        shutdownToHibernate(BLT_FALSE);
838
        break;
839
      case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
840
        shutdownToDeepsleep(BLT_FALSE);
841
        break;
842
      case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
843
        shutdownToTransportation(BLT_FALSE);
844
        break;
845
    }
846
  } else {
847
    /* restart request */
848

    
849
    /* there is no ambiguity for restart, so it is ignored */
850
    shutdownAndRestart(BLT_FALSE);
851
  }
852

    
853
  /* if this code is reached, the system did neither shut down, nor restart.
854
   * This must never be the case!
855
   */
856
  blinkSOSinf();
857
  return;
858
} /*** end of blCallbackHandleShutdownRequest ***/
859

    
860
/*********************************** end of main.c *************************************/