144 lines
5.4 KiB
C++
144 lines
5.4 KiB
C++
/*
|
|
* Copyright (C) OpenTX
|
|
*
|
|
* Based on code named
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "pwr.h"
|
|
#include "board.h"
|
|
|
|
void pwrInit()
|
|
{
|
|
GPIO_InitTypeDef GPIO_InitStructure;
|
|
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
|
|
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
|
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
|
|
|
// Internal module PWR
|
|
GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN);
|
|
GPIO_InitStructure.GPIO_Pin = INTMODULE_PWR_GPIO_PIN;
|
|
GPIO_Init(INTMODULE_PWR_GPIO, &GPIO_InitStructure);
|
|
|
|
// External module PWR
|
|
GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN);
|
|
GPIO_InitStructure.GPIO_Pin = EXTMODULE_PWR_GPIO_PIN;
|
|
GPIO_Init(EXTMODULE_PWR_GPIO, &GPIO_InitStructure);
|
|
|
|
#if defined(INTMODULE_BOOTCMD_GPIO)
|
|
GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN);
|
|
GPIO_InitStructure.GPIO_Pin = INTMODULE_BOOTCMD_GPIO_PIN;
|
|
GPIO_Init(INTMODULE_BOOTCMD_GPIO, &GPIO_InitStructure);
|
|
#endif
|
|
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
|
|
|
|
// PWR SWITCH
|
|
GPIO_InitStructure.GPIO_Pin = PWR_SWITCH_GPIO_PIN;
|
|
GPIO_Init(PWR_SWITCH_GPIO, &GPIO_InitStructure);
|
|
|
|
// PCBREV
|
|
#if defined(PCBREV_GPIO_PIN)
|
|
GPIO_InitStructure.GPIO_Pin = PCBREV_GPIO_PIN;
|
|
GPIO_Init(PCBREV_GPIO, &GPIO_InitStructure);
|
|
hardwareOptions.pcbrev = PCBREV_VALUE();
|
|
#endif
|
|
|
|
// SD-DETECT PIN
|
|
GPIO_ResetBits(SD_PRESENT_GPIO, SD_PRESENT_GPIO_PIN);
|
|
GPIO_InitStructure.GPIO_Pin = SD_PRESENT_GPIO_PIN;
|
|
GPIO_Init(SD_PRESENT_GPIO, &GPIO_InitStructure);
|
|
|
|
// TRAINER DETECT PIN
|
|
GPIO_InitStructure.GPIO_Pin = TRAINER_DETECT_GPIO_PIN;
|
|
GPIO_Init(TRAINER_DETECT_GPIO, &GPIO_InitStructure);
|
|
|
|
pwrOn();
|
|
}
|
|
|
|
void pwrOn()
|
|
{
|
|
GPIO_InitTypeDef GPIO_InitStructure;
|
|
GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
|
|
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
|
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
|
GPIO_Init(PWR_ON_GPIO, &GPIO_InitStructure);
|
|
|
|
GPIO_SetBits(PWR_ON_GPIO, PWR_ON_GPIO_PIN);
|
|
|
|
shutdownRequest = NO_SHUTDOWN_REQUEST;
|
|
shutdownReason = DIRTY_SHUTDOWN;
|
|
}
|
|
|
|
void pwrOff()
|
|
{
|
|
GPIO_ResetBits(PWR_ON_GPIO, PWR_ON_GPIO_PIN);
|
|
}
|
|
|
|
bool pwrPressed()
|
|
{
|
|
return GPIO_ReadInputDataBit(PWR_ON_GPIO, PWR_SWITCH_GPIO_PIN) == Bit_RESET;
|
|
}
|
|
|
|
void pwrResetHandler()
|
|
{
|
|
RCC->AHB1ENR |= PWR_RCC_AHB1Periph;
|
|
|
|
// these two NOPs are needed (see STM32F errata sheet) before the peripheral
|
|
// register can be written after the peripheral clock was enabled
|
|
__ASM volatile ("nop");
|
|
__ASM volatile ("nop");
|
|
|
|
// We get here whether we are powering up normally, we had an unexpected reboot or we have just powered down normally.
|
|
// We want:
|
|
// - In the 2nd case, to power ON as soon as possible if an unexpected reboot happened
|
|
// (we get there running on remaining capacitor charge, soft power having been cut by the RESET).
|
|
// - In the 3rd case, NOT power on as that would prevent from turning the system off.
|
|
// - The 1st case does not need to be handled here, but will be as a result of the handling for the 3rd case, see below.
|
|
//
|
|
// shutdownRequest is used to handle the 3rd case. If we really powered down on purpose this will still be set to SHUTDOWN_REQUEST
|
|
// as we left it in pwrOff(). If however we had an unexpected reboot, it would be set to NO_SHUTDOWN_REQUEST as we set it in pwrOn().
|
|
// Any other value (e.g. resulting from data corruption) would also keep power on for safety, so this variable can NOT be used
|
|
// to detect an unexpected reboot (on a normal power on the contents of the variable are random).
|
|
//
|
|
// shutdownReason is used to differentiate between an unexpected reboot and a normal power on. We set it to DIRTY_SHUTDOWN in pwrOn()
|
|
// in anticipation of a potential reboot. Should there be one the value should be preserved and signal below that we rebooted unexpectedly.
|
|
// If it is NOT set to DIRTY_SHUTDOWN we likely had a normal boot and its contents are random. Due to the need to initialize it to detect a
|
|
// potential failure ASAP we cannot use it to determine in the firmware why we got there, it has to be buffered.
|
|
//
|
|
// powerupReason is there to cater for that, and is what is used in the firmware to decide whether we have to enter emergency mode.
|
|
// This variable needs to be in a RAM section that is not initialized or zeroed, since once we exit this pwrResetHandler() function the
|
|
// C runtime would otherwise overwrite it during program init.
|
|
// Only for X12, X10 power circuit causes inability to shut down on some samples.
|
|
|
|
#if defined(PCBX12S)
|
|
if (shutdownRequest != SHUTDOWN_REQUEST || WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) {
|
|
if (shutdownReason == DIRTY_SHUTDOWN) {
|
|
powerupReason = DIRTY_SHUTDOWN;
|
|
}
|
|
pwrOn();
|
|
}
|
|
#else
|
|
if (WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) {
|
|
pwrOn();
|
|
}
|
|
#endif
|
|
}
|