/* * 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 "opentx.h" #if defined(__cplusplus) extern "C" { #endif #include "usb_dcd_int.h" #include "usb_bsp.h" #if defined(__cplusplus) } #endif HardwareOptions hardwareOptions; void watchdogInit(unsigned int duration) { IWDG->KR = 0x5555; // Unlock registers IWDG->PR = 3; // Divide by 32 => 1kHz clock IWDG->KR = 0x5555; // Unlock registers IWDG->RLR = duration; IWDG->KR = 0xAAAA; // reload IWDG->KR = 0xCCCC; // start } #if defined(SPORT_UPDATE_PWR_GPIO) void sportUpdateInit() { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = SPORT_UPDATE_PWR_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(SPORT_UPDATE_PWR_GPIO, &GPIO_InitStructure); } void sportUpdatePowerOn() { GPIO_SPORT_UPDATE_PWR_GPIO_ON(SPORT_UPDATE_PWR_GPIO, SPORT_UPDATE_PWR_GPIO_PIN); } void sportUpdatePowerOff() { GPIO_SPORT_UPDATE_PWR_GPIO_OFF(SPORT_UPDATE_PWR_GPIO, SPORT_UPDATE_PWR_GPIO_PIN); } void sportUpdatePowerInit() { if (g_eeGeneral.sportUpdatePower == 1) sportUpdatePowerOn(); else sportUpdatePowerOff(); } #endif void boardInit() { RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | PCBREV_RCC_AHB1Periph | KEYS_RCC_AHB1Periph | LCD_RCC_AHB1Periph | AUDIO_RCC_AHB1Periph | BACKLIGHT_RCC_AHB1Periph | ADC_RCC_AHB1Periph | I2C_RCC_AHB1Periph | SD_RCC_AHB1Periph | HAPTIC_RCC_AHB1Periph | INTMODULE_RCC_AHB1Periph | EXTMODULE_RCC_AHB1Periph | TELEMETRY_RCC_AHB1Periph | SPORT_UPDATE_RCC_AHB1Periph | AUX_SERIAL_RCC_AHB1Periph | TRAINER_RCC_AHB1Periph | TRAINER_MODULE_RCC_AHB1Periph | BT_RCC_AHB1Periph | GYRO_RCC_AHB1Periph, ENABLE); RCC_APB1PeriphClockCmd(ROTARY_ENCODER_RCC_APB1Periph | LCD_RCC_APB1Periph | AUDIO_RCC_APB1Periph | ADC_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph | HAPTIC_RCC_APB1Periph | INTERRUPT_xMS_RCC_APB1Periph | TIMER_2MHz_RCC_APB1Periph | I2C_RCC_APB1Periph | SD_RCC_APB1Periph | TRAINER_RCC_APB1Periph | TELEMETRY_RCC_APB1Periph | AUX_SERIAL_RCC_APB1Periph | INTMODULE_RCC_APB1Periph | TRAINER_MODULE_RCC_APB1Periph | BT_RCC_APB1Periph | GYRO_RCC_APB1Periph, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG | BACKLIGHT_RCC_APB2Periph | ADC_RCC_APB2Periph | HAPTIC_RCC_APB2Periph | INTMODULE_RCC_APB2Periph | EXTMODULE_RCC_APB2Periph | TRAINER_MODULE_RCC_APB2Periph | BT_RCC_APB2Periph | TELEMETRY_RCC_APB2Periph, ENABLE); #if defined(BLUETOOTH) && !defined(PCBX9E) bluetoothInit(BLUETOOTH_DEFAULT_BAUDRATE, true); #endif pwrInit(); #if defined(AUTOUPDATE) telemetryPortInit(FRSKY_SPORT_BAUDRATE, TELEMETRY_SERIAL_WITHOUT_DMA); sportSendByteLoop(0x7E); #endif #if defined(STATUS_LEDS) ledInit(); ledGreen(); #endif keysInit(); #if defined(ROTARY_ENCODER_NAVIGATION) rotaryEncoderInit(); #endif delaysInit(); #if NUM_PWMSTICKS > 0 sticksPwmInit(); delay_ms(20); if (pwm_interrupt_count < 32) { hardwareOptions.sticksPwmDisabled = true; } #endif adcInit(); lcdInit(); // delaysInit() must be called before audioInit(); init2MhzTimer(); init5msTimer(); __enable_irq(); i2cInit(); usbInit(); #if defined(DEBUG) && defined(AUX_SERIAL_GPIO) auxSerialInit(0, 0); // default serial mode (None if DEBUG not defined) TRACE("\nTaranis board started :)"); #endif #if defined(HAPTIC) hapticInit(); #endif #if defined(PXX2_PROBE) intmodulePxx2Probe(); #endif #if defined(DEBUG) DBGMCU_APB1PeriphConfig(DBGMCU_IWDG_STOP|DBGMCU_TIM1_STOP|DBGMCU_TIM2_STOP|DBGMCU_TIM3_STOP|DBGMCU_TIM6_STOP|DBGMCU_TIM8_STOP|DBGMCU_TIM10_STOP|DBGMCU_TIM13_STOP|DBGMCU_TIM14_STOP, ENABLE); #endif #if defined(PWR_BUTTON_PRESS) if (WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) { pwrOn(); } #endif #if defined(TOPLCD_GPIO) toplcdInit(); #endif if (HAS_SPORT_UPDATE_CONNECTOR()) { sportUpdateInit(); } #if defined(JACK_DETECT_GPIO) initJackDetect(); #endif initSpeakerEnable(); enableSpeaker(); initHeadphoneTrainerSwitch(); #if defined(GYRO) gyroInit(); #endif #if defined(RTCLOCK) && !defined(COPROCESSOR) rtcInit(); // RTC must be initialized before rambackupRestore() is called #endif backlightInit(); } void boardOff() { #if defined(STATUS_LEDS) && !defined(BOOT) ledOff(); #endif BACKLIGHT_DISABLE(); #if defined(TOPLCD_GPIO) && !defined(BOOT) toplcdOff(); #endif #if defined(PWR_BUTTON_PRESS) while (pwrPressed()) { WDG_RESET(); } #endif lcdOff(); SysTick->CTRL = 0; // turn off systick pwrOff(); // disable interrupts __disable_irq(); while (1) { WDG_RESET(); #if defined(PWR_BUTTON_PRESS) // X9E/X7 needs watchdog reset because CPU is still running while // the power key is held pressed by the user. // The power key should be released by now, but we must make sure if (!pwrPressed()) { // Put the CPU into sleep to reduce the consumption, // it might help with the RTC reset issue PWR->CR |= PWR_CR_CWUF; /* Select STANDBY mode */ PWR->CR |= PWR_CR_PDDS; /* Set SLEEPDEEP bit of Cortex System Control Register */ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; /* Request Wait For Event */ __WFE(); } #endif } // this function must not return! } uint16_t getBatteryVoltage() { int32_t instant_vbat = anaIn(TX_VOLTAGE); // using filtered ADC value on purpose instant_vbat = (instant_vbat * BATT_SCALE * (128 + g_eeGeneral.txVoltageCalibration) ) / 26214; instant_vbat += 20; // add 0.2V because of the diode TODO check if this is needed, but removal will break existing calibrations! return (uint16_t)instant_vbat; } #if defined(AUDIO_SPEAKER_ENABLE_GPIO) void initSpeakerEnable() { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = AUDIO_SPEAKER_ENABLE_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(AUDIO_SPEAKER_ENABLE_GPIO, &GPIO_InitStructure); } void enableSpeaker() { GPIO_SetBits(AUDIO_SPEAKER_ENABLE_GPIO, AUDIO_SPEAKER_ENABLE_GPIO_PIN); } void disableSpeaker() { GPIO_ResetBits(AUDIO_SPEAKER_ENABLE_GPIO, AUDIO_SPEAKER_ENABLE_GPIO_PIN); } #endif #if defined(HEADPHONE_TRAINER_SWITCH_GPIO) void initHeadphoneTrainerSwitch() { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = HEADPHONE_TRAINER_SWITCH_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(HEADPHONE_TRAINER_SWITCH_GPIO, &GPIO_InitStructure); } void enableHeadphone() { GPIO_ResetBits(HEADPHONE_TRAINER_SWITCH_GPIO, HEADPHONE_TRAINER_SWITCH_GPIO_PIN); } void enableTrainer() { GPIO_SetBits(HEADPHONE_TRAINER_SWITCH_GPIO, HEADPHONE_TRAINER_SWITCH_GPIO_PIN); } #endif #if defined(JACK_DETECT_GPIO) void initJackDetect(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = JACK_DETECT_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(JACK_DETECT_GPIO, &GPIO_InitStructure); } #endif