Statistics
| Branch: | Tag: | Revision:

amiro-blt / Target / Modules / LightRing_1-2 / Boot / main.c @ 6c75ad52

History | View | Annotate | Download (33.442 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_Beta, BL_VERSION_MAJOR, BL_VERSION_MINOR, 3},
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 SW_VSYS_EN and pull it down (disabled) */
328
  GPIO_ResetBits(SW_VSYS_EN_GPIO, SW_VSYS_EN_PIN);
329
  gpio_init.GPIO_Pin    = SW_VSYS_EN_PIN;
330
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
331
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
332
  GPIO_Init(SW_VSYS_EN_GPIO, &gpio_init);
333

    
334
  /* initialize SW_V50_EN and pull it down (disabled) */
335
  GPIO_ResetBits(SW_V50_EN_GPIO, SW_V50_EN_PIN);
336
  gpio_init.GPIO_Pin    = SW_V50_EN_PIN;
337
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
338
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
339
  GPIO_Init(SW_V50_EN_GPIO, &gpio_init);
340

    
341
  /* initialize SW_V42_EN and pull it down (disabled) */
342
  GPIO_ResetBits(SW_V42_EN_GPIO, SW_V42_EN_PIN);
343
  gpio_init.GPIO_Pin    = SW_V42_EN_PIN;
344
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
345
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
346
  GPIO_Init(SW_V42_EN_GPIO, &gpio_init);
347

    
348
  /* initialize SW_V33_EN and pull it down (disabled) */
349
  GPIO_ResetBits(SW_V33_EN_GPIO, SW_V33_EN_PIN);
350
  gpio_init.GPIO_Pin    = SW_V33_EN_PIN;
351
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
352
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
353
  GPIO_Init(SW_V33_EN_GPIO, &gpio_init);
354

    
355
  /* initialize SW_V18_EN and pull it down (disabled) */
356
  GPIO_ResetBits(SW_V18_EN_GPIO, SW_V18_EN_PIN);
357
  gpio_init.GPIO_Pin    = SW_V18_EN_PIN;
358
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
359
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
360
  GPIO_Init(SW_V18_EN_GPIO, &gpio_init);
361

    
362
  /* initialize LED and push it up (inactive) */
363
  GPIO_SetBits(LED_GPIO, LED_PIN);
364
  gpio_init.GPIO_Pin    = LED_PIN;
365
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_PP;
366
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
367
  GPIO_Init(LED_GPIO, &gpio_init);
368

    
369
  /* initialize SYS_PD_N and let it go (inactive) */
370
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
371
  gpio_init.GPIO_Pin    = SYS_PD_N_PIN;
372
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
373
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
374
  GPIO_Init(SYS_PD_N_GPIO, &gpio_init);
375

    
376
  /* initialize SYS_SYNC_N and pull it down (active) */
377
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
378
  gpio_init.GPIO_Pin    = SYS_SYNC_N_PIN;
379
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
380
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
381
  GPIO_Init(SYS_SYNC_N_GPIO, &gpio_init);
382

    
383
  /* initialize SYS_UART_DN and let it go (inactive) */
384
  GPIO_SetBits(SYS_UART_DN_GPIO, SYS_UART_DN_PIN);
385
  gpio_init.GPIO_Pin    = SYS_UART_DN_PIN;
386
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
387
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
388
  GPIO_Init(SYS_UART_DN_GPIO, &gpio_init);
389

    
390
  /* initialize SYS_UART_UP and let it go (inactive) */
391
  GPIO_SetBits(SYS_UART_UP_GPIO, SYS_UART_UP_PIN);
392
  gpio_init.GPIO_Pin    = SYS_UART_UP_PIN;
393
  gpio_init.GPIO_Mode   = GPIO_Mode_Out_OD;
394
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
395
  GPIO_Init(SYS_UART_UP_GPIO, &gpio_init);
396

    
397
  /*
398
   * INPUTS
399
   */
400

    
401
} /*** end of initGpio ***/
402

    
403
/*
404
 * Initialize all EXTI lines
405
 */
406
static void initExti() {
407
  /* configure EXTI lines */
408
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource2); // SYS_SYNC_N
409
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource6); // SYS_UART_DN
410
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource7); // SYS_UART_UP
411
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource14); // SYS_PD_N
412

    
413
  return;
414
} /*** end of initExti ***/
415

    
416
/*
417
 * Signals, which type of low-power mode the system shall enter after the shutdown sequence.
418
 */
419
ErrorStatus shutdownDisambiguationProcedure(const uint8_t type) {
420
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
421
  ErrorStatus ret_val = ERROR;
422

    
423
  switch (type) {
424
    case BL_SHUTDOWN_PRI_RSN_UNKNOWN:
425
    case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
426
    case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
427
    case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
428
    {
429
      // broadcast a number of pulses, depending on the argument
430
      uint8_t pulse_counter = 0;
431
      for (pulse_counter = 0; pulse_counter < type; ++pulse_counter) {
432
        msleep(1);
433
        GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
434
        msleep(1);
435
        GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
436
      }
437
      // wait for timeout
438
      msleep(10);
439
      ret_val = SUCCESS;
440
      break;
441
    }
442
    case BL_SHUTDOWN_PRI_RSN_RESTART:
443
    {
444
      // since there is no ambiguity for restart requests, no pulses are generated
445
      msleep(10);
446
      ret_val = SUCCESS;
447
      break;
448
    }
449
    default:
450
      ret_val = ERROR;
451
      break;
452
  }
453

    
454
  return ret_val;
455
} /*** end of shutdownDisambiguationProcedure ***/
456

    
457
/*
458
 * Final shutdown of the system to enter transportation mode.
459
 */
460
void shutdownToTransportation(const blt_bool exec_disambiguation) {
461
  /* configure some criticpal GPIOs as input
462
   * This is required, because otherwise some hardware might be powered through these signals */
463
  configGpioForShutdown();
464

    
465
  /* wait for all boards to be ready for shutdown */
466
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
467
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
468
  setLed(BLT_TRUE);
469
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
470
  setLed(BLT_FALSE);
471

    
472
  if (exec_disambiguation == BLT_TRUE) {
473
    /* execute disambiguation procedure and signal all modules to enter transportation mode */
474
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_TRANSPORT) != SUCCESS) {
475
      blinkSOS(1);
476
      msleep(10);
477
    }
478
  }
479

    
480
  /* morse 'OK' via the LED to signal that shutdown was successful */
481
  blinkOK(1);
482

    
483
  /* enter standby mode */
484
  PWR_EnterSTANDBYMode();
485

    
486
  return;
487
} /*** end of shutdownToTransportation ***/
488

    
489
/*
490
 * Final shutdown of the system to enter deepsleep mode.
491
 */
492
void shutdownToDeepsleep(const blt_bool exec_disambiguation) {
493
  /* configure some criticpal GPIOs as input
494
   * This is required, because otherwise some hardware might be powered through these signals */
495
  configGpioForShutdown();
496

    
497
  /* wait for all boards to be ready for shutdown */
498
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
499
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
500
  setLed(BLT_TRUE);
501
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
502
  setLed(BLT_FALSE);
503

    
504
  if (exec_disambiguation == BLT_TRUE) {
505
    /* execute disambiguation procedure and signal all modules to enter deepsleep mode */
506
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_DEEPSLEEP) != SUCCESS) {
507
      blinkSOS(1);
508
      msleep(10);
509
    }
510
  }
511

    
512
  /* morse 'OK' via the LED to signal that shutdown was successful */
513
  blinkOK(1);
514

    
515
  /* enter standby mode */
516
  PWR_EnterSTANDBYMode();
517

    
518
  return;
519
} /*** end of shutdownToDeepsleep ***/
520

    
521
/*
522
 * Final shutdown of the system to enter hibernate mode.
523
 */
524
void shutdownToHibernate(const blt_bool exec_disambiguation) {
525
  /* configure some criticpal GPIOs as input
526
   * This is required, because otherwise some hardware might be powered through these signals */
527
  configGpioForShutdown();
528

    
529
  /* wait for all boards to be ready for shutdown */
530
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
531
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
532
  setLed(BLT_TRUE);
533
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
534
  setLed(BLT_FALSE);
535

    
536
  if (exec_disambiguation == BLT_TRUE) {
537
    /* execute disambiguation procedure and signal all modules to enter hibernate mode */
538
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_HIBERNATE) != SUCCESS) {
539
      blinkSOS(1);
540
      msleep(10);
541
    }
542
  }
543

    
544
  /* morse 'OK' via the LED to signal that shutdown was successful */
545
  blinkOK(1);
546

    
547
  /* enter standby mode */
548
  PWR_EnterSTANDBYMode();
549

    
550
  return;
551
} /*** end of shutdownToHibernate ***/
552

    
553
/*
554
 * Final shutdown of the system and restart.
555
 */
556
void shutdownAndRestart(const blt_bool exec_disambiguation) {
557
  /* configure some criticpal GPIOs as input
558
   * This is required, because otherwise some hardware might be powered through these signals */
559
  configGpioForShutdown();
560

    
561
  /* wait for all boards to be ready for shutdown */
562
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
563
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
564
  setLed(BLT_TRUE);
565
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
566
  setLed(BLT_FALSE);
567

    
568
  if (exec_disambiguation == BLT_TRUE) {
569
    /* execute disambiguation procedure and signal all modules to restart in default mode */
570
    if (shutdownDisambiguationProcedure(BL_SHUTDOWN_PRI_RSN_RESTART) != SUCCESS) {
571
      blinkSOS(1);
572
      msleep(10);
573
    }
574
  }
575

    
576
  /* morse 'OK' via the LED to signal that shutdown was successful */
577
  blinkOK(1);
578

    
579
  /* enter standby mode */
580
  PWR_EnterSTANDBYMode();
581

    
582
  /*
583
   * Even though this module will not restart the system by its own, the PowerManagement will reset the system.
584
   */
585

    
586
  return;
587
} /*** end of shutdownAndRestart ***/
588

    
589
/*
590
 * Configures some GPIO pins as inputs for safety reasons.
591
 * Under certain circumstances, these pins might power hardware that is supposed to be shut down.
592
 */
593
void configGpioForShutdown() {
594
  /* turn off power switches */
595
  GPIO_ResetBits(SW_VSYS_EN_GPIO, SW_VSYS_EN_PIN);
596
  GPIO_ResetBits(SW_V50_EN_GPIO, SW_V50_EN_PIN);
597
  GPIO_ResetBits(SW_V42_EN_GPIO, SW_V42_EN_PIN);
598
  GPIO_ResetBits(SW_V33_EN_GPIO, SW_V33_EN_PIN);
599
  GPIO_ResetBits(SW_V18_EN_GPIO, SW_V18_EN_PIN);
600

    
601
  /* setup the configuration */
602
  GPIO_InitTypeDef gpio_init;
603
  gpio_init.GPIO_Mode   = GPIO_Mode_IN_FLOATING;
604
  gpio_init.GPIO_Speed  = GPIO_Speed_50MHz;
605

    
606
  /* configure SYS_UART_TX */
607
  gpio_init.GPIO_Pin = SYS_UART_TX_PIN;
608
  GPIO_Init(SYS_UART_TX_GPIO, &gpio_init);
609

    
610
  /* configure CAN_TX */
611
  gpio_init.GPIO_Pin = CAN_TX_PIN;
612
  GPIO_Init(CAN_TX_GPIO, &gpio_init);
613

    
614
  /* configure RS232 control signals */
615
  gpio_init.GPIO_Pin = RS232_R_EN_N_PIN;
616
  GPIO_Init(RS232_R_EN_N_GPIO, &gpio_init);
617
  gpio_init.GPIO_Pin = RS232_D_OFF_N_PIN;
618
  GPIO_Init(RS232_D_OFF_N_GPIO, &gpio_init);
619

    
620
  /* configure breakout USART signals */
621
  gpio_init.GPIO_Pin = USART_CTS_PIN;
622
  GPIO_Init(USART_CTS_GPIO, &gpio_init);
623
  gpio_init.GPIO_Pin = USART_RTS_PIN;
624
  GPIO_Init(USART_RTS_GPIO, &gpio_init);
625
  gpio_init.GPIO_Pin = USART_TX_PIN;
626
  GPIO_Init(USART_TX_GPIO, &gpio_init);
627
  gpio_init.GPIO_Pin = USART_RX_PIN;
628
  GPIO_Init(USART_RX_GPIO, &gpio_init);
629

    
630
  /* configure breakout SPI signals */
631
  gpio_init.GPIO_Pin = SPI_SS_N_PIN;
632
  GPIO_Init(SPI_SS_N_GPIO, &gpio_init);
633
  gpio_init.GPIO_Pin = SPI_SCLK_PIN;
634
  GPIO_Init(SPI_SCLK_GPIO, &gpio_init);
635
  gpio_init.GPIO_Pin = SPI_MISO_PIN;
636
  GPIO_Init(SPI_MISO_GPIO, &gpio_init);
637
  gpio_init.GPIO_Pin = SPI_MOSI_PIN;
638
  GPIO_Init(SPI_MOSI_GPIO, &gpio_init);
639

    
640
  /* configure breakout I/O signals */
641
  gpio_init.GPIO_Pin = IO_1_PIN;
642
  GPIO_Init(IO_1_GPIO, &gpio_init);
643
  gpio_init.GPIO_Pin = IO_2_PIN;
644
  GPIO_Init(IO_2_GPIO, &gpio_init);
645
  gpio_init.GPIO_Pin = IO_3_PIN;
646
  GPIO_Init(IO_3_GPIO, &gpio_init);
647
  gpio_init.GPIO_Pin = IO_4_PIN;
648
  GPIO_Init(IO_4_GPIO, &gpio_init);
649
  gpio_init.GPIO_Pin = IO_5_PIN;
650
  GPIO_Init(IO_5_GPIO, &gpio_init);
651
  gpio_init.GPIO_Pin = IO_6_PIN;
652
  GPIO_Init(IO_6_GPIO, &gpio_init);
653
  gpio_init.GPIO_Pin = IO_7_PIN;
654
  GPIO_Init(IO_7_GPIO, &gpio_init);
655
  gpio_init.GPIO_Pin = IO_8_PIN;
656
  GPIO_Init(IO_8_GPIO, &gpio_init);
657

    
658
  /* configure all LIGHT (SPI) signals */
659
  gpio_init.GPIO_Pin = LIGHT_SCLK_PIN;
660
  GPIO_Init(LIGHT_SCLK_GPIO, &gpio_init);
661
  gpio_init.GPIO_Pin = LIGHT_MISO_PIN;
662
  GPIO_Init(LIGHT_MISO_GPIO, &gpio_init);
663
  gpio_init.GPIO_Pin = LIGHT_MOSI_PIN;
664
  GPIO_Init(LIGHT_MOSI_GPIO, &gpio_init);
665
  gpio_init.GPIO_Pin = LIGHT_XLAT_PIN;
666
  GPIO_Init(LIGHT_XLAT_GPIO, &gpio_init);
667
  gpio_init.GPIO_Pin = LIGHT_BLANK_PIN;
668
  GPIO_Init(LIGHT_BLANK_GPIO, &gpio_init);
669

    
670
  return;
671
} /*** end of configGpioForShutdown ***/
672

    
673
/*
674
 * System was reset via the NRST pin or the reason could not be detected.
675
 * In this case, the system enters the boot loop and starts the OS.
676
 */
677
ErrorStatus handleWarmReset() {
678
  /* initialize the bootloader */
679
  BootInit();
680

    
681
  /* start the infinite program loop */
682
  uint32_t loopStartTime = 0;
683
  saTimerUpdate(&loopStartTime);
684
  uint32_t currentTime = loopStartTime;
685
  while (1)
686
  {
687
//    /* make the pseudo LED "double-blink" */
688
//    saTimerUpdate(&currentTime);
689
//    if (currentTime < loopStartTime + 50) {
690
//      setLed(BLT_TRUE);
691
//    } else if (currentTime < loopStartTime + 50+100) {
692
//      setLed(BLT_FALSE);
693
//    } else if (currentTime < loopStartTime + 50+100+50) {
694
//      setLed(BLT_TRUE);
695
//    } else if (currentTime < loopStartTime + 50+100+50+300) {
696
//      setLed(BLT_FALSE);
697
//    } else {
698
//      loopStartTime = currentTime;
699
//    }
700

    
701
    /* run the bootloader task */
702
    BootTask();
703

    
704
    /* check the SYS_PD_N signal */
705
    if (GPIO_ReadInputDataBit(SYS_PD_N_GPIO, SYS_PD_N_PIN) == Bit_RESET) {
706
      blCallbackHandleShutdownRequest();
707
      return SUCCESS;
708
    }
709
  }
710

    
711
  return ERROR;
712
} /*** end of handleWarmReset ***/
713

    
714
/*
715
 * Callback function that handles the system shutdown and enters transportation mode.
716
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
717
 * In transportation low-power mode the system can only be woken up by pulling down the NRST signal.
718
 * Furthermore, the system can not be charged when in transportation mode.
719
 */
720
void blCallbackShutdownTransportation() {
721
  /* make sure that the required clocks are activated */
722
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
723
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
724

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

    
729
  /* initialized the standalone timer */
730
  saTimerInit();
731

    
732
  setLed(BLT_TRUE);
733

    
734
  shutdownToTransportation(BLT_TRUE);
735

    
736
  return;
737
} /*** end of blCallbackShutdownTransportation ***/
738

    
739
/*
740
 * Callback function that handles the system shutdown and enters deepsleep mode.
741
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
742
 * 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.
743
 */
744
void blCallbackShutdownDeepsleep(void) {
745
  /* make sure that the required clocks are activated */
746
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
747
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
748

    
749
  /* set/keep the SYS_SYNC and SYS_PD signals active */
750
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
751
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
752

    
753
  /* initialized the standalone timer */
754
  saTimerInit();
755

    
756
  setLed(BLT_TRUE);
757

    
758
  shutdownToDeepsleep(BLT_TRUE);
759

    
760
  return;
761
} /*** end of blCallbackShutdownDeepsleep ***/
762

    
763
/*
764
 * Callback function that handles the system shutdown and enters hibernate mode.
765
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
766
 */
767
void blCallbackShutdownHibernate(void) {
768
  /* make sure that the required clocks are activated */
769
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
770
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
771

    
772
  /* set/keep the SYS_SYNC and SYS_PD signals active */
773
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
774
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
775

    
776
  /* initialized the standalone timer */
777
  saTimerInit();
778

    
779
  setLed(BLT_TRUE);
780

    
781
  shutdownToHibernate(BLT_TRUE);
782

    
783
  return;
784
} /*** end of blCallbackShutdownHibernate ***/
785

    
786
/*
787
 * Callback function that handles the system shutdown and initializes a restart.
788
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
789
 */
790
void blCallbackShutdownRestart(void) {
791
  /* make sure that the required clocks are activated */
792
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
793
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
794

    
795
  /* set/keep the SYS_SYNC and SYS_PD signals active */
796
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
797
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
798

    
799
  /* initialized the standalone timer */
800
  saTimerInit();
801

    
802
  setLed(BLT_TRUE);
803

    
804
  /* deactivate SYS_PD_N and ensure that all modules had a chance to detect the falling edge */
805
  msleep(1);
806
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
807
  msleep(1);
808

    
809
  shutdownAndRestart(BLT_TRUE);
810

    
811
  return;
812
} /*** end of blCallbackShutdownRestart ***/
813

    
814
/*
815
 * Callback function that handles a system shutdown/restart request from another module.
816
 * Depending on the result of the disambiguation procedure, the module will enter the according low-power mode or restart.
817
 * When called from a multithreaded environment, it must be ensured that no other thread will preempt this function.
818
 */
819
void blCallbackHandleShutdownRequest(void) {
820
  /* make sure that the required clocks are activated */
821
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
822
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
823

    
824
  /* set/keep the SYS_SYNC and SYS_PD signals active */
825
  GPIO_ResetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
826
  GPIO_ResetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
827

    
828
  /* initialized the standalone timer */
829
  saTimerInit();
830

    
831
  setLed(BLT_TRUE);
832

    
833
  /* deactivate SYS_PD_N and ensure that all modules had a chance to detect the falling edge */
834
  msleep(1);
835
  GPIO_SetBits(SYS_PD_N_GPIO, SYS_PD_N_PIN);
836
  msleep(1);
837

    
838
  /* wait for all boards to be ready for shutdown */
839
  GPIO_SetBits(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN);
840
  // this must not be skipped, since the pull-up voltage for SYS_SYNC_N (VIO3.3) must be configured at this point by definition.
841
  setLed(BLT_TRUE);
842
  waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
843
  setLed(BLT_FALSE);
844

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

    
848
  /* disambiguation procedure (passive) */
849
  uint32_t pulse_counter = 0;
850
  while (waitForSignalTimeout(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_RESET, 10)) {
851
    waitForSignal(SYS_SYNC_N_GPIO, SYS_SYNC_N_PIN, Bit_SET);
852
    ++pulse_counter;
853
  }
854

    
855
  /* evaluate and hanlde disambiguation result */
856
  if (shutdown_nrestart == BLT_TRUE) {
857
    /* shutdown request */
858

    
859
    /* handle special cases */
860
    if (pulse_counter == BL_SHUTDOWN_PRI_RSN_UNKNOWN) {
861
      /* no pulse at all was received */
862
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
863
    } else if (pulse_counter != BL_SHUTDOWN_PRI_RSN_HIBERNATE &&
864
               pulse_counter != BL_SHUTDOWN_PRI_RSN_DEEPSLEEP &&
865
               pulse_counter != BL_SHUTDOWN_PRI_RSN_TRANSPORT) {
866
      /* invalid number of pulses received */
867
      blinkSOS(1);
868
      pulse_counter = BL_SHUTDOWN_PRI_RSN_DEFAULT;
869
    }
870

    
871
    switch (pulse_counter) {
872
      case BL_SHUTDOWN_PRI_RSN_HIBERNATE:
873
        shutdownToHibernate(BLT_FALSE);
874
        break;
875
      case BL_SHUTDOWN_PRI_RSN_DEEPSLEEP:
876
        shutdownToDeepsleep(BLT_FALSE);
877
        break;
878
      case BL_SHUTDOWN_PRI_RSN_TRANSPORT:
879
        shutdownToTransportation(BLT_FALSE);
880
        break;
881
    }
882
  } else {
883
    /* restart request */
884

    
885
    /* there is no ambiguity for restart, so it is ignored */
886
    shutdownAndRestart(BLT_FALSE);
887
  }
888

    
889
  /* if this code is reached, the system did neither shut down, nor restart.
890
   * This must never be the case!
891
   */
892
  blinkSOSinf();
893
  return;
894
} /*** end of blCallbackHandleShutdownRequest ***/
895

    
896
/*********************************** end of main.c *************************************/