From 902ae831bfe5b93277a816d012b44e2d61e7b61c Mon Sep 17 00:00:00 2001 From: Antoine van Gelder Date: Thu, 19 Mar 2026 11:30:54 +0200 Subject: [PATCH 1/7] firmware: move cpu clock logic to cpu_clock.h|c --- firmware/common/cpu_clock.c | 252 +++++++++++++++++++++++++++++++ firmware/common/cpu_clock.h | 34 +++++ firmware/common/hackrf_core.c | 225 +-------------------------- firmware/common/hackrf_core.h | 3 +- firmware/hackrf-common.cmake | 1 + firmware/hackrf_usb/hackrf_usb.c | 1 + 6 files changed, 291 insertions(+), 225 deletions(-) create mode 100644 firmware/common/cpu_clock.c create mode 100644 firmware/common/cpu_clock.h diff --git a/firmware/common/cpu_clock.c b/firmware/common/cpu_clock.c new file mode 100644 index 000000000..1bbd95718 --- /dev/null +++ b/firmware/common/cpu_clock.c @@ -0,0 +1,252 @@ +/* + * Copyright 2026 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "cpu_clock.h" + +#include + +#include +#if defined(IS_JAWBREAKER) || defined(IS_HACKRF_ONE) || defined(IS_PRALINE) + #include +#endif + +#include "delay.h" +#include "hackrf_core.h" +#include "i2c_bus.h" +#ifdef IS_NOT_RAD1O + #include "platform_detect.h" +#endif + +/* +Configure PLL1 (Main MCU Clock) to max speed (204MHz). +Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. +This function shall be called after cpu_clock_init(). +*/ +static void cpu_clock_pll1_max_speed(void) +{ + uint32_t reg_val; + + /* This function implements the sequence recommended in: + * UM10503 Rev 2.4 (Aug 2018), section 13.2.1.1, page 167. */ + + /* 1. Select the IRC as BASE_M4_CLK source. */ + reg_val = CGU_BASE_M4_CLK; + reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK; + reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_IRC) | CGU_BASE_M4_CLK_AUTOBLOCK(1); + CGU_BASE_M4_CLK = reg_val; + + /* 2. Enable the crystal oscillator. */ + CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE_MASK; + + /* 3. Wait 250us. */ + delay_us_at_mhz(250, 12); + + /* 4. Set the AUTOBLOCK bit. */ + CGU_PLL1_CTRL |= CGU_PLL1_CTRL_AUTOBLOCK(1); + + /* 5. Reconfigure PLL1 to produce the final output frequency, with the + * crystal oscillator as clock source. */ + reg_val = CGU_PLL1_CTRL; + // clang-format off + reg_val &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK | + CGU_PLL1_CTRL_PD_MASK | + CGU_PLL1_CTRL_FBSEL_MASK | + CGU_PLL1_CTRL_BYPASS_MASK | + CGU_PLL1_CTRL_DIRECT_MASK | + CGU_PLL1_CTRL_PSEL_MASK | + CGU_PLL1_CTRL_MSEL_MASK | + CGU_PLL1_CTRL_NSEL_MASK ); + /* Set PLL1 up to 12MHz * 17 = 204MHz. + * Direct mode: FCLKOUT = FCCO = M*(FCLKIN/N) */ + reg_val |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL) | + CGU_PLL1_CTRL_PSEL(0) | + CGU_PLL1_CTRL_NSEL(0) | + CGU_PLL1_CTRL_MSEL(16) | + CGU_PLL1_CTRL_FBSEL(0) | + CGU_PLL1_CTRL_DIRECT(1); + // clang-format on + CGU_PLL1_CTRL = reg_val; + + /* 6. Wait for PLL1 to lock. */ + while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK)) {} + + /* 7. Set the PLL1 P-divider to divide by 2 (DIRECT=0, PSEL=0). */ + CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_DIRECT_MASK; + + /* 8. Select PLL1 as BASE_M4_CLK source. */ + reg_val = CGU_BASE_M4_CLK; + reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK; + reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1); + CGU_BASE_M4_CLK = reg_val; + + /* 9. Wait 50us. */ + delay_us_at_mhz(50, 102); + + /* 10. Set the PLL1 P-divider to direct output mode (DIRECT=1). */ + CGU_PLL1_CTRL |= CGU_PLL1_CTRL_DIRECT_MASK; +} + +/* clock startup for LPC4320 configure PLL1 to max speed (204MHz). +Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. */ +void cpu_clock_init(void) +{ + /* use IRC as clock source for APB1 (including I2C0) */ + CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_IRC); + + /* use IRC as clock source for APB3 */ + CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC); + + //FIXME disable I2C + /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); + + /* + * 12MHz clock is entering LPC XTAL1/OSC input now. + * On HackRF One and Jawbreaker, there is a 12 MHz crystal at the LPC. + * Set up PLL1 to run from XTAL1 input. + */ + + //FIXME a lot of the details here should be in a CGU driver + + /* set xtal oscillator to low frequency mode */ + CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF_MASK; + + cpu_clock_pll1_max_speed(); + + /* use XTAL_OSC as clock source for APB1 */ + CGU_BASE_APB1_CLK = + CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_XTAL); + + /* use XTAL_OSC as clock source for APB3 */ + CGU_BASE_APB3_CLK = + CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_XTAL); + + /* use XTAL_OSC as clock source for PLL0USB */ + CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_AUTOBLOCK(1) | + CGU_PLL0USB_CTRL_CLK_SEL(CGU_SRC_XTAL); + while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK) {} + + /* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */ + /* Values from User Manual v1.4 Table 94, for 12MHz oscillator. */ + CGU_PLL0USB_MDIV = 0x06167FFA; + CGU_PLL0USB_NP_DIV = 0x00302062; + CGU_PLL0USB_CTRL |= + (CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_DIRECTI(1) | + CGU_PLL0USB_CTRL_DIRECTO(1) | CGU_PLL0USB_CTRL_CLKEN(1)); + + /* power on PLL0USB and wait until stable */ + CGU_PLL0USB_CTRL &= ~CGU_PLL0USB_CTRL_PD_MASK; + while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK)) {} + + /* use PLL0USB as clock source for USB0 */ + CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK(1) | + CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB); + + /* Switch peripheral clock over to use PLL1 (204MHz) */ + CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK(1) | + CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); + + /* Switch APB1 clock over to use PLL1 (204MHz) */ + CGU_BASE_APB1_CLK = + CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); + + /* Switch APB3 clock over to use PLL1 (204MHz) */ + CGU_BASE_APB3_CLK = + CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_PLL1); + + CGU_BASE_SSP0_CLK = + CGU_BASE_SSP0_CLK_AUTOBLOCK(1) | CGU_BASE_SSP0_CLK_CLK_SEL(CGU_SRC_PLL1); + + CGU_BASE_SSP1_CLK = + CGU_BASE_SSP1_CLK_AUTOBLOCK(1) | CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1); + +#ifdef IS_NOT_RAD1O + if (IS_NOT_RAD1O) { + /* Disable unused clocks */ + /* Start with PLLs */ + CGU_PLL0AUDIO_CTRL = CGU_PLL0AUDIO_CTRL_PD(1); + + /* Dividers */ + CGU_IDIVA_CTRL = CGU_IDIVA_CTRL_PD(1); + CGU_IDIVB_CTRL = CGU_IDIVB_CTRL_PD(1); + CGU_IDIVC_CTRL = CGU_IDIVC_CTRL_PD(1); + CGU_IDIVD_CTRL = CGU_IDIVD_CTRL_PD(1); + CGU_IDIVE_CTRL = CGU_IDIVE_CTRL_PD(1); + + /* Base clocks */ + CGU_BASE_SPIFI_CLK = + CGU_BASE_SPIFI_CLK_PD(1); /* SPIFI is only used at boot */ + CGU_BASE_USB1_CLK = + CGU_BASE_USB1_CLK_PD(1); /* USB1 is not exposed on HackRF */ + CGU_BASE_PHY_RX_CLK = CGU_BASE_PHY_RX_CLK_PD(1); + CGU_BASE_PHY_TX_CLK = CGU_BASE_PHY_TX_CLK_PD(1); + CGU_BASE_LCD_CLK = CGU_BASE_LCD_CLK_PD(1); + CGU_BASE_VADC_CLK = CGU_BASE_VADC_CLK_PD(1); + CGU_BASE_SDIO_CLK = CGU_BASE_SDIO_CLK_PD(1); + CGU_BASE_UART0_CLK = CGU_BASE_UART0_CLK_PD(1); + CGU_BASE_UART1_CLK = CGU_BASE_UART1_CLK_PD(1); + CGU_BASE_UART2_CLK = CGU_BASE_UART2_CLK_PD(1); + CGU_BASE_UART3_CLK = CGU_BASE_UART3_CLK_PD(1); + CGU_BASE_OUT_CLK = CGU_BASE_OUT_CLK_PD(1); + CGU_BASE_AUDIO_CLK = CGU_BASE_AUDIO_CLK_PD(1); + CGU_BASE_CGU_OUT0_CLK = CGU_BASE_CGU_OUT0_CLK_PD(1); + CGU_BASE_CGU_OUT1_CLK = CGU_BASE_CGU_OUT1_CLK_PD(1); + + /* Disable unused peripheral clocks */ + CCU1_CLK_APB1_CAN1_CFG = 0; + CCU1_CLK_APB1_I2S_CFG = 0; + CCU1_CLK_APB1_MOTOCONPWM_CFG = 0; + //CCU1_CLK_APB3_ADC0_CFG = 0; + CCU1_CLK_APB3_ADC1_CFG = 0; + CCU1_CLK_APB3_CAN0_CFG = 0; + CCU1_CLK_APB3_DAC_CFG = 0; + //CCU1_CLK_M4_DMA_CFG = 0; + CCU1_CLK_M4_EMC_CFG = 0; + CCU1_CLK_M4_EMCDIV_CFG = 0; + CCU1_CLK_M4_ETHERNET_CFG = 0; + CCU1_CLK_M4_LCD_CFG = 0; + CCU1_CLK_M4_QEI_CFG = 0; + CCU1_CLK_M4_RITIMER_CFG = 0; + // CCU1_CLK_M4_SCT_CFG = 0; + CCU1_CLK_M4_SDIO_CFG = 0; + CCU1_CLK_M4_SPIFI_CFG = 0; + CCU1_CLK_M4_TIMER0_CFG = 0; + //CCU1_CLK_M4_TIMER1_CFG = 0; + //CCU1_CLK_M4_TIMER2_CFG = 0; + CCU1_CLK_M4_TIMER3_CFG = 0; + CCU1_CLK_M4_UART1_CFG = 0; + CCU1_CLK_M4_USART0_CFG = 0; + CCU1_CLK_M4_USART2_CFG = 0; + CCU1_CLK_M4_USART3_CFG = 0; + CCU1_CLK_M4_USB1_CFG = 0; + CCU1_CLK_M4_VADC_CFG = 0; + // CCU1_CLK_SPIFI_CFG = 0; + // CCU1_CLK_USB1_CFG = 0; + // CCU1_CLK_VADC_CFG = 0; + // CCU2_CLK_APB0_UART1_CFG = 0; + // CCU2_CLK_APB0_USART0_CFG = 0; + // CCU2_CLK_APB2_USART2_CFG = 0; + // CCU2_CLK_APB2_USART3_CFG = 0; + // CCU2_CLK_APLL_CFG = 0; + // CCU2_CLK_SDIO_CFG = 0; + } +#endif +} diff --git a/firmware/common/cpu_clock.h b/firmware/common/cpu_clock.h new file mode 100644 index 000000000..b0393081c --- /dev/null +++ b/firmware/common/cpu_clock.h @@ -0,0 +1,34 @@ +/* + * Copyright 2026 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "platform_detect.h" // IWYU pragma: keep + +void cpu_clock_init(void); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index d56799425..e9bc4c2ef 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -21,17 +21,12 @@ * Boston, MA 02110-1301, USA. */ -#include #include #include #include #include "platform_detect.h" -#ifdef IS_NOT_RAD1O - #include -#endif - #include "delay.h" #include "gpio.h" #include "hackrf_core.h" @@ -44,14 +39,12 @@ #include "spi_bus.h" #include "w25q80bv_target.h" #ifdef IS_EXPANSION_COMPATIBLE - #include "portapack.h" + #include "portapack.h" #endif #ifdef IS_PRALINE #include "ice40_spi.h" #endif -#include - i2c_bus_t i2c0 = { .obj = (void*) I2C0_BASE, .start = i2c_lpc_start, @@ -428,222 +421,6 @@ fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program) return resultant_rate; } -/* -Configure PLL1 (Main MCU Clock) to max speed (204MHz). -Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. -This function shall be called after cpu_clock_init(). -*/ -static void cpu_clock_pll1_max_speed(void) -{ - uint32_t reg_val; - - /* This function implements the sequence recommended in: - * UM10503 Rev 2.4 (Aug 2018), section 13.2.1.1, page 167. */ - - /* 1. Select the IRC as BASE_M4_CLK source. */ - reg_val = CGU_BASE_M4_CLK; - reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK; - reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_IRC) | CGU_BASE_M4_CLK_AUTOBLOCK(1); - CGU_BASE_M4_CLK = reg_val; - - /* 2. Enable the crystal oscillator. */ - CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE_MASK; - - /* 3. Wait 250us. */ - delay_us_at_mhz(250, 12); - - /* 4. Set the AUTOBLOCK bit. */ - CGU_PLL1_CTRL |= CGU_PLL1_CTRL_AUTOBLOCK(1); - - /* 5. Reconfigure PLL1 to produce the final output frequency, with the - * crystal oscillator as clock source. */ - reg_val = CGU_PLL1_CTRL; - // clang-format off - reg_val &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK | - CGU_PLL1_CTRL_PD_MASK | - CGU_PLL1_CTRL_FBSEL_MASK | - CGU_PLL1_CTRL_BYPASS_MASK | - CGU_PLL1_CTRL_DIRECT_MASK | - CGU_PLL1_CTRL_PSEL_MASK | - CGU_PLL1_CTRL_MSEL_MASK | - CGU_PLL1_CTRL_NSEL_MASK ); - /* Set PLL1 up to 12MHz * 17 = 204MHz. - * Direct mode: FCLKOUT = FCCO = M*(FCLKIN/N) */ - reg_val |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL) | - CGU_PLL1_CTRL_PSEL(0) | - CGU_PLL1_CTRL_NSEL(0) | - CGU_PLL1_CTRL_MSEL(16) | - CGU_PLL1_CTRL_FBSEL(0) | - CGU_PLL1_CTRL_DIRECT(1); - // clang-format on - CGU_PLL1_CTRL = reg_val; - - /* 6. Wait for PLL1 to lock. */ - while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK)) {} - - /* 7. Set the PLL1 P-divider to divide by 2 (DIRECT=0, PSEL=0). */ - CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_DIRECT_MASK; - - /* 8. Select PLL1 as BASE_M4_CLK source. */ - reg_val = CGU_BASE_M4_CLK; - reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK; - reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1); - CGU_BASE_M4_CLK = reg_val; - - /* 9. Wait 50us. */ - delay_us_at_mhz(50, 102); - - /* 10. Set the PLL1 P-divider to direct output mode (DIRECT=1). */ - CGU_PLL1_CTRL |= CGU_PLL1_CTRL_DIRECT_MASK; -} - -/* clock startup for LPC4320 configure PLL1 to max speed (204MHz). -Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. */ -void cpu_clock_init(void) -{ - /* use IRC as clock source for APB1 (including I2C0) */ - CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_IRC); - - /* use IRC as clock source for APB3 */ - CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC); - - //FIXME disable I2C - /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ - i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); - - /* - * 12MHz clock is entering LPC XTAL1/OSC input now. - * On HackRF One and Jawbreaker, there is a 12 MHz crystal at the LPC. - * Set up PLL1 to run from XTAL1 input. - */ - - //FIXME a lot of the details here should be in a CGU driver - - /* set xtal oscillator to low frequency mode */ - CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF_MASK; - - cpu_clock_pll1_max_speed(); - - /* use XTAL_OSC as clock source for APB1 */ - CGU_BASE_APB1_CLK = - CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_XTAL); - - /* use XTAL_OSC as clock source for APB3 */ - CGU_BASE_APB3_CLK = - CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_XTAL); - - /* use XTAL_OSC as clock source for PLL0USB */ - CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_AUTOBLOCK(1) | - CGU_PLL0USB_CTRL_CLK_SEL(CGU_SRC_XTAL); - while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK) {} - - /* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */ - /* Values from User Manual v1.4 Table 94, for 12MHz oscillator. */ - CGU_PLL0USB_MDIV = 0x06167FFA; - CGU_PLL0USB_NP_DIV = 0x00302062; - CGU_PLL0USB_CTRL |= - (CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_DIRECTI(1) | - CGU_PLL0USB_CTRL_DIRECTO(1) | CGU_PLL0USB_CTRL_CLKEN(1)); - - /* power on PLL0USB and wait until stable */ - CGU_PLL0USB_CTRL &= ~CGU_PLL0USB_CTRL_PD_MASK; - while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK)) {} - - /* use PLL0USB as clock source for USB0 */ - CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK(1) | - CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB); - - /* Switch peripheral clock over to use PLL1 (204MHz) */ - CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK(1) | - CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); - - /* Switch APB1 clock over to use PLL1 (204MHz) */ - CGU_BASE_APB1_CLK = - CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); - - /* Switch APB3 clock over to use PLL1 (204MHz) */ - CGU_BASE_APB3_CLK = - CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_PLL1); - - CGU_BASE_SSP0_CLK = - CGU_BASE_SSP0_CLK_AUTOBLOCK(1) | CGU_BASE_SSP0_CLK_CLK_SEL(CGU_SRC_PLL1); - - CGU_BASE_SSP1_CLK = - CGU_BASE_SSP1_CLK_AUTOBLOCK(1) | CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1); - -#ifdef IS_NOT_RAD1O - if (IS_NOT_RAD1O) { - /* Disable unused clocks */ - /* Start with PLLs */ - CGU_PLL0AUDIO_CTRL = CGU_PLL0AUDIO_CTRL_PD(1); - - /* Dividers */ - CGU_IDIVA_CTRL = CGU_IDIVA_CTRL_PD(1); - CGU_IDIVB_CTRL = CGU_IDIVB_CTRL_PD(1); - CGU_IDIVC_CTRL = CGU_IDIVC_CTRL_PD(1); - CGU_IDIVD_CTRL = CGU_IDIVD_CTRL_PD(1); - CGU_IDIVE_CTRL = CGU_IDIVE_CTRL_PD(1); - - /* Base clocks */ - CGU_BASE_SPIFI_CLK = - CGU_BASE_SPIFI_CLK_PD(1); /* SPIFI is only used at boot */ - CGU_BASE_USB1_CLK = - CGU_BASE_USB1_CLK_PD(1); /* USB1 is not exposed on HackRF */ - CGU_BASE_PHY_RX_CLK = CGU_BASE_PHY_RX_CLK_PD(1); - CGU_BASE_PHY_TX_CLK = CGU_BASE_PHY_TX_CLK_PD(1); - CGU_BASE_LCD_CLK = CGU_BASE_LCD_CLK_PD(1); - CGU_BASE_VADC_CLK = CGU_BASE_VADC_CLK_PD(1); - CGU_BASE_SDIO_CLK = CGU_BASE_SDIO_CLK_PD(1); - CGU_BASE_UART0_CLK = CGU_BASE_UART0_CLK_PD(1); - CGU_BASE_UART1_CLK = CGU_BASE_UART1_CLK_PD(1); - CGU_BASE_UART2_CLK = CGU_BASE_UART2_CLK_PD(1); - CGU_BASE_UART3_CLK = CGU_BASE_UART3_CLK_PD(1); - CGU_BASE_OUT_CLK = CGU_BASE_OUT_CLK_PD(1); - CGU_BASE_AUDIO_CLK = CGU_BASE_AUDIO_CLK_PD(1); - CGU_BASE_CGU_OUT0_CLK = CGU_BASE_CGU_OUT0_CLK_PD(1); - CGU_BASE_CGU_OUT1_CLK = CGU_BASE_CGU_OUT1_CLK_PD(1); - - /* Disable unused peripheral clocks */ - CCU1_CLK_APB1_CAN1_CFG = 0; - CCU1_CLK_APB1_I2S_CFG = 0; - CCU1_CLK_APB1_MOTOCONPWM_CFG = 0; - //CCU1_CLK_APB3_ADC0_CFG = 0; - CCU1_CLK_APB3_ADC1_CFG = 0; - CCU1_CLK_APB3_CAN0_CFG = 0; - CCU1_CLK_APB3_DAC_CFG = 0; - //CCU1_CLK_M4_DMA_CFG = 0; - CCU1_CLK_M4_EMC_CFG = 0; - CCU1_CLK_M4_EMCDIV_CFG = 0; - CCU1_CLK_M4_ETHERNET_CFG = 0; - CCU1_CLK_M4_LCD_CFG = 0; - CCU1_CLK_M4_QEI_CFG = 0; - CCU1_CLK_M4_RITIMER_CFG = 0; - // CCU1_CLK_M4_SCT_CFG = 0; - CCU1_CLK_M4_SDIO_CFG = 0; - CCU1_CLK_M4_SPIFI_CFG = 0; - CCU1_CLK_M4_TIMER0_CFG = 0; - //CCU1_CLK_M4_TIMER1_CFG = 0; - //CCU1_CLK_M4_TIMER2_CFG = 0; - CCU1_CLK_M4_TIMER3_CFG = 0; - CCU1_CLK_M4_UART1_CFG = 0; - CCU1_CLK_M4_USART0_CFG = 0; - CCU1_CLK_M4_USART2_CFG = 0; - CCU1_CLK_M4_USART3_CFG = 0; - CCU1_CLK_M4_USB1_CFG = 0; - CCU1_CLK_M4_VADC_CFG = 0; - // CCU1_CLK_SPIFI_CFG = 0; - // CCU1_CLK_USB1_CFG = 0; - // CCU1_CLK_VADC_CFG = 0; - // CCU2_CLK_APB0_UART1_CFG = 0; - // CCU2_CLK_APB0_USART0_CFG = 0; - // CCU2_CLK_APB2_USART2_CFG = 0; - // CCU2_CLK_APB2_USART3_CFG = 0; - // CCU2_CLK_APLL_CFG = 0; - // CCU2_CLK_SDIO_CFG = 0; - } -#endif -} - void clock_gen_init(void) { i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 56221f6b6..334d74a0f 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -33,6 +33,7 @@ extern "C" { #include "cpld_jtag.h" #include "fixed_point.h" #include "i2c_bus.h" +#include "i2c_lpc.h" #include "max283x.h" #include "max5864.h" #include "mixer.h" @@ -49,6 +50,7 @@ extern "C" { #endif /* TODO: Hide these configurations */ +extern const i2c_lpc_config_t i2c_config_si5351c_fast_clock; extern si5351c_driver_t clock_gen; extern ssp_config_t ssp_config_w25q80bv; @@ -67,7 +69,6 @@ extern rf_path_t rf_path; extern jtag_t jtag_cpld; extern i2c_bus_t i2c0; -void cpu_clock_init(void); void clock_gen_init(void); void clock_gen_shutdown(void); void ssp1_set_mode_max283x(void); diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index 9a349b1ef..a2823405c 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -168,6 +168,7 @@ endmacro() macro(DeclareTargets) SET(SRC_M4 ${SRC_M4} + ${PATH_HACKRF_FIRMWARE_COMMON}/cpu_clock.c ${PATH_HACKRF_FIRMWARE_COMMON}/delay.c ${PATH_HACKRF_FIRMWARE_COMMON}/hackrf_core.c ${PATH_HACKRF_FIRMWARE_COMMON}/sgpio.c diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index b79dcdecf..dba9a39ed 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include From b8cd1d51a7e3d605b238a68f6051c74c5e1bc8ca Mon Sep 17 00:00:00 2001 From: Antoine van Gelder Date: Thu, 19 Mar 2026 11:04:47 +0200 Subject: [PATCH 2/7] firmware: move clock generator logic to clock_gen.h|c --- firmware/common/clock_gen.c | 452 ++++++++++++++++++++++ firmware/common/clock_gen.h | 76 ++++ firmware/common/fpga_selftest.c | 1 + firmware/common/hackrf_core.c | 416 +------------------- firmware/common/hackrf_core.h | 27 -- firmware/common/hackrf_ui.h | 2 +- firmware/common/radio.h | 7 - firmware/common/ui_portapack.c | 2 +- firmware/common/ui_rad1o.c | 5 +- firmware/hackrf-common.cmake | 1 + firmware/hackrf_usb/hackrf_usb.c | 1 + firmware/hackrf_usb/usb_api_board_info.c | 1 + firmware/hackrf_usb/usb_api_praline.c | 1 + firmware/hackrf_usb/usb_api_transceiver.c | 1 + 14 files changed, 541 insertions(+), 452 deletions(-) create mode 100644 firmware/common/clock_gen.c create mode 100644 firmware/common/clock_gen.h diff --git a/firmware/common/clock_gen.c b/firmware/common/clock_gen.c new file mode 100644 index 000000000..e29e5a916 --- /dev/null +++ b/firmware/common/clock_gen.c @@ -0,0 +1,452 @@ +/* + * Copyright 2026 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "clock_gen.h" + +#include + +#include "hackrf_core.h" +#include "hackrf_ui.h" +#include "i2c_bus.h" +#include "platform_detect.h" +#include "sgpio.h" +#include "si5351c.h" +#if defined(IS_HACKRF_ONE) || defined(IS_PRALINE) + #include "delay.h" + #include "portapack.h" +#endif +#if defined(IS_PRALINE) + #include "gpio.h" + #include "platform_gpio.h" +#endif + +void clock_gen_init(void) +{ + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); + + si5351c_init(&clock_gen); + si5351c_disable_all_outputs(&clock_gen); + si5351c_disable_oeb_pin_control(&clock_gen); + si5351c_power_down_all_clocks(&clock_gen); + si5351c_set_crystal_configuration(&clock_gen); + si5351c_enable_xo_and_ms_fanout(&clock_gen); + + /* + * Clocks on HackRF One r9: + * CLK0 -> MAX5864/CPLD/SGPIO (sample clocks) + * CLK1 -> RFFC5072/MAX2839 + * CLK2 -> External Clock Output/LPC43xx (power down at boot) + * + * Clocks on other platforms: + * CLK0 -> MAX5864/CPLD + * CLK1 -> CPLD + * CLK2 -> SGPIO + * CLK3 -> External Clock Output (power down at boot) + * CLK4 -> RFFC5072 (MAX2837 on rad1o) + * CLK5 -> MAX2837 (MAX2871 on rad1o) + * CLK6 -> none + * CLK7 -> LPC43xx (uses a 12MHz crystal by default) + * + * Clocks on Praline: + * CLK0 -> AFE_CLK (MAX5864/FPGA) + * CLK1 -> SCT_CLK + * CLK2 -> MCU_CLK (uses a 12MHz crystal by default) + * CLK3 -> External Clock Output (power down at boot) + * CLK4 -> XCVR_CLK (MAX2837) + * CLK5 -> MIX_CLK (RFFC5072) + * CLK6 -> AUX_CLK1 + * CLK7 -> AUX_CLK2 + */ + +#ifdef IS_H1_R9 + if (IS_H1_R9) { + /* MS0/CLK0 is the reference for both RFFC5071 and MAX2839. */ + si5351c_configure_multisynth( + &clock_gen, + 0, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + } +#endif +#ifdef IS_NOT_H1_R9 + if (IS_NOT_H1_R9) { + /* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */ + si5351c_configure_multisynth( + &clock_gen, + 4, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + /* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */ + si5351c_configure_multisynth( + &clock_gen, + 5, + 20 * 128 - 512, + 0, + 1, + 0); /* 800/20 = 40MHz */ + } +#endif + + /* MS6/CLK6 is unused. */ + /* MS7/CLK7 is unused. */ + + /* Set to 10 MHz, the common rate between Jawbreaker and HackRF One. */ + sample_rate_set(SR_FP_MHZ(10), true); + + si5351c_configure_clock_control(&clock_gen); + si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL); + // soft reset + si5351c_reset_pll(&clock_gen, SI5351C_PLL_BOTH); + si5351c_enable_clock_outputs(&clock_gen); +} + +void clock_gen_shutdown(void) +{ + i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); + si5351c_disable_all_outputs(&clock_gen); + si5351c_disable_oeb_pin_control(&clock_gen); + si5351c_power_down_all_clocks(&clock_gen); +} + +clock_source_t activate_best_clock_source(void) +{ +#ifdef IS_EXPANSION_COMPATIBLE + if (IS_EXPANSION_COMPATIBLE) { + /* Ensure PortaPack reference oscillator is off while checking for external clock input. */ + if (portapack_reference_oscillator && portapack()) { + portapack_reference_oscillator(false); + } + } +#endif + + clock_source_t source = CLOCK_SOURCE_HACKRF; + + /* Check for external clock input. */ + if (si5351c_clkin_signal_valid(&clock_gen)) { + source = CLOCK_SOURCE_EXTERNAL; + } else { +#ifdef IS_EXPANSION_COMPATIBLE + if (IS_EXPANSION_COMPATIBLE) { + /* Enable PortaPack reference oscillator (if present), and check for valid clock. */ + if (portapack_reference_oscillator && portapack()) { + portapack_reference_oscillator(true); + delay(510000); /* loop iterations @ 204MHz for >10ms for oscillator to enable. */ + if (si5351c_clkin_signal_valid(&clock_gen)) { + source = CLOCK_SOURCE_PORTAPACK; + } else { + portapack_reference_oscillator(false); + } + } + } +#endif + /* No external or PortaPack clock was found. Use HackRF Si5351C crystal. */ + } + + si5351c_set_clock_source( + &clock_gen, + (source == CLOCK_SOURCE_HACKRF) ? PLL_SOURCE_XTAL : PLL_SOURCE_CLKIN); + hackrf_ui()->set_clock_source(source); + + return source; +} + +/* + * Closest fraction to m/d with denominator <= max_den. + * Returns result in *r / *s with gcd(*r, *s) == 1 and 0 < *s <= max_den. + * Straight port from CPython's fractions, and better documented there. + */ +void limit_denominator( + uint64_t m, + uint64_t d, + const uint64_t max_den, + uint64_t* r, + uint64_t* s) +{ + if (d <= max_den) { + *r = m; + *s = d; + return; + } + + uint64_t p0 = 0, q0 = 1, p1 = 1, q1 = 0; + uint64_t n = m, orig_d = d; + uint64_t tmp; + + while (1) { + uint64_t a = n / d; + uint64_t q2 = q0 + a * q1; + + if (q2 > max_den) + break; + + tmp = p0 + a * p1; + p0 = p1; + q0 = q1; + p1 = tmp; + q1 = q2; + + tmp = n - a * d; + n = d; + d = tmp; + if (d == 0) + break; + } + + uint64_t k = (max_den - q0) / q1; + + /* Return closer candidate. */ + if (2 * d * (q0 + k * q1) <= orig_d) { + *r = p1; + *s = q1; + } else { + *r = p0 + k * p1; + *s = q0 + k * q1; + } +} + +/* + * Configure clock generator to produce sample clock in units of 1/(2**36) Hz. + * Can be called with program=false for a dry run that returns the resultant + * frequency without actually configuring the clock generator. + * + * The clock generator output frequency is: + * + * fs = 128 * vco / (512 + p1 + p2/p3)) + * + * where p1, p2, and p3 are register values. + * + * For more information see: + * https://www.pa3fwm.nl/technotes/tn42a-si5351-programming.html + */ +fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program) +{ + const uint64_t vco_hz = 800 * 1000ULL * 1000ULL; + uint64_t p1, p2, p3; + uint64_t n, d, q1, q2, q3, r1, r2; + fp_28_36_t resultant_rate; + + /* + * First double the sample rate so that we can produce a clock at twice + * the intended sample rate. The 2x clock is sometimes used directly, + * and it is divided by two in an output divider to produce the actual + * AFE clock. + */ + fp_28_36_t rate = sample_rate * 2; + + /* + * Computes p1 = (N << 36) / rate - 512, where N = 128 * vco_hz. + * + * Full numerator (N << 36) is 73 bits, so we split the division: + * + * (N << 36) / rate = ((N << 27) / rate) << 9 + * + (((N << 27) % rate) << 9) / rate + * + * IMPORTANT: Assumes sample rate is in [200e3 << 36, 43.6e6 << 36]. + */ + const uint64_t A = (128 * vco_hz) << 27; + + q1 = A / rate; + r1 = A % rate; + + // Remaining 9 bits with long division. + q2 = 0; + r2 = r1; + for (int j = 0; j < 9; j++) { + uint64_t msb = r2 >> 63; + r2 <<= 1; + q2 <<= 1; + if (msb || r2 >= rate) { + r2 -= rate; + q2 |= 1; + } + } + + p1 = (q1 << 9) + q2 - 512; + + if (r2) { + /* Use the remainder for the fractional part. */ + n = r2; + d = rate; + + /* Reduce fraction. */ + const uint64_t p3_max = 0xfffff; + limit_denominator(n, d, p3_max, &p2, &p3); + + /* Roll over to next p1 to enable integer mode. */ + if (p2 >= p3) { + p1++; + p2 = 0; + } + } else { + p2 = 0; + } + + /* Maximum: (128 * 2048) - 512 */ + if (p1 > 0x3fe00) { + p1 = 0x3fe00; + p2 = 0; + } + + if (p2 == 0) { + /* Use unity denominator for integer mode. */ + p3 = 1; + n = (128 * vco_hz) << 18; + d = (p1 + 512); + q1 = n / d; + r1 = n % d; + q2 = ((r1 << 18) + (d / 2)) / d; + resultant_rate = (q1 << 18) + q2; + } else { + n = p3 * vco_hz * 128; + d = p3 * (p1 + 512) + p2; + q1 = n / d; + r1 = n % d; + q2 = (r1 << 18) / d; + r2 = (r1 << 18) % d; + q3 = ((r2 << 18) + (d / 2)) / d; + resultant_rate = (q1 << 36) + (q2 << 18) + q3; + } + + /* Return MCU sample rate, not AFE clock rate. */ + resultant_rate = (resultant_rate + 1) / 2; + + if (!program) { + return resultant_rate; + } + + bool streaming = sgpio_cpld_stream_is_enabled(&sgpio_config); + + if (streaming) { + sgpio_cpld_stream_disable(&sgpio_config); + } + +#ifdef IS_NOT_PRALINE + if (IS_NOT_PRALINE) { + /* Integer mode can be enabled if p1 is even and p2 is zero. */ + if (p1 & 0x1 || p2) { + si5351c_set_int_mode(&clock_gen, 0, 0); + } else { + si5351c_set_int_mode(&clock_gen, 0, 1); + } + + #ifdef IS_H1_R9 + if (IS_H1_R9) { + /* + * On HackRF One r9 all sample clocks are externally derived + * from MS1/CLK1 operating at twice the sample rate. + */ + si5351c_configure_multisynth(&clock_gen, 1, p1, p2, p3, 0); + } + #endif + #ifdef IS_NOT_H1_R9 + if (IS_NOT_H1_R9) { + /* + * On other platforms the clock generator produces three + * different sample clocks, all derived from multisynth 0. + */ + /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ + si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1); + + /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ + si5351c_configure_multisynth( + &clock_gen, + 1, + 0, + 0, + 0, + 0); //p1 doesn't matter + + /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ + si5351c_configure_multisynth( + &clock_gen, + 2, + 0, + 0, + 0, + 0); //p1 doesn't matter + } + #endif + } +#endif +#ifdef IS_PRALINE + if (IS_PRALINE) { + /* MS0/CLK0 is the source for the MAX5864 (AFE_CLK). */ + si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1); + + /* MS1/CLK1 is the source for the FPGA (FPGA_CLK and SCT_CLK). */ + si5351c_configure_multisynth(&clock_gen, 1, p1, p2, p3, 1); + + /* Delay FPGA_CLK relative to AFE_CLK. */ + uint8_t phase_offset = 0; + if (p1 < 2100) { + phase_offset = (p1 >> 4) - 6; + } + si5351c_set_phase(&clock_gen, 1, phase_offset); + + if ((detected_revision() & ~BOARD_REV_GSG) < BOARD_REV_PRALINE_R1_1) { + /* + * On older boards FPGA_CLK is on CLK2 while SCT_CLK is on + * CLK1. We configure both so that behavior is consistent with + * newer boards that use CLK1 for both FPGA_CLK and SCT_CLK. + */ + si5351c_configure_multisynth(&clock_gen, 2, p1, p2, p3, 1); + si5351c_set_phase(&clock_gen, 2, phase_offset); + } + + /* Reset PLL to synchronize output clock phase. */ + si5351c_reset_pll(&clock_gen, SI5351C_PLL_A); + } +#endif + + if (streaming) { + sgpio_cpld_stream_enable(&sgpio_config); + } + + return resultant_rate; +} + +#ifdef IS_PRALINE +void p1_ctrl_set(const p1_ctrl_signal_t signal) +{ + const platform_gpio_t* gpio = platform_gpio(); + + gpio_write(gpio->p1_ctrl0, signal & 1); + gpio_write(gpio->p1_ctrl1, (signal >> 1) & 1); + gpio_write(gpio->p1_ctrl2, (signal >> 2) & 1); +} + +void p2_ctrl_set(const p2_ctrl_signal_t signal) +{ + const platform_gpio_t* gpio = platform_gpio(); + + gpio_write(gpio->p2_ctrl0, signal & 1); + gpio_write(gpio->p2_ctrl1, (signal >> 1) & 1); +} + +void pps_out_set(const uint8_t value) +{ + gpio_write(platform_gpio()->pps_out, value & 1); +} +#endif diff --git a/firmware/common/clock_gen.h b/firmware/common/clock_gen.h new file mode 100644 index 000000000..48fb6f202 --- /dev/null +++ b/firmware/common/clock_gen.h @@ -0,0 +1,76 @@ +/* + * Copyright 2026 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "platform_detect.h" // IWYU pragma: keep + +#include +#ifdef IS_PRALINE + #include +#endif + +#include "fixed_point.h" + +typedef enum { + CLOCK_SOURCE_HACKRF = 0, + CLOCK_SOURCE_EXTERNAL = 1, + CLOCK_SOURCE_PORTAPACK = 2, +} clock_source_t; + +void clock_gen_init(void); +void clock_gen_shutdown(void); + +clock_source_t activate_best_clock_source(void); + +fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program); + +#ifdef IS_PRALINE +typedef enum { + P1_SIGNAL_TRIGGER_IN = 0, + P1_SIGNAL_AUX_CLK1 = 1, + P1_SIGNAL_CLKIN = 2, + P1_SIGNAL_TRIGGER_OUT = 3, + P1_SIGNAL_P22_CLKIN = 4, + P1_SIGNAL_P2_5 = 5, + P1_SIGNAL_NC = 6, + P1_SIGNAL_AUX_CLK2 = 7, +} p1_ctrl_signal_t; + +typedef enum { + P2_SIGNAL_CLK3 = 0, + P2_SIGNAL_TRIGGER_IN = 2, + P2_SIGNAL_TRIGGER_OUT = 3, +} p2_ctrl_signal_t; + +void p1_ctrl_set(const p1_ctrl_signal_t signal); +void p2_ctrl_set(const p2_ctrl_signal_t signal); + +void pps_out_set(const uint8_t value); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/firmware/common/fpga_selftest.c b/firmware/common/fpga_selftest.c index 270d3ff41..fe0a96f93 100644 --- a/firmware/common/fpga_selftest.c +++ b/firmware/common/fpga_selftest.c @@ -23,6 +23,7 @@ #include #include +#include "clock_gen.h" #include "delay.h" #include "fixed_point.h" #include "fpga.h" diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index e9bc4c2ef..c8b128423 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -27,10 +27,10 @@ #include "platform_detect.h" +#include "clock_gen.h" #include "delay.h" #include "gpio.h" #include "hackrf_core.h" -#include "hackrf_ui.h" #include "i2c_lpc.h" #include "max283x.h" #include "max5864_target.h" @@ -38,9 +38,6 @@ #include "platform_scu.h" #include "spi_bus.h" #include "w25q80bv_target.h" -#ifdef IS_EXPANSION_COMPATIBLE - #include "portapack.h" -#endif #ifdef IS_PRALINE #include "ice40_spi.h" #endif @@ -166,395 +163,6 @@ jtag_t jtag_cpld = { .gpio = &jtag_gpio_cpld, }; -/* - * Closest fraction to m/d with denominator <= max_den. - * Returns result in *r / *s with gcd(*r, *s) == 1 and 0 < *s <= max_den. - * Straight port from CPython's fractions, and better documented there. - */ -void limit_denominator( - uint64_t m, - uint64_t d, - const uint64_t max_den, - uint64_t* r, - uint64_t* s) -{ - if (d <= max_den) { - *r = m; - *s = d; - return; - } - - uint64_t p0 = 0, q0 = 1, p1 = 1, q1 = 0; - uint64_t n = m, orig_d = d; - uint64_t tmp; - - while (1) { - uint64_t a = n / d; - uint64_t q2 = q0 + a * q1; - - if (q2 > max_den) - break; - - tmp = p0 + a * p1; - p0 = p1; - q0 = q1; - p1 = tmp; - q1 = q2; - - tmp = n - a * d; - n = d; - d = tmp; - if (d == 0) - break; - } - - uint64_t k = (max_den - q0) / q1; - - /* Return closer candidate. */ - if (2 * d * (q0 + k * q1) <= orig_d) { - *r = p1; - *s = q1; - } else { - *r = p0 + k * p1; - *s = q0 + k * q1; - } -} - -/* - * Configure clock generator to produce sample clock in units of 1/(2**36) Hz. - * Can be called with program=false for a dry run that returns the resultant - * frequency without actually configuring the clock generator. - * - * The clock generator output frequency is: - * - * fs = 128 * vco / (512 + p1 + p2/p3)) - * - * where p1, p2, and p3 are register values. - * - * For more information see: - * https://www.pa3fwm.nl/technotes/tn42a-si5351-programming.html - */ -fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program) -{ - const uint64_t vco_hz = 800 * 1000ULL * 1000ULL; - uint64_t p1, p2, p3; - uint64_t n, d, q1, q2, q3, r1, r2; - fp_28_36_t resultant_rate; - - /* - * First double the sample rate so that we can produce a clock at twice - * the intended sample rate. The 2x clock is sometimes used directly, - * and it is divided by two in an output divider to produce the actual - * AFE clock. - */ - fp_28_36_t rate = sample_rate * 2; - - /* - * Computes p1 = (N << 36) / rate - 512, where N = 128 * vco_hz. - * - * Full numerator (N << 36) is 73 bits, so we split the division: - * - * (N << 36) / rate = ((N << 27) / rate) << 9 - * + (((N << 27) % rate) << 9) / rate - * - * IMPORTANT: Assumes sample rate is in [200e3 << 36, 43.6e6 << 36]. - */ - const uint64_t A = (128 * vco_hz) << 27; - - q1 = A / rate; - r1 = A % rate; - - // Remaining 9 bits with long division. - q2 = 0; - r2 = r1; - for (int j = 0; j < 9; j++) { - uint64_t msb = r2 >> 63; - r2 <<= 1; - q2 <<= 1; - if (msb || r2 >= rate) { - r2 -= rate; - q2 |= 1; - } - } - - p1 = (q1 << 9) + q2 - 512; - - if (r2) { - /* Use the remainder for the fractional part. */ - n = r2; - d = rate; - - /* Reduce fraction. */ - const uint64_t p3_max = 0xfffff; - limit_denominator(n, d, p3_max, &p2, &p3); - - /* Roll over to next p1 to enable integer mode. */ - if (p2 >= p3) { - p1++; - p2 = 0; - } - } else { - p2 = 0; - } - - /* Maximum: (128 * 2048) - 512 */ - if (p1 > 0x3fe00) { - p1 = 0x3fe00; - p2 = 0; - } - - if (p2 == 0) { - /* Use unity denominator for integer mode. */ - p3 = 1; - n = (128 * vco_hz) << 18; - d = (p1 + 512); - q1 = n / d; - r1 = n % d; - q2 = ((r1 << 18) + (d / 2)) / d; - resultant_rate = (q1 << 18) + q2; - } else { - n = p3 * vco_hz * 128; - d = p3 * (p1 + 512) + p2; - q1 = n / d; - r1 = n % d; - q2 = (r1 << 18) / d; - r2 = (r1 << 18) % d; - q3 = ((r2 << 18) + (d / 2)) / d; - resultant_rate = (q1 << 36) + (q2 << 18) + q3; - } - - /* Return MCU sample rate, not AFE clock rate. */ - resultant_rate = (resultant_rate + 1) / 2; - - if (!program) { - return resultant_rate; - } - - bool streaming = sgpio_cpld_stream_is_enabled(&sgpio_config); - - if (streaming) { - sgpio_cpld_stream_disable(&sgpio_config); - } - -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - /* Integer mode can be enabled if p1 is even and p2 is zero. */ - if (p1 & 0x1 || p2) { - si5351c_set_int_mode(&clock_gen, 0, 0); - } else { - si5351c_set_int_mode(&clock_gen, 0, 1); - } - - #ifdef IS_H1_R9 - if (IS_H1_R9) { - /* - * On HackRF One r9 all sample clocks are externally derived - * from MS1/CLK1 operating at twice the sample rate. - */ - si5351c_configure_multisynth(&clock_gen, 1, p1, p2, p3, 0); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - /* - * On other platforms the clock generator produces three - * different sample clocks, all derived from multisynth 0. - */ - /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ - si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1); - - /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ - si5351c_configure_multisynth( - &clock_gen, - 1, - 0, - 0, - 0, - 0); //p1 doesn't matter - - /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ - si5351c_configure_multisynth( - &clock_gen, - 2, - 0, - 0, - 0, - 0); //p1 doesn't matter - } - #endif - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - /* MS0/CLK0 is the source for the MAX5864 (AFE_CLK). */ - si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1); - - /* MS1/CLK1 is the source for the FPGA (FPGA_CLK and SCT_CLK). */ - si5351c_configure_multisynth(&clock_gen, 1, p1, p2, p3, 1); - - /* Delay FPGA_CLK relative to AFE_CLK. */ - uint8_t phase_offset = 0; - if (p1 < 2100) { - phase_offset = (p1 >> 4) - 6; - } - si5351c_set_phase(&clock_gen, 1, phase_offset); - - if ((detected_revision() & ~BOARD_REV_GSG) < BOARD_REV_PRALINE_R1_1) { - /* - * On older boards FPGA_CLK is on CLK2 while SCT_CLK is on - * CLK1. We configure both so that behavior is consistent with - * newer boards that use CLK1 for both FPGA_CLK and SCT_CLK. - */ - si5351c_configure_multisynth(&clock_gen, 2, p1, p2, p3, 1); - si5351c_set_phase(&clock_gen, 2, phase_offset); - } - - /* Reset PLL to synchronize output clock phase. */ - si5351c_reset_pll(&clock_gen, SI5351C_PLL_A); - } -#endif - - if (streaming) { - sgpio_cpld_stream_enable(&sgpio_config); - } - - return resultant_rate; -} - -void clock_gen_init(void) -{ - i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); - - si5351c_init(&clock_gen); - si5351c_disable_all_outputs(&clock_gen); - si5351c_disable_oeb_pin_control(&clock_gen); - si5351c_power_down_all_clocks(&clock_gen); - si5351c_set_crystal_configuration(&clock_gen); - si5351c_enable_xo_and_ms_fanout(&clock_gen); - - /* - * Clocks on HackRF One r9: - * CLK0 -> MAX5864/CPLD/SGPIO (sample clocks) - * CLK1 -> RFFC5072/MAX2839 - * CLK2 -> External Clock Output/LPC43xx (power down at boot) - * - * Clocks on other platforms: - * CLK0 -> MAX5864/CPLD - * CLK1 -> CPLD - * CLK2 -> SGPIO - * CLK3 -> External Clock Output (power down at boot) - * CLK4 -> RFFC5072 (MAX2837 on rad1o) - * CLK5 -> MAX2837 (MAX2871 on rad1o) - * CLK6 -> none - * CLK7 -> LPC43xx (uses a 12MHz crystal by default) - * - * Clocks on Praline: - * CLK0 -> AFE_CLK (MAX5864/FPGA) - * CLK1 -> SCT_CLK - * CLK2 -> MCU_CLK (uses a 12MHz crystal by default) - * CLK3 -> External Clock Output (power down at boot) - * CLK4 -> XCVR_CLK (MAX2837) - * CLK5 -> MIX_CLK (RFFC5072) - * CLK6 -> AUX_CLK1 - * CLK7 -> AUX_CLK2 - */ - -#ifdef IS_H1_R9 - if (IS_H1_R9) { - /* MS0/CLK0 is the reference for both RFFC5071 and MAX2839. */ - si5351c_configure_multisynth( - &clock_gen, - 0, - 20 * 128 - 512, - 0, - 1, - 0); /* 800/20 = 40MHz */ - } -#endif -#ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - /* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */ - si5351c_configure_multisynth( - &clock_gen, - 4, - 20 * 128 - 512, - 0, - 1, - 0); /* 800/20 = 40MHz */ - /* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */ - si5351c_configure_multisynth( - &clock_gen, - 5, - 20 * 128 - 512, - 0, - 1, - 0); /* 800/20 = 40MHz */ - } -#endif - - /* MS6/CLK6 is unused. */ - /* MS7/CLK7 is unused. */ - - /* Set to 10 MHz, the common rate between Jawbreaker and HackRF One. */ - sample_rate_set(SR_FP_MHZ(10), true); - - si5351c_configure_clock_control(&clock_gen); - si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL); - // soft reset - si5351c_reset_pll(&clock_gen, SI5351C_PLL_BOTH); - si5351c_enable_clock_outputs(&clock_gen); -} - -void clock_gen_shutdown(void) -{ - i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock); - si5351c_disable_all_outputs(&clock_gen); - si5351c_disable_oeb_pin_control(&clock_gen); - si5351c_power_down_all_clocks(&clock_gen); -} - -clock_source_t activate_best_clock_source(void) -{ -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - /* Ensure PortaPack reference oscillator is off while checking for external clock input. */ - if (portapack_reference_oscillator && portapack()) { - portapack_reference_oscillator(false); - } - } -#endif - - clock_source_t source = CLOCK_SOURCE_HACKRF; - - /* Check for external clock input. */ - if (si5351c_clkin_signal_valid(&clock_gen)) { - source = CLOCK_SOURCE_EXTERNAL; - } else { -#ifdef IS_EXPANSION_COMPATIBLE - if (IS_EXPANSION_COMPATIBLE) { - /* Enable PortaPack reference oscillator (if present), and check for valid clock. */ - if (portapack_reference_oscillator && portapack()) { - portapack_reference_oscillator(true); - delay(510000); /* loop iterations @ 204MHz for >10ms for oscillator to enable. */ - if (si5351c_clkin_signal_valid(&clock_gen)) { - source = CLOCK_SOURCE_PORTAPACK; - } else { - portapack_reference_oscillator(false); - } - } - } -#endif - /* No external or PortaPack clock was found. Use HackRF Si5351C crystal. */ - } - - si5351c_set_clock_source( - &clock_gen, - (source == CLOCK_SOURCE_HACKRF) ? PLL_SOURCE_XTAL : PLL_SOURCE_CLKIN); - hackrf_ui()->set_clock_source(source); - - return source; -} - void ssp1_set_mode_max283x(void) { spi_bus_start(&spi_bus_ssp1, &ssp_config_max283x); @@ -1151,33 +759,11 @@ void halt_and_flash(const uint32_t duration) } #ifdef IS_PRALINE -void p1_ctrl_set(const p1_ctrl_signal_t signal) -{ - const platform_gpio_t* gpio = platform_gpio(); - - gpio_write(gpio->p1_ctrl0, signal & 1); - gpio_write(gpio->p1_ctrl1, (signal >> 1) & 1); - gpio_write(gpio->p1_ctrl2, (signal >> 2) & 1); -} - -void p2_ctrl_set(const p2_ctrl_signal_t signal) -{ - const platform_gpio_t* gpio = platform_gpio(); - - gpio_write(gpio->p2_ctrl0, signal & 1); - gpio_write(gpio->p2_ctrl1, (signal >> 1) & 1); -} - void clkin_ctrl_set(const clkin_signal_t signal) { gpio_write(platform_gpio()->clkin_ctrl, signal & 1); } -void pps_out_set(const uint8_t value) -{ - gpio_write(platform_gpio()->pps_out, value & 1); -} - void narrowband_filter_set(const uint8_t value) { gpio_write(platform_gpio()->aa_en, value & 1); diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 334d74a0f..d38ce3872 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -31,7 +31,6 @@ extern "C" { #include #include "cpld_jtag.h" -#include "fixed_point.h" #include "i2c_bus.h" #include "i2c_lpc.h" #include "max283x.h" @@ -69,8 +68,6 @@ extern rf_path_t rf_path; extern jtag_t jtag_cpld; extern i2c_bus_t i2c0; -void clock_gen_init(void); -void clock_gen_shutdown(void); void ssp1_set_mode_max283x(void); void ssp1_set_mode_max5864(void); #ifdef IS_PRALINE @@ -89,10 +86,6 @@ void disable_3v3aux_power(void); void enable_1v8_power(void); void disable_1v8_power(void); -fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program); - -clock_source_t activate_best_clock_source(void); - #if defined(IS_RAD1O) || defined(IS_HACKRF_ONE) || defined(IS_PRALINE) void enable_rf_power(void); void disable_rf_power(void); @@ -115,33 +108,13 @@ void trigger_enable(const bool enable); void halt_and_flash(const uint32_t duration); #ifdef IS_PRALINE -typedef enum { - P1_SIGNAL_TRIGGER_IN = 0, - P1_SIGNAL_AUX_CLK1 = 1, - P1_SIGNAL_CLKIN = 2, - P1_SIGNAL_TRIGGER_OUT = 3, - P1_SIGNAL_P22_CLKIN = 4, - P1_SIGNAL_P2_5 = 5, - P1_SIGNAL_NC = 6, - P1_SIGNAL_AUX_CLK2 = 7, -} p1_ctrl_signal_t; - -typedef enum { - P2_SIGNAL_CLK3 = 0, - P2_SIGNAL_TRIGGER_IN = 2, - P2_SIGNAL_TRIGGER_OUT = 3, -} p2_ctrl_signal_t; - typedef enum { CLKIN_SIGNAL_P1 = 0, CLKIN_SIGNAL_P22 = 1, } clkin_signal_t; -void p1_ctrl_set(const p1_ctrl_signal_t signal); -void p2_ctrl_set(const p2_ctrl_signal_t signal); void narrowband_filter_set(const uint8_t value); void clkin_ctrl_set(const clkin_signal_t value); -void pps_out_set(const uint8_t value); #endif #ifdef __cplusplus diff --git a/firmware/common/hackrf_ui.h b/firmware/common/hackrf_ui.h index 1193d1c5d..7b7d67e46 100644 --- a/firmware/common/hackrf_ui.h +++ b/firmware/common/hackrf_ui.h @@ -25,7 +25,7 @@ #include #include -#include "radio.h" +#include "clock_gen.h" #include "rf_path.h" #include "transceiver_mode.h" diff --git a/firmware/common/radio.h b/firmware/common/radio.h index 83f724417..7ab46c80b 100644 --- a/firmware/common/radio.h +++ b/firmware/common/radio.h @@ -54,13 +54,6 @@ typedef struct { uint32_t hz; } radio_sample_rate_t; -// legacy type, moved from hackrf_core -typedef enum { - CLOCK_SOURCE_HACKRF = 0, - CLOCK_SOURCE_EXTERNAL = 1, - CLOCK_SOURCE_PORTAPACK = 2, -} clock_source_t; - /** * Configurable registers stored as uint64_t. Any register may be set to * RADIO_UNSET. When not RADIO_UNSET, some registers are read as a specific type diff --git a/firmware/common/ui_portapack.c b/firmware/common/ui_portapack.c index 8912777f7..85ffa705c 100644 --- a/firmware/common/ui_portapack.c +++ b/firmware/common/ui_portapack.c @@ -26,8 +26,8 @@ #include #include +#include "clock_gen.h" #include "portapack.h" -#include "radio.h" #include "rf_path.h" #include "transceiver_mode.h" diff --git a/firmware/common/ui_rad1o.c b/firmware/common/ui_rad1o.c index ce894cdf7..878e9e746 100644 --- a/firmware/common/ui_rad1o.c +++ b/firmware/common/ui_rad1o.c @@ -26,10 +26,13 @@ #include #include +#include "clock_gen.h" #include "hackrf_core.h" -#include "radio.h" #include "rf_path.h" #include "transceiver_mode.h" +#ifdef IS_NOT_RAD1O + #include "radio.h" +#endif #include "rad1o/display.h" #include "rad1o/draw.h" diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index a2823405c..0183948fd 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -174,6 +174,7 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/sgpio.c ${PATH_HACKRF_FIRMWARE_COMMON}/rf_path.c ${PATH_HACKRF_FIRMWARE_COMMON}/si5351c.c + ${PATH_HACKRF_FIRMWARE_COMMON}/clock_gen.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864_target.c ${PATH_HACKRF_FIRMWARE_COMMON}/mixer.c diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index dba9a39ed..661d6791d 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include diff --git a/firmware/hackrf_usb/usb_api_board_info.c b/firmware/hackrf_usb/usb_api_board_info.c index 920ad7494..c46346055 100644 --- a/firmware/hackrf_usb/usb_api_board_info.c +++ b/firmware/hackrf_usb/usb_api_board_info.c @@ -26,6 +26,7 @@ #include +#include #include #include #include diff --git a/firmware/hackrf_usb/usb_api_praline.c b/firmware/hackrf_usb/usb_api_praline.c index 2a41b839c..47b594467 100644 --- a/firmware/hackrf_usb/usb_api_praline.c +++ b/firmware/hackrf_usb/usb_api_praline.c @@ -23,6 +23,7 @@ #include "usb_api_praline.h" +#include #include #include #include diff --git a/firmware/hackrf_usb/usb_api_transceiver.c b/firmware/hackrf_usb/usb_api_transceiver.c index be16b1bea..3d3ded454 100644 --- a/firmware/hackrf_usb/usb_api_transceiver.c +++ b/firmware/hackrf_usb/usb_api_transceiver.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include From 92476260edde8dae7a1d9814c3a3acd10141501c Mon Sep 17 00:00:00 2001 From: Antoine van Gelder Date: Tue, 24 Mar 2026 11:00:56 +0200 Subject: [PATCH 3/7] firmware: move power logic to power.h|c --- firmware/blinky/blinky.c | 9 +- firmware/common/hackrf_core.c | 163 +------------------------ firmware/common/hackrf_core.h | 14 --- firmware/common/power.c | 197 +++++++++++++++++++++++++++++++ firmware/common/power.h | 46 ++++++++ firmware/hackrf-common.cmake | 1 + firmware/hackrf_usb/hackrf_usb.c | 1 + 7 files changed, 251 insertions(+), 180 deletions(-) create mode 100644 firmware/common/power.c create mode 100644 firmware/common/power.h diff --git a/firmware/blinky/blinky.c b/firmware/blinky/blinky.c index 6d071c971..e82f4007a 100644 --- a/firmware/blinky/blinky.c +++ b/firmware/blinky/blinky.c @@ -19,9 +19,10 @@ * Boston, MA 02110-1301, USA. */ +#include "delay.h" #include "hackrf_core.h" #include "platform_detect.h" -#include "delay.h" +#include "power.h" int main(void) { @@ -37,18 +38,18 @@ int main(void) #endif /* Blink LED1/2/3 on the board. */ - while (1) + while (1) { led_on(LED1); led_on(LED2); led_on(LED3); delay(2000000); - + led_off(LED1); led_off(LED2); led_off(LED3); - + delay(2000000); } diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index c8b128423..b0b8a5633 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -36,6 +36,7 @@ #include "max5864_target.h" #include "platform_gpio.h" #include "platform_scu.h" +#include "power.h" #include "spi_bus.h" #include "w25q80bv_target.h" #ifdef IS_PRALINE @@ -511,168 +512,6 @@ void pin_setup(void) sgpio_configure_pin_functions(&sgpio_config); } -#ifdef IS_PRALINE -void enable_1v2_power(void) -{ - if (IS_PRALINE) { - gpio_set(platform_gpio()->gpio_1v2_enable); - } -} - -void disable_1v2_power(void) -{ - if (IS_PRALINE) { - gpio_clear(platform_gpio()->gpio_1v2_enable); - } -} - -void enable_3v3aux_power(void) -{ - if (IS_PRALINE) { - gpio_clear(platform_gpio()->gpio_3v3aux_enable_n); - } -} - -void disable_3v3aux_power(void) -{ - if (IS_PRALINE) { - gpio_set(platform_gpio()->gpio_3v3aux_enable_n); - } -} -#endif - -void enable_1v8_power(void) -{ -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - #ifdef IS_H1_R9 - if (IS_H1_R9) { - gpio_set(platform_gpio()->h1r9_1v8_enable); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - gpio_set(platform_gpio()->gpio_1v8_enable); - } - #endif - } -#endif -} - -void disable_1v8_power(void) -{ -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - #ifdef IS_H1_R9 - if (IS_H1_R9) { - gpio_clear(platform_gpio()->h1r9_1v8_enable); - } - #endif - #ifdef IS_NOT_H1_R9 - if (IS_NOT_H1_R9) { - gpio_clear(platform_gpio()->gpio_1v8_enable); - } - #endif - } -#endif -} - -#ifdef IS_HACKRF_ONE -static inline void enable_rf_power_hackrf_one(void) -{ - const platform_gpio_t* gpio = platform_gpio(); - uint32_t i; - - /* many short pulses to avoid one big voltage glitch */ - for (i = 0; i < 1000; i++) { - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - gpio_set(gpio->h1r9_vaa_disable); - gpio_clear(gpio->h1r9_vaa_disable); - } else { - gpio_set(gpio->vaa_disable); - gpio_clear(gpio->vaa_disable); - } - } -} - -static inline void disable_rf_power_hackrf_one(void) -{ - if (detected_platform() == BOARD_ID_HACKRF1_R9) { - gpio_set(platform_gpio()->h1r9_vaa_disable); - } else { - gpio_set(platform_gpio()->vaa_disable); - } -} -#endif - -#ifdef IS_PRALINE -static inline void enable_rf_power_praline(void) -{ - gpio_clear(platform_gpio()->vaa_disable); - - /* Let the voltage stabilize */ - delay(1000000); -} - -static inline void disable_rf_power_praline(void) -{ - gpio_set(platform_gpio()->vaa_disable); -} -#endif - -#ifdef IS_RAD1O -static inline void enable_rf_power_rad1o(void) -{ - gpio_set(platform_gpio()->vaa_enable); - - /* Let the voltage stabilize */ - delay(1000000); -} - -static inline void disable_rf_power_rad1o(void) -{ - gpio_clear(platform_gpio()->vaa_enable); -} -#endif - -void enable_rf_power(void) -{ -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - enable_rf_power_hackrf_one(); - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - enable_rf_power_praline(); - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - enable_rf_power_rad1o(); - } -#endif -} - -void disable_rf_power(void) -{ -#ifdef IS_HACKRF_ONE - if (IS_HACKRF_ONE) { - disable_rf_power_hackrf_one(); - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - disable_rf_power_praline(); - } -#endif -#ifdef IS_RAD1O - if (IS_RAD1O) { - disable_rf_power_rad1o(); - } -#endif -} - void led_on(const led_t led) { #ifdef IS_PRALINE diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index d38ce3872..1d7832364 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -77,20 +77,6 @@ void ssp1_set_mode_ice40(void); void pin_shutdown(void); void pin_setup(void); -#ifdef IS_PRALINE -void enable_1v2_power(void); -void disable_1v2_power(void); -void enable_3v3aux_power(void); -void disable_3v3aux_power(void); -#endif -void enable_1v8_power(void); -void disable_1v8_power(void); - -#if defined(IS_RAD1O) || defined(IS_HACKRF_ONE) || defined(IS_PRALINE) -void enable_rf_power(void); -void disable_rf_power(void); -#endif - typedef enum { LED1 = 0, LED2 = 1, diff --git a/firmware/common/power.c b/firmware/common/power.c new file mode 100644 index 000000000..25424aabd --- /dev/null +++ b/firmware/common/power.c @@ -0,0 +1,197 @@ +/* + * Copyright 2026 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "power.h" + +#if defined(IS_HACKRF_ONE) + #include +#endif +#if defined(IS_HACKRF_ONE) || defined(IS_RAD1O) || defined(IS_JAWBREAKER) + #include "platform_detect.h" +#endif +#if defined(IS_PRALINE) || defined(IS_RAD1O) + #include "delay.h" +#endif + +#include "gpio.h" +#include "platform_gpio.h" + +#ifdef IS_PRALINE +void enable_1v2_power(void) +{ + if (IS_PRALINE) { + gpio_set(platform_gpio()->gpio_1v2_enable); + } +} + +void disable_1v2_power(void) +{ + if (IS_PRALINE) { + gpio_clear(platform_gpio()->gpio_1v2_enable); + } +} + +void enable_3v3aux_power(void) +{ + if (IS_PRALINE) { + gpio_clear(platform_gpio()->gpio_3v3aux_enable_n); + } +} + +void disable_3v3aux_power(void) +{ + if (IS_PRALINE) { + gpio_set(platform_gpio()->gpio_3v3aux_enable_n); + } +} +#endif + +void enable_1v8_power(void) +{ +#ifdef IS_NOT_PRALINE + if (IS_NOT_PRALINE) { + #ifdef IS_H1_R9 + if (IS_H1_R9) { + gpio_set(platform_gpio()->h1r9_1v8_enable); + } + #endif + #ifdef IS_NOT_H1_R9 + if (IS_NOT_H1_R9) { + gpio_set(platform_gpio()->gpio_1v8_enable); + } + #endif + } +#endif +} + +void disable_1v8_power(void) +{ +#ifdef IS_NOT_PRALINE + if (IS_NOT_PRALINE) { + #ifdef IS_H1_R9 + if (IS_H1_R9) { + gpio_clear(platform_gpio()->h1r9_1v8_enable); + } + #endif + #ifdef IS_NOT_H1_R9 + if (IS_NOT_H1_R9) { + gpio_clear(platform_gpio()->gpio_1v8_enable); + } + #endif + } +#endif +} + +#ifdef IS_HACKRF_ONE +static inline void enable_rf_power_hackrf_one(void) +{ + const platform_gpio_t* gpio = platform_gpio(); + uint32_t i; + + /* many short pulses to avoid one big voltage glitch */ + for (i = 0; i < 1000; i++) { + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_set(gpio->h1r9_vaa_disable); + gpio_clear(gpio->h1r9_vaa_disable); + } else { + gpio_set(gpio->vaa_disable); + gpio_clear(gpio->vaa_disable); + } + } +} + +static inline void disable_rf_power_hackrf_one(void) +{ + if (detected_platform() == BOARD_ID_HACKRF1_R9) { + gpio_set(platform_gpio()->h1r9_vaa_disable); + } else { + gpio_set(platform_gpio()->vaa_disable); + } +} +#endif + +#ifdef IS_PRALINE +static inline void enable_rf_power_praline(void) +{ + gpio_clear(platform_gpio()->vaa_disable); + + /* Let the voltage stabilize */ + delay(1000000); +} + +static inline void disable_rf_power_praline(void) +{ + gpio_set(platform_gpio()->vaa_disable); +} +#endif + +#ifdef IS_RAD1O +static inline void enable_rf_power_rad1o(void) +{ + gpio_set(platform_gpio()->vaa_enable); + + /* Let the voltage stabilize */ + delay(1000000); +} + +static inline void disable_rf_power_rad1o(void) +{ + gpio_clear(platform_gpio()->vaa_enable); +} +#endif + +void enable_rf_power(void) +{ +#ifdef IS_HACKRF_ONE + if (IS_HACKRF_ONE) { + enable_rf_power_hackrf_one(); + } +#endif +#ifdef IS_PRALINE + if (IS_PRALINE) { + enable_rf_power_praline(); + } +#endif +#ifdef IS_RAD1O + if (IS_RAD1O) { + enable_rf_power_rad1o(); + } +#endif +} + +void disable_rf_power(void) +{ +#ifdef IS_HACKRF_ONE + if (IS_HACKRF_ONE) { + disable_rf_power_hackrf_one(); + } +#endif +#ifdef IS_PRALINE + if (IS_PRALINE) { + disable_rf_power_praline(); + } +#endif +#ifdef IS_RAD1O + if (IS_RAD1O) { + disable_rf_power_rad1o(); + } +#endif +} diff --git a/firmware/common/power.h b/firmware/common/power.h new file mode 100644 index 000000000..22b2345eb --- /dev/null +++ b/firmware/common/power.h @@ -0,0 +1,46 @@ +/* + * Copyright 2026 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "platform_detect.h" // IWYU pragma: keep + +#ifdef IS_PRALINE +void enable_1v2_power(void); +void disable_1v2_power(void); +void enable_3v3aux_power(void); +void disable_3v3aux_power(void); +#endif +void enable_1v8_power(void); +void disable_1v8_power(void); + +#if defined(IS_RAD1O) || defined(IS_HACKRF_ONE) || defined(IS_PRALINE) +void enable_rf_power(void); +void disable_rf_power(void); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index 0183948fd..1a55400ff 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -168,6 +168,7 @@ endmacro() macro(DeclareTargets) SET(SRC_M4 ${SRC_M4} + ${PATH_HACKRF_FIRMWARE_COMMON}/power.c ${PATH_HACKRF_FIRMWARE_COMMON}/cpu_clock.c ${PATH_HACKRF_FIRMWARE_COMMON}/delay.c ${PATH_HACKRF_FIRMWARE_COMMON}/hackrf_core.c diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 661d6791d..eff692986 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include From 799af35b5fd7f94221e0d37db477bd5b3e0bbc1b Mon Sep 17 00:00:00 2001 From: Antoine van Gelder Date: Tue, 24 Mar 2026 14:03:55 +0200 Subject: [PATCH 4/7] firmware: move led logic to leds.h|c --- firmware/blinky/blinky.c | 1 + firmware/common/hackrf_core.c | 73 +--------------- firmware/common/hackrf_core.h | 18 +--- firmware/common/leds.c | 100 ++++++++++++++++++++++ firmware/common/leds.h | 46 ++++++++++ firmware/common/platform_detect.c | 2 +- firmware/hackrf-common.cmake | 1 + firmware/hackrf_usb/hackrf_usb.c | 1 + firmware/hackrf_usb/usb_api_cpld.c | 1 + firmware/hackrf_usb/usb_api_register.c | 1 + firmware/hackrf_usb/usb_api_transceiver.c | 1 + 11 files changed, 157 insertions(+), 88 deletions(-) create mode 100644 firmware/common/leds.c create mode 100644 firmware/common/leds.h diff --git a/firmware/blinky/blinky.c b/firmware/blinky/blinky.c index e82f4007a..0bf89bf83 100644 --- a/firmware/blinky/blinky.c +++ b/firmware/blinky/blinky.c @@ -21,6 +21,7 @@ #include "delay.h" #include "hackrf_core.h" +#include "leds.h" #include "platform_detect.h" #include "power.h" diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index b0b8a5633..c6429f6d1 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -28,10 +28,10 @@ #include "platform_detect.h" #include "clock_gen.h" -#include "delay.h" #include "gpio.h" #include "hackrf_core.h" #include "i2c_lpc.h" +#include "leds.h" #include "max283x.h" #include "max5864_target.h" #include "platform_gpio.h" @@ -512,62 +512,6 @@ void pin_setup(void) sgpio_configure_pin_functions(&sgpio_config); } -void led_on(const led_t led) -{ -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio_clear(platform_gpio()->led[led]); - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_set(platform_gpio()->led[led]); - } -#endif -} - -void led_off(const led_t led) -{ -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio_set(platform_gpio()->led[led]); - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_clear(platform_gpio()->led[led]); - } -#endif -} - -void led_toggle(const led_t led) -{ - gpio_toggle(platform_gpio()->led[led]); -} - -void set_leds(const uint8_t state) -{ - int num_leds = 3; -#ifdef IS_FOUR_LEDS - if (IS_FOUR_LEDS) { - num_leds = 4; - } -#endif - - for (int i = 0; i < num_leds; i++) { -#ifdef IS_PRALINE - if (IS_PRALINE) { - gpio_write(platform_gpio()->led[i], ((state >> i) & 1) == 0); - } -#endif -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_write(platform_gpio()->led[i], ((state >> i) & 1) == 1); - } -#endif - } -} - void trigger_enable(const bool enable) { #ifdef IS_NOT_PRALINE @@ -582,21 +526,6 @@ void trigger_enable(const bool enable) #endif } -void halt_and_flash(const uint32_t duration) -{ - /* blink LED1, LED2, and LED3 */ - while (1) { - led_on(LED1); - led_on(LED2); - led_on(LED3); - delay(duration); - led_off(LED1); - led_off(LED2); - led_off(LED3); - delay(duration); - } -} - #ifdef IS_PRALINE void clkin_ctrl_set(const clkin_signal_t signal) { diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 1d7832364..7b6e13366 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -28,7 +28,9 @@ extern "C" { #endif #include -#include +#ifdef IS_PRALINE + #include +#endif #include "cpld_jtag.h" #include "i2c_bus.h" @@ -77,22 +79,8 @@ void ssp1_set_mode_ice40(void); void pin_shutdown(void); void pin_setup(void); -typedef enum { - LED1 = 0, - LED2 = 1, - LED3 = 2, - LED4 = 3, -} led_t; - -void led_on(const led_t led); -void led_off(const led_t led); -void led_toggle(const led_t led); -void set_leds(const uint8_t state); - void trigger_enable(const bool enable); -void halt_and_flash(const uint32_t duration); - #ifdef IS_PRALINE typedef enum { CLKIN_SIGNAL_P1 = 0, diff --git a/firmware/common/leds.c b/firmware/common/leds.c new file mode 100644 index 000000000..ab9b56fba --- /dev/null +++ b/firmware/common/leds.c @@ -0,0 +1,100 @@ +/* + * Copyright 2026 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "leds.h" + +#include + +#include "delay.h" +#include "gpio.h" +#include "platform_detect.h" +#include "platform_gpio.h" + +void led_on(const led_t led) +{ +#ifdef IS_PRALINE + if (IS_PRALINE) { + gpio_clear(platform_gpio()->led[led]); + } +#endif +#ifdef IS_NOT_PRALINE + if (IS_NOT_PRALINE) { + gpio_set(platform_gpio()->led[led]); + } +#endif +} + +void led_off(const led_t led) +{ +#ifdef IS_PRALINE + if (IS_PRALINE) { + gpio_set(platform_gpio()->led[led]); + } +#endif +#ifdef IS_NOT_PRALINE + if (IS_NOT_PRALINE) { + gpio_clear(platform_gpio()->led[led]); + } +#endif +} + +void led_toggle(const led_t led) +{ + gpio_toggle(platform_gpio()->led[led]); +} + +void set_leds(const uint8_t state) +{ + int num_leds = 3; +#ifdef IS_FOUR_LEDS + if (IS_FOUR_LEDS) { + num_leds = 4; + } +#endif + + for (int i = 0; i < num_leds; i++) { +#ifdef IS_PRALINE + if (IS_PRALINE) { + gpio_write(platform_gpio()->led[i], ((state >> i) & 1) == 0); + } +#endif +#ifdef IS_NOT_PRALINE + if (IS_NOT_PRALINE) { + gpio_write(platform_gpio()->led[i], ((state >> i) & 1) == 1); + } +#endif + } +} + +void halt_and_flash(const uint32_t duration) +{ + /* blink LED1, LED2, and LED3 */ + while (1) { + led_on(LED1); + led_on(LED2); + led_on(LED3); + delay(duration); + led_off(LED1); + led_off(LED2); + led_off(LED3); + delay(duration); + } +} diff --git a/firmware/common/leds.h b/firmware/common/leds.h new file mode 100644 index 000000000..a552dca64 --- /dev/null +++ b/firmware/common/leds.h @@ -0,0 +1,46 @@ +/* + * Copyright 2026 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef enum { + LED1 = 0, + LED2 = 1, + LED3 = 2, + LED4 = 3, +} led_t; + +void led_on(const led_t led); +void led_off(const led_t led); +void led_toggle(const led_t led); +void set_leds(const uint8_t state); + +void halt_and_flash(const uint32_t duration); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/common/platform_detect.c b/firmware/common/platform_detect.c index b39030358..7c9fb53d9 100644 --- a/firmware/common/platform_detect.c +++ b/firmware/common/platform_detect.c @@ -26,7 +26,7 @@ #include "firmware_info.h" #include "gpio.h" #include "gpio_lpc.h" -#include "hackrf_core.h" +#include "leds.h" #include "platform_detect.h" #include "platform_scu.h" diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index 1a55400ff..92a905f45 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -172,6 +172,7 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/cpu_clock.c ${PATH_HACKRF_FIRMWARE_COMMON}/delay.c ${PATH_HACKRF_FIRMWARE_COMMON}/hackrf_core.c + ${PATH_HACKRF_FIRMWARE_COMMON}/leds.c ${PATH_HACKRF_FIRMWARE_COMMON}/sgpio.c ${PATH_HACKRF_FIRMWARE_COMMON}/rf_path.c ${PATH_HACKRF_FIRMWARE_COMMON}/si5351c.c diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index eff692986..4cd68852d 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/firmware/hackrf_usb/usb_api_cpld.c b/firmware/hackrf_usb/usb_api_cpld.c index 05636a0be..7381601d2 100644 --- a/firmware/hackrf_usb/usb_api_cpld.c +++ b/firmware/hackrf_usb/usb_api_cpld.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/firmware/hackrf_usb/usb_api_register.c b/firmware/hackrf_usb/usb_api_register.c index b9498dab8..632ce0e51 100644 --- a/firmware/hackrf_usb/usb_api_register.c +++ b/firmware/hackrf_usb/usb_api_register.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include diff --git a/firmware/hackrf_usb/usb_api_transceiver.c b/firmware/hackrf_usb/usb_api_transceiver.c index 3d3ded454..153b760bf 100644 --- a/firmware/hackrf_usb/usb_api_transceiver.c +++ b/firmware/hackrf_usb/usb_api_transceiver.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include From 634bd605b92770defb63959a5736682951ec8d05 Mon Sep 17 00:00:00 2001 From: Antoine van Gelder Date: Wed, 25 Mar 2026 14:53:00 +0200 Subject: [PATCH 5/7] firmware: move clkin_ctrl_set to clkin.h|c --- firmware/common/clkin.c | 13 ++++++++++++- firmware/common/clkin.h | 11 +++++++++++ firmware/common/hackrf_core.c | 6 +----- firmware/common/hackrf_core.h | 6 ------ firmware/hackrf_usb/usb_api_praline.c | 1 + 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/firmware/common/clkin.c b/firmware/common/clkin.c index 9f63681c3..f5af17237 100644 --- a/firmware/common/clkin.c +++ b/firmware/common/clkin.c @@ -30,6 +30,10 @@ #include #include "gpdma.h" +#ifdef IS_PRALINE + #include "gpio.h" + #include "platform_gpio.h" +#endif #define CLOCK_CYCLES_1_MS (204000) #define MEASUREMENT_WINDOW_MS (50) @@ -114,4 +118,11 @@ void clkin_detect_init(void) uint32_t clkin_frequency(void) { return TIMER2_CR3 * (1000 / MEASUREMENT_WINDOW_MS); -}; +} + +#ifdef IS_PRALINE +void clkin_ctrl_set(const clkin_signal_t signal) +{ + gpio_write(platform_gpio()->clkin_ctrl, signal & 1); +} +#endif diff --git a/firmware/common/clkin.h b/firmware/common/clkin.h index 2cef67cfc..53379013d 100644 --- a/firmware/common/clkin.h +++ b/firmware/common/clkin.h @@ -23,5 +23,16 @@ #include +#include "platform_detect.h" // IWYU pragma: keep + void clkin_detect_init(void); uint32_t clkin_frequency(void); + +#ifdef IS_PRALINE +typedef enum { + CLKIN_SIGNAL_P1 = 0, + CLKIN_SIGNAL_P22 = 1, +} clkin_signal_t; + +void clkin_ctrl_set(const clkin_signal_t value); +#endif diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index c6429f6d1..29ca38206 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -40,6 +40,7 @@ #include "spi_bus.h" #include "w25q80bv_target.h" #ifdef IS_PRALINE + #include "clkin.h" #include "ice40_spi.h" #endif @@ -527,11 +528,6 @@ void trigger_enable(const bool enable) } #ifdef IS_PRALINE -void clkin_ctrl_set(const clkin_signal_t signal) -{ - gpio_write(platform_gpio()->clkin_ctrl, signal & 1); -} - void narrowband_filter_set(const uint8_t value) { gpio_write(platform_gpio()->aa_en, value & 1); diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 7b6e13366..e02534588 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -82,13 +82,7 @@ void pin_setup(void); void trigger_enable(const bool enable); #ifdef IS_PRALINE -typedef enum { - CLKIN_SIGNAL_P1 = 0, - CLKIN_SIGNAL_P22 = 1, -} clkin_signal_t; - void narrowband_filter_set(const uint8_t value); -void clkin_ctrl_set(const clkin_signal_t value); #endif #ifdef __cplusplus diff --git a/firmware/hackrf_usb/usb_api_praline.c b/firmware/hackrf_usb/usb_api_praline.c index 47b594467..434418a5b 100644 --- a/firmware/hackrf_usb/usb_api_praline.c +++ b/firmware/hackrf_usb/usb_api_praline.c @@ -23,6 +23,7 @@ #include "usb_api_praline.h" +#include #include #include #include From e2741090ad36b9aac6243fa25abad5eed9404ddd Mon Sep 17 00:00:00 2001 From: Antoine van Gelder Date: Fri, 27 Mar 2026 14:46:12 +0200 Subject: [PATCH 6/7] firmware: move narrowband_filter_set to rf_path.h|c --- firmware/common/fpga.h | 2 ++ firmware/common/hackrf_core.c | 7 ------- firmware/common/hackrf_core.h | 7 ------- firmware/common/rf_path.c | 10 ++++++++++ firmware/common/rf_path.h | 4 ++++ firmware/hackrf_usb/usb_api_praline.c | 4 ++-- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/firmware/common/fpga.h b/firmware/common/fpga.h index 4aa54239d..65826b216 100644 --- a/firmware/common/fpga.h +++ b/firmware/common/fpga.h @@ -90,3 +90,5 @@ bool fpga_image_load(struct fpga_loader_t* loader, unsigned int index); bool fpga_spi_selftest(void); bool fpga_sgpio_selftest(void); bool fpga_if_xcvr_selftest(void); + +//void narrowband_filter_set(const uint8_t value); diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 29ca38206..584994422 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -526,10 +526,3 @@ void trigger_enable(const bool enable) } #endif } - -#ifdef IS_PRALINE -void narrowband_filter_set(const uint8_t value) -{ - gpio_write(platform_gpio()->aa_en, value & 1); -} -#endif diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index e02534588..3755ee2ea 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -28,9 +28,6 @@ extern "C" { #endif #include -#ifdef IS_PRALINE - #include -#endif #include "cpld_jtag.h" #include "i2c_bus.h" @@ -81,10 +78,6 @@ void pin_setup(void); void trigger_enable(const bool enable); -#ifdef IS_PRALINE -void narrowband_filter_set(const uint8_t value); -#endif - #ifdef __cplusplus } #endif diff --git a/firmware/common/rf_path.c b/firmware/common/rf_path.c index 6a8e3caf6..6cadea1c7 100644 --- a/firmware/common/rf_path.c +++ b/firmware/common/rf_path.c @@ -32,6 +32,9 @@ #include #include "platform_scu.h" #endif +#ifdef IS_PRALINE + #include "platform_gpio.h" +#endif /* * RF switches on Jawbreaker are controlled by General Purpose Outputs (GPO) on @@ -615,3 +618,10 @@ void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable) switchctrl_set(rf_path, rf_path->switchctrl); } + +#ifdef IS_PRALINE +void narrowband_filter_set(const uint8_t value) +{ + gpio_write(platform_gpio()->aa_en, value & 1); +} +#endif diff --git a/firmware/common/rf_path.h b/firmware/common/rf_path.h index 42dd91cbd..12f83b535 100644 --- a/firmware/common/rf_path.h +++ b/firmware/common/rf_path.h @@ -102,3 +102,7 @@ void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable); void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable); + +#ifdef IS_PRALINE +void narrowband_filter_set(const uint8_t value); +#endif diff --git a/firmware/hackrf_usb/usb_api_praline.c b/firmware/hackrf_usb/usb_api_praline.c index 434418a5b..262e66dff 100644 --- a/firmware/hackrf_usb/usb_api_praline.c +++ b/firmware/hackrf_usb/usb_api_praline.c @@ -25,12 +25,12 @@ #include #include -#include #include +#include #include #include #include -#if !(defined(DFU_MODE) || defined(RAM_MODE)) +#if !defined(DFU_MODE) && !defined(RAM_MODE) #include #endif From 5672be9d00a67a5ad8c2488580325d686b8365ef Mon Sep 17 00:00:00 2001 From: Antoine van Gelder Date: Tue, 31 Mar 2026 11:25:14 +0200 Subject: [PATCH 7/7] firmware: move clock-associated gpio functions to clkin.x and rename to clock_io.h|c --- firmware/common/clock_gen.c | 28 --------------- firmware/common/clock_gen.h | 27 --------------- firmware/common/{clkin.c => clock_io.c} | 45 +++++++++++++++++++++++-- firmware/common/{clkin.h => clock_io.h} | 26 +++++++++++++- firmware/common/hackrf_core.c | 18 ++-------- firmware/common/hackrf_core.h | 4 --- firmware/common/radio.c | 1 + firmware/common/sgpio.c | 2 +- firmware/common/si5351c.c | 2 +- firmware/hackrf-common.cmake | 2 +- firmware/hackrf_usb/hackrf_usb.c | 2 +- firmware/hackrf_usb/usb_api_praline.c | 3 +- 12 files changed, 76 insertions(+), 84 deletions(-) rename firmware/common/{clkin.c => clock_io.c} (81%) rename firmware/common/{clkin.h => clock_io.h} (64%) diff --git a/firmware/common/clock_gen.c b/firmware/common/clock_gen.c index e29e5a916..3080c4365 100644 --- a/firmware/common/clock_gen.c +++ b/firmware/common/clock_gen.c @@ -33,10 +33,6 @@ #include "delay.h" #include "portapack.h" #endif -#if defined(IS_PRALINE) - #include "gpio.h" - #include "platform_gpio.h" -#endif void clock_gen_init(void) { @@ -426,27 +422,3 @@ fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program) return resultant_rate; } - -#ifdef IS_PRALINE -void p1_ctrl_set(const p1_ctrl_signal_t signal) -{ - const platform_gpio_t* gpio = platform_gpio(); - - gpio_write(gpio->p1_ctrl0, signal & 1); - gpio_write(gpio->p1_ctrl1, (signal >> 1) & 1); - gpio_write(gpio->p1_ctrl2, (signal >> 2) & 1); -} - -void p2_ctrl_set(const p2_ctrl_signal_t signal) -{ - const platform_gpio_t* gpio = platform_gpio(); - - gpio_write(gpio->p2_ctrl0, signal & 1); - gpio_write(gpio->p2_ctrl1, (signal >> 1) & 1); -} - -void pps_out_set(const uint8_t value) -{ - gpio_write(platform_gpio()->pps_out, value & 1); -} -#endif diff --git a/firmware/common/clock_gen.h b/firmware/common/clock_gen.h index 48fb6f202..0bc6439b0 100644 --- a/firmware/common/clock_gen.h +++ b/firmware/common/clock_gen.h @@ -28,9 +28,6 @@ extern "C" { #include "platform_detect.h" // IWYU pragma: keep #include -#ifdef IS_PRALINE - #include -#endif #include "fixed_point.h" @@ -47,30 +44,6 @@ clock_source_t activate_best_clock_source(void); fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program); -#ifdef IS_PRALINE -typedef enum { - P1_SIGNAL_TRIGGER_IN = 0, - P1_SIGNAL_AUX_CLK1 = 1, - P1_SIGNAL_CLKIN = 2, - P1_SIGNAL_TRIGGER_OUT = 3, - P1_SIGNAL_P22_CLKIN = 4, - P1_SIGNAL_P2_5 = 5, - P1_SIGNAL_NC = 6, - P1_SIGNAL_AUX_CLK2 = 7, -} p1_ctrl_signal_t; - -typedef enum { - P2_SIGNAL_CLK3 = 0, - P2_SIGNAL_TRIGGER_IN = 2, - P2_SIGNAL_TRIGGER_OUT = 3, -} p2_ctrl_signal_t; - -void p1_ctrl_set(const p1_ctrl_signal_t signal); -void p2_ctrl_set(const p2_ctrl_signal_t signal); - -void pps_out_set(const uint8_t value); -#endif - #ifdef __cplusplus } #endif diff --git a/firmware/common/clkin.c b/firmware/common/clock_io.c similarity index 81% rename from firmware/common/clkin.c rename to firmware/common/clock_io.c index f5af17237..0a8b48d9b 100644 --- a/firmware/common/clkin.c +++ b/firmware/common/clock_io.c @@ -1,5 +1,5 @@ /* - * Copyright 2022 Great Scott Gadgets + * Copyright 2022-2026 Great Scott Gadgets * * This file is part of HackRF. * @@ -19,8 +19,9 @@ * Boston, MA 02110-1301, USA. */ -#include "clkin.h" +#include "clock_io.h" +#include #include #include @@ -30,8 +31,10 @@ #include #include "gpdma.h" +#include "gpio.h" +#include "hackrf_core.h" #ifdef IS_PRALINE - #include "gpio.h" + #include "fpga.h" #include "platform_gpio.h" #endif @@ -120,9 +123,45 @@ uint32_t clkin_frequency(void) return TIMER2_CR3 * (1000 / MEASUREMENT_WINDOW_MS); } +void trigger_enable(const bool enable) +{ +#ifdef IS_NOT_PRALINE + if (IS_NOT_PRALINE) { + gpio_write(sgpio_config.gpio_trigger_enable, enable); + } +#endif +#ifdef IS_PRALINE + if (IS_PRALINE) { + fpga_set_trigger_enable(&fpga, enable); + } +#endif +} + #ifdef IS_PRALINE void clkin_ctrl_set(const clkin_signal_t signal) { gpio_write(platform_gpio()->clkin_ctrl, signal & 1); } + +void p1_ctrl_set(const p1_ctrl_signal_t signal) +{ + const platform_gpio_t* gpio = platform_gpio(); + + gpio_write(gpio->p1_ctrl0, signal & 1); + gpio_write(gpio->p1_ctrl1, (signal >> 1) & 1); + gpio_write(gpio->p1_ctrl2, (signal >> 2) & 1); +} + +void p2_ctrl_set(const p2_ctrl_signal_t signal) +{ + const platform_gpio_t* gpio = platform_gpio(); + + gpio_write(gpio->p2_ctrl0, signal & 1); + gpio_write(gpio->p2_ctrl1, (signal >> 1) & 1); +} + +void pps_out_set(const uint8_t value) +{ + gpio_write(platform_gpio()->pps_out, value & 1); +} #endif diff --git a/firmware/common/clkin.h b/firmware/common/clock_io.h similarity index 64% rename from firmware/common/clkin.h rename to firmware/common/clock_io.h index 53379013d..df540022e 100644 --- a/firmware/common/clkin.h +++ b/firmware/common/clock_io.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 Great Scott Gadgets + * Copyright 2022-2026 Great Scott Gadgets * * This file is part of HackRF. * @@ -21,6 +21,7 @@ #pragma once +#include #include #include "platform_detect.h" // IWYU pragma: keep @@ -28,11 +29,34 @@ void clkin_detect_init(void); uint32_t clkin_frequency(void); +void trigger_enable(const bool enable); + #ifdef IS_PRALINE typedef enum { CLKIN_SIGNAL_P1 = 0, CLKIN_SIGNAL_P22 = 1, } clkin_signal_t; +typedef enum { + P1_SIGNAL_TRIGGER_IN = 0, + P1_SIGNAL_AUX_CLK1 = 1, + P1_SIGNAL_CLKIN = 2, + P1_SIGNAL_TRIGGER_OUT = 3, + P1_SIGNAL_P22_CLKIN = 4, + P1_SIGNAL_P2_5 = 5, + P1_SIGNAL_NC = 6, + P1_SIGNAL_AUX_CLK2 = 7, +} p1_ctrl_signal_t; + +typedef enum { + P2_SIGNAL_CLK3 = 0, + P2_SIGNAL_TRIGGER_IN = 2, + P2_SIGNAL_TRIGGER_OUT = 3, +} p2_ctrl_signal_t; + void clkin_ctrl_set(const clkin_signal_t value); +void p1_ctrl_set(const p1_ctrl_signal_t signal); +void p2_ctrl_set(const p2_ctrl_signal_t signal); + +void pps_out_set(const uint8_t value); #endif diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 584994422..086e3961d 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -21,6 +21,8 @@ * Boston, MA 02110-1301, USA. */ +#include + #include #include #include @@ -40,7 +42,7 @@ #include "spi_bus.h" #include "w25q80bv_target.h" #ifdef IS_PRALINE - #include "clkin.h" + #include "clock_io.h" #include "ice40_spi.h" #endif @@ -512,17 +514,3 @@ void pin_setup(void) sgpio_configure_pin_functions(&sgpio_config); } - -void trigger_enable(const bool enable) -{ -#ifdef IS_NOT_PRALINE - if (IS_NOT_PRALINE) { - gpio_write(sgpio_config.gpio_trigger_enable, enable); - } -#endif -#ifdef IS_PRALINE - if (IS_PRALINE) { - fpga_set_trigger_enable(&fpga, enable); - } -#endif -} diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 3755ee2ea..6e0c1cc0a 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -27,8 +27,6 @@ extern "C" { #endif -#include - #include "cpld_jtag.h" #include "i2c_bus.h" #include "i2c_lpc.h" @@ -76,8 +74,6 @@ void ssp1_set_mode_ice40(void); void pin_shutdown(void); void pin_setup(void); -void trigger_enable(const bool enable); - #ifdef __cplusplus } #endif diff --git a/firmware/common/radio.c b/firmware/common/radio.c index 760351ace..7191f1ffb 100644 --- a/firmware/common/radio.c +++ b/firmware/common/radio.c @@ -25,6 +25,7 @@ #include +#include "clock_io.h" #include "fixed_point.h" #include "hackrf_core.h" #include "mixer.h" diff --git a/firmware/common/sgpio.c b/firmware/common/sgpio.c index 9d03924aa..568f1208b 100644 --- a/firmware/common/sgpio.c +++ b/firmware/common/sgpio.c @@ -32,7 +32,7 @@ #include "platform_scu.h" #include "sgpio.h" #ifdef IS_NOT_PRALINE - #include "hackrf_core.h" + #include "clock_io.h" #endif static void update_q_invert(sgpio_config_t* const config); diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 0acff63e4..c97674054 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -23,7 +23,7 @@ #include #include -#include "clkin.h" +#include "clock_io.h" #include "delay.h" #include "platform_detect.h" #include "selftest.h" diff --git a/firmware/hackrf-common.cmake b/firmware/hackrf-common.cmake index 92a905f45..6384acdc0 100644 --- a/firmware/hackrf-common.cmake +++ b/firmware/hackrf-common.cmake @@ -192,7 +192,7 @@ macro(DeclareTargets) ${PATH_HACKRF_FIRMWARE_COMMON}/platform_gpio.c ${PATH_HACKRF_FIRMWARE_COMMON}/platform_scu.c ${PATH_HACKRF_FIRMWARE_COMMON}/firmware_info.c - ${PATH_HACKRF_FIRMWARE_COMMON}/clkin.c + ${PATH_HACKRF_FIRMWARE_COMMON}/clock_io.c ${PATH_HACKRF_FIRMWARE_COMMON}/gpdma.c ${PATH_HACKRF_FIRMWARE_COMMON}/radio.c ${PATH_HACKRF_FIRMWARE_COMMON}/selftest.c diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index 4cd68852d..bd2c59649 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -28,8 +28,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/firmware/hackrf_usb/usb_api_praline.c b/firmware/hackrf_usb/usb_api_praline.c index 262e66dff..d889f5dac 100644 --- a/firmware/hackrf_usb/usb_api_praline.c +++ b/firmware/hackrf_usb/usb_api_praline.c @@ -23,8 +23,7 @@ #include "usb_api_praline.h" -#include -#include +#include #include #include #include