/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */ /************************************************************************************ ** ** ** mcHF QRP Transceiver ** ** K Atanassov - M0NKA 2014 ** ** ** **---------------------------------------------------------------------------------** ** ** ** File name: ** ** Description: ** ** Last Modified: ** ** Licence: GNU GPLv3 ** ************************************************************************************/ #include "uhsdr_board.h" #include "ui_configuration.h" #include "ui_lcd_hy28.h" #include #include "uhsdr_hw_i2c.h" #include "uhsdr_rtc.h" #include "ui_driver.h" #include "ui_rotary.h" #include "codec.h" #include "soft_tcxo.h" // // Eeprom items #include "uhsdr_flash.h" #include "adc.h" #include "dac.h" #include "uhsdr_keypad.h" #include "osc_si5351a.h" // Transceiver state public structure __IO __MCHF_SPECIALMEM TransceiverState ts; //TransceiverState ts; static void Board_Led_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Pin = GREEN_LED; HAL_GPIO_Init(GREEN_LED_PIO, &GPIO_InitStructure); GPIO_InitStructure.Pin = RED_LED; HAL_GPIO_Init(RED_LED_PIO, &GPIO_InitStructure); } #if 0 // DO NOT ENABLE UNLESS ALL TOUCHSCREEN SETUP CODE IS DISABLED // TOUCHSCREEN AND USART SHARE PA9 Pin static void mchf_board_debug_init(void) { #ifdef DEBUG_BUILD // disabled the USART since it is used by the touch screen code // as well which renders it unusable #error "Debug Build No Longer Supported, needs alternative way of communication" USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; USART_InitStructure.USART_BaudRate = 921600;//230400; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx; // Enable UART clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // Connect PXx to USARTx_Tx GPIO_PinAFConfig(DEBUG_PRINT_PIO, DEBUG_PRINT_SOURCE, GPIO_AF_USART1); // Configure USART Tx as alternate function GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Pin = DEBUG_PRINT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DEBUG_PRINT_PIO, &GPIO_InitStructure); // USART configuration USART_Init(USART1, &USART_InitStructure); // Enable USART USART_Cmd(USART1, ENABLE); // Wait tx ready while (USART_GetFlagStatus(DEBUG_COM, USART_FLAG_TC) == RESET); #endif } #endif static void Board_TxRxCntrPin_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_PULLDOWN; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; // RX/TX control pin init GPIO_InitStructure.Pin = TXRX_CNTR; HAL_GPIO_Init(TXRX_CNTR_PIO, &GPIO_InitStructure); } static void Board_Dac_Init(void) { #ifdef UI_BRD_OVI40 HAL_DAC_Start(&hdac,DAC_CHANNEL_1); HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_8B_R,0); // AUDIO PA volume zero #endif HAL_DAC_Start(&hdac,DAC_CHANNEL_2); HAL_DAC_SetValue(&hdac,DAC_CHANNEL_2,DAC_ALIGN_8B_R,0); } static void Board_Adc_Init(void) { // ADC init for Input Voltage readings HAL_ADC_Start(&hadc1); // ADC init for antenna forward power readings HAL_ADC_Start(&hadc2); // ADC init for antenna return power readings HAL_ADC_Start(&hadc3); } static void Board_PowerDown_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Pin = POWER_DOWN; HAL_GPIO_Init(POWER_DOWN_PIO, &GPIO_InitStructure); // Set initial state - low to enable main regulator GPIO_ResetBits(POWER_DOWN_PIO,POWER_DOWN); } // Band control GPIOs setup // // ------------------------------------------- // BAND BAND0 BAND1 BAND2 // // 80m 1 1 x // 40m 1 0 x // 20/30m 0 0 x // 15-10m 0 1 x // // ------------------------------------------- // static void Board_BandCntr_Init(void) { #ifdef UI_BRD_MCHF // FIXME: USE HAL Init here as well, this handles also the multiple Ports case GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Speed = GPIO_SPEED_LOW; GPIO_InitStructure.Pin = BAND0|BAND1|BAND2; HAL_GPIO_Init(BAND0_PIO, &GPIO_InitStructure); #endif // Set initial state - low (20m band) GPIO_ResetBits(BAND0_PIO,BAND0); GPIO_ResetBits(BAND1_PIO,BAND1); // Pulse the latch relays line, active low, so set high to disable GPIO_SetBits(BAND2_PIO,BAND2); } static void Board_Touchscreen_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Mode = GPIO_MODE_INPUT; GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Pin = TP_IRQ; HAL_GPIO_Init(TP_IRQ_PIO, &GPIO_InitStructure); GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pin = TP_CS; HAL_GPIO_Init(TP_CS_PIO, &GPIO_InitStructure); GPIO_SetBits(TP_CS_PIO, TP_CS); } /** * Get us to a state where display and touch (and some other stuff) works, we have an idea about the * rf hardware connected to us and then let the application do their thing */ void Board_InitMinimal() { // Enable clock on all ports __GPIOA_CLK_ENABLE(); __GPIOB_CLK_ENABLE(); __GPIOC_CLK_ENABLE(); __GPIOD_CLK_ENABLE(); __GPIOE_CLK_ENABLE(); // LED init Board_Led_Init(); Board_RedLed(LED_STATE_ON); // Power up hardware Board_PowerDown_Init(); // FROM HERE // Filter control lines Board_BandCntr_Init(); // Touchscreen SPI Control Signals Init // TODO: Move to CubeMX Config Board_Touchscreen_Init(); // Initialize LO Osc_Init(); // TO HERE: Code be moved to init_full() if we figure out what causes the white screen @MiniTRX SPI // TODO: It seems that some SPI display need some time to get started... // LCD Init UiLcdHy28_Init(); // we determine and set the correct RF board here ts.rf_board = Si5351a_IsPresent()?FOUND_RF_BOARD_OVI40:FOUND_RF_BOARD_MCHF; } /* * This initializes non-essential hardware for later use by the application */ void Board_InitFull() { #ifdef UI_BRD_MCHF // on a STM32F4 MCHF UI we can have the internal RTC only if there is an SPI display. if (ts.display->use_spi == true) #endif { ts.rtc_present = Rtc_isEnabled(); } #ifdef UI_BRD_MCHF // we need to find out which keyboard layout before we init the GPIOs to use it. // at this point we have to have called the display init and the rtc init // in order to know which one to use. if (ts.rtc_present) { Keypad_SetLayoutRTC_MCHF(); } #endif // Init keypad hw based on button map bm Keypad_KeypadInit(); // Encoders init UiRotaryFreqEncoderInit(); UiRotaryEncoderOneInit(); UiRotaryEncoderTwoInit(); UiRotaryEncoderThreeInit(); // Init DACs Board_Dac_Init(); // Enable all ADCs Board_Adc_Init(); } /* * @brief handle final power-off and delay */ void Board_HandlePowerDown() { static ulong powerdown_delay = 0; if(ts.powering_down) // are we powering down? { powerdown_delay++; // yes - do the powerdown delay if(powerdown_delay > POWERDOWN_DELAY_COUNT) // is it time to power down { Board_Powerdown(); // never reached } } } /* * @brief kills power hold immediately and waits for user to release power button * @returns never returns */ void Board_Powerdown() { // we set this to input and add a pullup config // this seems to be more reliably handling power down // on F7 by rising the voltage to high enough levels. // simply setting the OUTPUT to high did not do the trick here // worked on F4, though. GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Mode = GPIO_MODE_INPUT; GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Pin = POWER_DOWN; HAL_GPIO_Init(POWER_DOWN_PIO, &GPIO_InitStructure); // disable all interrupts __disable_irq(); // disable systick irq HAL_SuspendTick(); // set clocks to default state HAL_RCC_DeInit(); // clear Interrupt Enable Register & Interrupt Pending Register const size_t icer_count = sizeof(NVIC->ICER)/sizeof(NVIC->ICER[0]); for (size_t i = 0; i ICER[i]=0xFFFFFFFF; NVIC->ICPR[i]=0xFFFFFFFF; } Board_GreenLed(LED_STATE_OFF); UiLcdHy28_BacklightEnable(false); for(;;) { asm("nop"); } // there is no coming back from here... } /** * This is called once AFTER configuration data has been loaded from persistent storage * (i.e. EEPROM or FLASH) */ void Board_PostInit(void) { // Set system tick interrupt // Currently used for UI driver processing only ///mchf_board_set_system_tick_value(); // PTT control Board_TxRxCntrPin_Init(); if (ts.rtc_present) { Rtc_SetPpm(ts.rtc_calib); } } void Board_Reboot() { ///Si570_ResetConfiguration(); // restore SI570 to factory default *(__IO uint32_t*)(SRAM2_BASE) = 0x55; __DSB(); #if defined(STM32F7) || defined(STM32H7) SCB_CleanDCache(); #endif NVIC_SystemReset(); // restart mcHF } // #pragma GCC optimize("O0") static volatile bool busfault_detected; #define TEST_ADDR_192 (0x20000000 + 0x0001FFFC) #define TEST_ADDR_256 (0x20000000 + 0x0002FFFC) #define TEST_ADDR_512 (0x20000000 + 0x0005FFFC) // function below mostly based on http://stackoverflow.com/questions/23411824/determining-arm-cortex-m3-ram-size-at-run-time __attribute__ ((naked)) void BusFault_Handler(void) { /* NAKED function so we can be sure that SP is correct when we * run our asm code below */ // DO NOT clear the busfault active flag - it causes a hard fault! /* Instead, we must increase the value of the PC, so that when we * return, we don't return to the same instruction. * * Registers are stacked as follows: r0,r1,r2,r3,r12,lr,pc,xPSR * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/Babedgea.html * * So we want PC - the 6th down * 4 bytes = 24 * * Then we add 2 - which IS DANGEROUS because we're assuming that the op * is 2 bytes, but it COULD be 4. */ asm("mov r3, %0\n mov r2,#1\n str r2,[r3,#0]\n" : : "l" (&busfault_detected) ); // WE LEAVE 1 in busfault_detected -> if we have a busfault there is no memory here. __asm__( "ldr r0, [sp, #24]\n" // load the PC "add r0, #2\n" // increase by 2 - dangerous, see above "str r0, [sp, #24]\n" // save the PC back "bx lr\n" // Return (function is naked so we must do this explicitly) ); } /* * Tests if there is ram at the specified location * Use with care and with 4byte aligned addresses. * IT NEEDS A MATCHING BUSFAULT HANDLER!!!! */ __attribute__ ((noinline)) bool is_ram_at(volatile uint32_t* where) { bool retval; // we rely on the BusFault_Handler setting r4 to 0 (aka false) if a busfault occurs. // this is truly bad code as it can be broken easily. The function cannot be optimize // this this breaks the approach. uint32_t oldval; busfault_detected = false; oldval = *where; if (*where == oldval+1) { *where = oldval; } retval = busfault_detected == false; busfault_detected = false; return retval; } uint32_t Board_RamSizeGet() { uint32_t retval = 0; // we enable the bus fault // we now get bus faults if we access not available memory // instead of hard faults // this will run our very special bus fault handler in case no memory // is at the defined location #if defined(STM32F4) || defined(STM32F7) SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk; if (is_ram_at((volatile uint32_t*)TEST_ADDR_512)){ retval=512; } else if (is_ram_at((volatile uint32_t*)TEST_ADDR_256)){ retval=256; } else if (is_ram_at((volatile uint32_t*)TEST_ADDR_192)){ retval=192; } // now we disable it // we'll get hard faults as usual if we access wrong addresses SCB->SHCSR &= ~SCB_SHCSR_BUSFAULTENA_Msk; #elif defined(STM32H7) // TODO make it detect the really available RAM retval = 512; #else #warning Unkown processor, cannot determine ramsize retval = 0; #endif return retval; } /** * Determines the available RAM. Only supports 192 and 256 STM32F4 models * Approach works but makes some assumptions. Do not change if you don't know * what you are doing! * USE WITH CARE! */ void Board_RamSizeDetection() { // we enable the bus fault // we now get bus faults if we access not available memory // instead of hard faults // this will run our very special bus fault handler in case no memory // is at the defined location ts.ramsize = Board_RamSizeGet(); } static void Board_BandFilterPulseRelays(void) { // FIXME: Replace non_os_delay with HAL_Delay GPIO_ResetBits(BAND2_PIO, BAND2); // TODO: Check if we can go down to 10ms as per datasheet // HAL_Delay(20); non_os_delay(); GPIO_SetBits(BAND2_PIO, BAND2); } #ifdef SDR_AMBER void Board_Amber_InputStateSet(uint8_t code) { uint8_t tstate = ts.amber_io8_state; switch(code) { case 0: // PRE [11] { tstate = tstate | 3; // set bits break; } case 1: // NoPRE [10] { tstate = tstate | 2; // set bit tstate = tstate & ~1; // reset bit break; } case 2: // Att12 [01] { tstate = tstate | 1; // set bit tstate = tstate & ~2; // reset bit break; } case 3: // ATT24 [00] { tstate = tstate & ~3; // reset bits break; } default: break; } if(ts.amber_io8_present) { ts.amber_io8_state = tstate; Board_AmberIOx8_Write(tstate); } } static void Board_Amber_BandFilterPulseRelays(bool up) { if(ts.amber_io8_present) { // Control, set relays bits to high ts.amber_io8_state = ts.amber_io8_state | 48; Board_AmberIOx8_Write(ts.amber_io8_state); // Pulse ts.amber_io8_state = ts.amber_io8_state & ~(up ? 16 : 32); // reset bit Board_AmberIOx8_Write(ts.amber_io8_state); // HAL_Delay(20); non_os_delay(); // Off, set relays bits to high ts.amber_io8_state = ts.amber_io8_state | 48; Board_AmberIOx8_Write(ts.amber_io8_state); } } static void Board_Amber_BPF_FilterSet(uint8_t code) { uint8_t tstate = ts.amber_io8_state; switch(code) { case 0: { tstate = tstate & ~12; // reset bits break; } case 1: { tstate = tstate | 4; // set bit tstate = tstate & ~8; // reset bit break; } case 2: { tstate = tstate & ~4; // reset bit tstate = tstate | 8; // set bit break; } case 3: { tstate = tstate | 12; // set bits break; } default: break; } if(ts.amber_io8_present) { ts.amber_io8_state = tstate; Board_AmberIOx8_Write(tstate); } } #endif /** * @brief switches one of the four LPF&BPF groups into the RX/TX signal path * @param group 0: 80m, 1: 40m, 2: 20m , 3:10m */ void Board_SelectLpfBpf(uint8_t group) { // ------------------------------------------- // BAND BAND0 BAND1 BAND2 // // 80m 1 1 x // 40m 1 0 x // 20/30m 0 0 x // 15-10m 0 1 x // --------------------------------------------- // Amber // --------------------------------------------- // <=160m 1 1 x group==4 BPF-option - <160m // Not in use 1 1 x group==5 BPF-option - 160m // 6m 1 1 x group==6 // --------------------------------------------- // Set LPFs: // Set relays in groups, internal first, then external group // state change via two pulses on BAND2 line, then idle // // then // // Set BPFs // Constant line states for the BPF filter, // always last - after LPF change switch(group) { case 0: { #ifdef SDR_AMBER // Subinternal group - Set(Up) Board_Amber_BandFilterPulseRelays(true); #endif // Internal group - Set(High/Low) GPIO_SetBits(BAND0_PIO, BAND0); GPIO_ResetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // External group -Set(High/High) GPIO_SetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // BPF GPIO_SetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); #ifdef SDR_AMBER Board_Amber_BPF_FilterSet(3); #endif break; } case 1: { #ifdef SDR_AMBER // Subinternal group - Set(Up) Board_Amber_BandFilterPulseRelays(true); #endif // Internal group - Set(High/Low) GPIO_SetBits(BAND0_PIO, BAND0); GPIO_ResetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // External group - Reset(Low/High) GPIO_ResetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // BPF GPIO_SetBits(BAND0_PIO, BAND0); GPIO_ResetBits(BAND1_PIO, BAND1); #ifdef SDR_AMBER Board_Amber_BPF_FilterSet(3); #endif break; } case 2: { #ifdef SDR_AMBER // Subinternal group - Set(Up) Board_Amber_BandFilterPulseRelays(true); #endif // Internal group - Reset(Low/Low) GPIO_ResetBits(BAND0_PIO, BAND0); GPIO_ResetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // External group - Reset(Low/High) GPIO_ResetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // BPF GPIO_ResetBits(BAND0_PIO, BAND0); GPIO_ResetBits(BAND1_PIO, BAND1); #ifdef SDR_AMBER Board_Amber_BPF_FilterSet(3); #endif break; } case 3: { #ifdef SDR_AMBER // Subinternal group - Set(Up) Board_Amber_BandFilterPulseRelays(true); #endif // Internal group - Reset(Low/Low) GPIO_ResetBits(BAND0_PIO, BAND0); GPIO_ResetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // External group - Set(High/High) GPIO_SetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // BPF GPIO_ResetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); #ifdef SDR_AMBER Board_Amber_BPF_FilterSet(3); #endif break; } #ifdef SDR_AMBER case 4: // <=160m (BPF-option - <160m) { // Subinternal group - Set(Down) - for 160m Board_Amber_BandFilterPulseRelays(false); // Internal group - Set(High/Low) - as 80m GPIO_SetBits(BAND0_PIO, BAND0); GPIO_ResetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // External group -Set(High/High) - as 80m GPIO_SetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // BPF - as 80m GPIO_SetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); Board_Amber_BPF_FilterSet(2); break; } case 5: // Not in use (BPF-option - 160m) { // Subinternal group - Set(Down) - for 160m Board_Amber_BandFilterPulseRelays(false); // Internal group - Set(High/Low) - as 80m GPIO_SetBits(BAND0_PIO, BAND0); GPIO_ResetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // External group -Set(High/High) - as 80m GPIO_SetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // BPF - as 80m GPIO_SetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); Board_Amber_BPF_FilterSet(0); break; } case 6: // 6m { // Subinternal group - Set(Down) - for 6m Board_Amber_BandFilterPulseRelays(false); // Internal group - Reset(Low/Low) - as 10m GPIO_ResetBits(BAND0_PIO, BAND0); GPIO_ResetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // External group - Set(High/High) - as 10m GPIO_SetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); Board_BandFilterPulseRelays(); // BPF - as 80m GPIO_SetBits(BAND0_PIO, BAND0); GPIO_SetBits(BAND1_PIO, BAND1); Board_Amber_BPF_FilterSet(1); break; } #endif default: break; } } const char* Board_BootloaderVersion() { const char* outs = "Unknown BL"; // We search for string "Version: " in bootloader memory // this assume the bootloader starting at 0x8000000 and being followed by the virtual eeprom // which starts at EEPROM_START_ADDRESS for(uint8_t* begin = (uint8_t*)0x8000000; begin < (uint8_t*)EEPROM_START_ADDRESS-8; begin++) { if (memcmp("Version: ",begin,9) == 0) { outs = (const char*)&begin[9]; break; } else { if (memcmp("M0NKA 2",begin,7) == 0) { if (begin[11] == 0xb5) { outs = "M0NKA 0.0.0.9"; break; } else if (begin[11] == 0xd1) { outs = "M0NKA 0.0.0.14"; break; } } } } return outs; } /** * @brief set PA bias at the LM2931CDG (U18) using DAC Channel 2 */ void Board_SetPaBiasValue(uint16_t bias) { // Set DAC Channel 1 DHR12L register // DAC_SetChannel2Data(DAC_Align_8b_R,bias); HAL_DAC_SetValue(&hdac, DAC_CHANNEL_2, DAC_ALIGN_8B_R, bias); } void Board_GreenLed(ledstate_t state) { switch(state) { case LED_STATE_ON: GPIO_SetBits(GREEN_LED_PIO, GREEN_LED); break; case LED_STATE_OFF: GPIO_ResetBits(GREEN_LED_PIO, GREEN_LED); break; default: GPIO_ToggleBits(GREEN_LED_PIO, GREEN_LED); break; } } void Board_RedLed(ledstate_t state) { switch(state) { case LED_STATE_ON: GPIO_SetBits(RED_LED_PIO, RED_LED); break; case LED_STATE_OFF: GPIO_ResetBits(RED_LED_PIO, RED_LED); break; default: GPIO_ToggleBits(RED_LED_PIO, RED_LED); break; } } #ifdef UI_BRD_OVI40 void Board_BlueLed(ledstate_t state) { switch(state) { case LED_STATE_ON: GPIO_SetBits(BLUE_LED_PIO, BLUE_LED); break; case LED_STATE_OFF: GPIO_ResetBits(BLUE_LED_PIO, BLUE_LED); break; default: GPIO_ToggleBits(BLUE_LED_PIO, BLUE_LED); break; } } #endif #ifdef SDR_AMBER void Board_IllumButt() { if(ts.amber_io8_present) { // bit6 == 1 - Illumination of buttons is ON if(ts.expflags2 & EXPFLAGS2_ILLUM_BUTT) { ts.amber_io8_state = ts.amber_io8_state | 64; // set bit } else { ts.amber_io8_state = ts.amber_io8_state & ~64; // reset bit } Board_AmberIOx8_Write(ts.amber_io8_state); } } #endif /** * @brief sets the hw ptt line and by this switches the mcHF board signal path between rx and tx configuration * @param tx_enable true == TX Paths, false == RX Paths */ void Board_EnableTXSignalPath(bool tx_enable) { // to make switching as noiseless as possible, make sure the codec lineout is muted/produces zero output before switching if (tx_enable) { GPIO_SetBits(TXRX_CNTR_PIO,TXRX_CNTR); // TX on and switch CODEC audio paths // Antenna Direction Output // BPF Direction Output (U1,U2) // PTT Optocoupler LED On (ACC Port) (U6) // QSD Mixer Output Disable (U15) // QSE Mixer Output Enable (U17) // Codec LineIn comes from mcHF LineIn Socket (U3) // Codec LineOut connected to QSE mixer (IQ Out) (U3a) } else { GPIO_ResetBits(TXRX_CNTR_PIO,TXRX_CNTR); // TX off // Antenna Direction Input // BPF Direction Input (U1,U2) // PTT Optocoupler LED Off (ACC Port) (U6) // QSD Mixer Output Enable (U15) // QSE Mixer Output Disable (U17) // Codec LineIn comes from RF Board QSD mixer (IQ In) (U3) // Codec LineOut disconnected from QSE mixer (IQ Out) (U3a) } } /** * Is the hardware contact named DAH pressed */ bool Board_PttDahLinePressed() { return !HAL_GPIO_ReadPin(PADDLE_DAH_PIO,PADDLE_DAH); } #ifdef SDR_AMBER_PTT_ALT bool Board_PttAltLinePressed() { return !HAL_GPIO_ReadPin(BUTTON_S19_PIO, BUTTON_S19); } #endif /** * Is the hardware contact named DIT pressed */ bool Board_DitLinePressed() { return !HAL_GPIO_ReadPin(PADDLE_DIT_PIO,PADDLE_DIT); } // For DACs MCP4725 - on band carrier TX depression uint16_t LO_TX_SUPR_DAC_WriteReg(uint8_t qitem, uint16_t cal_value) { uint8_t write_address = qitem?LO_TX_SUPR_DAC1_WRITE:LO_TX_SUPR_DAC0_WRITE; uint8_t write_data[2] = { (cal_value & 0x00FFFFFF) >> 4, (cal_value & 0x000000FF) << 4 }; return UhsdrHw_I2C_WriteBlock(SERIALEEPROM_I2C, write_address, 64, 1, write_data, 2); } #ifdef SDR_AMBER // For DAC MCP4725 - Alt. POWER level ctrl. uint16_t ALT_RWP_CTRL_DAC_WriteReg(uint16_t vol_value) { uint8_t write_address = AMBER_DAC_PWR_TX_WRITE; uint8_t write_data[2] = { (vol_value & 0x00FFFFFF) >> 4, (vol_value & 0x000000FF) << 4 }; return UhsdrHw_I2C_WriteBlock(SI5351A_I2C, write_address, 64, 1, write_data, 2); } uint16_t Board_AmberIOx8_Write(uint8_t value) { uint8_t write_address = AMBER_IO8_WRITE; uint8_t write_data[2] = { value, value }; return UhsdrHw_I2C_WriteBlock(SERIALEEPROM_I2C, write_address, 64, 1, write_data, 2); } uint16_t Board_AmberIOx4_Write(uint8_t command, uint8_t value) { return UhsdrHw_I2C_WriteRegister(SERIALEEPROM_I2C, AMBER_IO4_WRITE, command, 1, value); } uint16_t Board_AmberCS4270_Write(uint8_t map, uint8_t value) { return UhsdrHw_I2C_WriteRegister(CODEC_IQ_I2C, AMBER_CS4270_WRITE, map, 1, value); } #endif // Determine the "band" for LO TX Supression void LO_TX_SUPR_DAC_GetBand(uint32_t freq) { ts.band_lo_tx_supr = ts.band_index; if (ts.band_lo_tx_supr == 16) // BAND_MODE_160 { ts.band_lo_tx_supr = 10; // Don't calibrate add.OVI40 bands, but 160m is so far away... } if (ts.band_lo_tx_supr > 10) { ts.band_lo_tx_supr = 13; // Gen band for LO TX Supression. Don't calibrate add. OVI40 bands } if (ts.band_lo_tx_supr == 13) // CB band? { if (ts.HereIsEnableCB26Mc) { ts.band_lo_tx_supr = 11; } if (ts.HereIsEnableCB27Mc) { ts.band_lo_tx_supr = 12; } } if (ts.band_lo_tx_supr == 8) // 28Mc? { if (freq > 28850000) { ts.band_lo_tx_supr = 14; // Additional adjustment point for the upper half of the band 28 Mc } } if (ts.band_lo_tx_supr != ts.band_lo_tx_supr_old) { LO_TX_SUPR_DAC_WriteReg(0, ts.cal_lo_tx_supr0[ts.band_lo_tx_supr]); // Set the DAC0 voltage LO_TX_SUPR_DAC_WriteReg(1, ts.cal_lo_tx_supr1[ts.band_lo_tx_supr]); // Set the DAC1 voltage ts.band_lo_tx_supr_old = ts.band_lo_tx_supr; } } void CW_Smooth_Settings(void) { switch (ts.cw_smooth) { case 0: // 3 ms ts.cw_smooth_len = 1; ts.cw_smooth_steps = 5; break; case 1: // 5 ms ts.cw_smooth_len = 2; ts.cw_smooth_steps = 9; break; case 2: // 8 ms ts.cw_smooth_len = 3; ts.cw_smooth_steps = 13; break; case 3: // 10 ms ts.cw_smooth_len = 4; ts.cw_smooth_steps = 18; break; } } #ifndef UI_BRD_MCHF void MIC_bias_set(void) { if(ts.tx_mic_boost > 0) // dinamic MIC { GPIO_SetBits(AUDIO_MIC_BIAS_PIO,AUDIO_MIC_BIAS); } else // electret MIC { GPIO_ResetBits(AUDIO_MIC_BIAS_PIO,AUDIO_MIC_BIAS); } } #endif