From 42b7f7703dba64b34f921ec58448a06652c22fec Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Fri, 12 Jun 2026 16:00:48 +0100 Subject: [PATCH 1/6] Fix management of CLKOUT/MCU_CLK synth sharing on H1R9. --- firmware/common/si5351c.c | 47 +++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index 259c062a..a455a23e 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -274,17 +274,6 @@ void si5351c_enable_clock_outputs(si5351c_driver_t* const drv) SI5351C_OUTPUT_DISABLE); } si5351c_regs_commit(drv); - -#ifdef IS_H1_R9 - if (IS_H1_R9) { - const platform_gpio_t* gpio = platform_gpio(); - if (drv->clk[drv->clkout_id].output_enable) { - gpio_set(gpio->h1r9_clkout_en); - } else { - gpio_clear(gpio->h1r9_clkout_en); - } - } -#endif } void si5351c_set_int_mode( @@ -339,7 +328,7 @@ bool si5351c_clkin_signal_valid(si5351c_driver_t* const drv) } } -void si5351c_clkout_enable(si5351c_driver_t* const drv, bool enable) +static void si5351c_clkout_ms_enable(si5351c_driver_t* const drv, bool enable) { drv->clk[drv->clkout_id].output_enable = enable; drv->clk[drv->clkout_id].power_down = !enable; @@ -351,12 +340,42 @@ void si5351c_clkout_enable(si5351c_driver_t* const drv, bool enable) si5351c_enable_clock_outputs(drv); } +void si5351c_clkout_enable(si5351c_driver_t* const drv, bool enable) +{ +#ifdef IS_H1_R9 + if (IS_H1_R9) { + const platform_gpio_t* gpio = platform_gpio(); + + /* CLKOUT is shared with MCU_CLK, enable MS when either on. */ + bool mcu_clkin_enabled = gpio_read(gpio->h1r9_mcu_clk_en); + bool ms_needed = enable | mcu_clkin_enabled; + si5351c_clkout_ms_enable(drv, ms_needed); + + /* Set GPIO to gate CLKOUT output downstream of MS. */ + gpio_write(gpio->h1r9_clkout_en, enable); + } +#endif +#ifdef IS_NOT_H1_R9 + if (IS_NOT_H1_R9) { + /* We have a dedicated CLKOUT multisynth. */ + si5351c_clkout_ms_enable(drv, enable); + } +#endif +} + void si5351c_mcu_clkin_enable(si5351c_driver_t* const drv, bool enable) { #ifdef IS_H1_R9 if (IS_H1_R9) { - /* MCU clock is shared with CLKOUT. */ - si5351c_clkout_enable(drv, enable); + const platform_gpio_t* gpio = platform_gpio(); + + /* MCU_CLK is shared with CLKOUT, enable MS when either on. */ + bool clkout_enabled = gpio_read(gpio->h1r9_clkout_en); + bool ms_needed = enable | clkout_enabled; + si5351c_clkout_ms_enable(drv, ms_needed); + + /* Set GPIO to gate MCU_CLK output downstream of MS. */ + gpio_write(gpio->h1r9_mcu_clk_en, enable); } #endif #ifdef IS_NOT_H1_R9 From 0ce3d25edec50d5413aa9c197a7a0e0282b8e5f6 Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Thu, 28 May 2026 15:54:22 +0100 Subject: [PATCH 2/6] portapack: Expose more internal functions. --- firmware/common/portapack.c | 32 ++++++++++++++++---------------- firmware/common/portapack.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/firmware/common/portapack.c b/firmware/common/portapack.c index b84bf03c..8046b6cb 100644 --- a/firmware/common/portapack.c +++ b/firmware/common/portapack.c @@ -50,30 +50,30 @@ static portapack_if_t portapack_if = { #define GPIO_DATA_SHIFT (8) static const uint32_t gpio_data_mask = 0xFFU << GPIO_DATA_SHIFT; -static void portapack_data_mask_set(void) +void portapack_data_mask_set(void) { portapack_if.gpio_port_data->mask = ~gpio_data_mask; } -static void portapack_data_write_low(const uint32_t value) +void portapack_data_write_low(const uint32_t value) { portapack_if.gpio_port_data->mpin = (value << GPIO_DATA_SHIFT); } -static void portapack_data_write_high(const uint32_t value) +void portapack_data_write_high(const uint32_t value) { /* NOTE: Assumes no other bits in the port are masked. */ /* NOTE: Assumes that bits 15 through 8 are masked. */ portapack_if.gpio_port_data->mpin = value; } -static void portapack_dir_read(void) +void portapack_dir_read(void) { portapack_if.gpio_port_data->dir &= ~gpio_data_mask; gpio_set(portapack_if.gpio_dir); } -static void portapack_dir_write(void) +void portapack_dir_write(void) { gpio_clear(portapack_if.gpio_dir); portapack_if.gpio_port_data->dir |= gpio_data_mask; @@ -115,12 +115,12 @@ static void portapack_io_stb_deassert(void) gpio_set(portapack_if.gpio_io_stbx); } -static void portapack_addr(const bool value) +void portapack_addr(const bool value) { gpio_write(portapack_if.gpio_addr, value); } -static void portapack_lcd_command(const uint32_t value) +void portapack_lcd_command(const uint32_t value) { portapack_data_write_high(0); /* Drive high byte (with zero -- don't care) */ portapack_dir_write(); /* Turn around data bus, MCU->CPLD */ @@ -139,7 +139,7 @@ static void portapack_lcd_command(const uint32_t value) portapack_addr(1); /* Set up for data phase (most likely after a command) */ } -static void portapack_lcd_write_data(const uint32_t value) +void portapack_lcd_write_data(const uint32_t value) { // NOTE: Assumes and DIR=0 and ADDR=1 from command phase. portapack_data_write_high(value); /* Drive high byte */ @@ -153,7 +153,7 @@ static void portapack_lcd_write_data(const uint32_t value) portapack_lcd_wr_deassert(); /* Complete write operation */ } -static void portapack_io_write(const bool address, const uint_fast16_t value) +void portapack_io_write(const bool address, const uint_fast16_t value) { portapack_data_write_low(value); portapack_dir_write(); @@ -168,7 +168,7 @@ static void portapack_io_write(const bool address, const uint_fast16_t value) portapack_io_stb_deassert(); } -static void portapack_if_init(void) +void portapack_if_init(void) { const platform_gpio_t* gpio = platform_gpio(); const platform_scu_t* scu = platform_scu(); @@ -214,13 +214,13 @@ static void portapack_if_init(void) /* scu_pinmux(scu->PINMUX_PP_UNUSED, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */ } -static void portapack_lcd_reset_state(const bool active) +void portapack_lcd_reset_state(const bool active) { portapack_if.io_reg = (portapack_if.io_reg & 0xfe) | (active ? (1 << 0) : 0); portapack_io_write(1, portapack_if.io_reg); } -static void portapack_lcd_data_write_command_and_data( +void portapack_lcd_data_write_command_and_data( const uint_fast8_t command, const uint8_t* data, const size_t data_count) @@ -231,7 +231,7 @@ static void portapack_lcd_data_write_command_and_data( } } -static void portapack_lcd_sleep_out(void) +void portapack_lcd_sleep_out(void) { const uint8_t cmd_11[] = {}; portapack_lcd_data_write_command_and_data(0x11, cmd_11, ARRAY_SIZEOF(cmd_11)); @@ -241,7 +241,7 @@ static void portapack_lcd_sleep_out(void) delay_ms(120); } -static void portapack_lcd_display_on(void) +void portapack_lcd_display_on(void) { const uint8_t cmd_29[] = {}; portapack_lcd_data_write_command_and_data(0x29, cmd_29, ARRAY_SIZEOF(cmd_29)); @@ -301,7 +301,7 @@ static void portapack_lcd_wake(void) portapack_lcd_display_on(); } -static void portapack_lcd_reset(void) +void portapack_lcd_reset(void) { portapack_lcd_reset_state(false); delay_ms(1); @@ -311,7 +311,7 @@ static void portapack_lcd_reset(void) delay_ms(120); } -static void portapack_lcd_init(void) +void portapack_lcd_init(void) { // LCDs are configured for IM[2:0] = 001 // 8080-I system, 16-bit parallel bus diff --git a/firmware/common/portapack.h b/firmware/common/portapack.h index 3926bc3f..d010149f 100644 --- a/firmware/common/portapack.h +++ b/firmware/common/portapack.h @@ -65,6 +65,41 @@ typedef struct { bool portapack_init(void); +void portapack_if_init(void); + +void portapack_lcd_reset_state(const bool active); + +void portapack_lcd_reset(void); + +void portapack_lcd_init(void); + +void portapack_addr(const bool value); + +void portapack_dir_read(void); + +void portapack_dir_write(void); + +void portapack_data_mask_set(void); + +void portapack_data_write_high(const uint32_t value); + +void portapack_data_write_low(const uint32_t value); + +void portapack_io_write(const bool address, const uint_fast16_t value); + +void portapack_lcd_command(const uint32_t value); + +void portapack_lcd_write_data(const uint32_t value); + +void portapack_lcd_data_write_command_and_data( + const uint_fast8_t command, + const uint8_t* data, + const size_t data_count); + +void portapack_lcd_sleep_out(void); + +void portapack_lcd_display_on(void); + bool portapack_present(void); void portapack_backlight(const bool on); From fbb6651567b393874ded1ae028ff56908202eaf8 Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Tue, 9 Jun 2026 13:20:27 +0100 Subject: [PATCH 3/6] Add portapack_audio_reset_state(). --- firmware/common/portapack.c | 6 ++++++ firmware/common/portapack.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/firmware/common/portapack.c b/firmware/common/portapack.c index 8046b6cb..e8836104 100644 --- a/firmware/common/portapack.c +++ b/firmware/common/portapack.c @@ -220,6 +220,12 @@ void portapack_lcd_reset_state(const bool active) portapack_io_write(1, portapack_if.io_reg); } +void portapack_audio_reset_state(const bool active) +{ + portapack_if.io_reg = (portapack_if.io_reg & 0xfd) | (active ? (1 << 0) : 0); + portapack_io_write(1, portapack_if.io_reg); +} + void portapack_lcd_data_write_command_and_data( const uint_fast8_t command, const uint8_t* data, diff --git a/firmware/common/portapack.h b/firmware/common/portapack.h index d010149f..c5d662c1 100644 --- a/firmware/common/portapack.h +++ b/firmware/common/portapack.h @@ -67,6 +67,8 @@ bool portapack_init(void); void portapack_if_init(void); +void portapack_audio_reset_state(const bool active); + void portapack_lcd_reset_state(const bool active); void portapack_lcd_reset(void); From c2ff760ead700ef4e1c334d4c7db02d5f5f51550 Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Tue, 9 Jun 2026 13:33:55 +0100 Subject: [PATCH 4/6] Add portapack_lcd_sleep_in(). --- firmware/common/portapack.c | 10 ++++++++++ firmware/common/portapack.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/firmware/common/portapack.c b/firmware/common/portapack.c index e8836104..35cd7b24 100644 --- a/firmware/common/portapack.c +++ b/firmware/common/portapack.c @@ -237,6 +237,16 @@ void portapack_lcd_data_write_command_and_data( } } +void portapack_lcd_sleep_in(void) +{ + const uint8_t cmd_10[] = {}; + portapack_lcd_data_write_command_and_data(0x10, cmd_10, ARRAY_SIZEOF(cmd_10)); + // "It will be necessary to wait 5msec before sending next command, + // this is to allow time for the supply voltages and clock circuits + // to stabilize." + delay_ms(5); +} + void portapack_lcd_sleep_out(void) { const uint8_t cmd_11[] = {}; diff --git a/firmware/common/portapack.h b/firmware/common/portapack.h index c5d662c1..14f8dc79 100644 --- a/firmware/common/portapack.h +++ b/firmware/common/portapack.h @@ -100,6 +100,8 @@ void portapack_lcd_data_write_command_and_data( void portapack_lcd_sleep_out(void); +void portapack_lcd_sleep_in(void); + void portapack_lcd_display_on(void); bool portapack_present(void); From 202a97b6a84097392eddae8af41522b481ca12f5 Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Tue, 9 Jun 2026 13:54:13 +0100 Subject: [PATCH 5/6] Add portapack_lcd_display_off(). --- firmware/common/portapack.c | 6 ++++++ firmware/common/portapack.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/firmware/common/portapack.c b/firmware/common/portapack.c index 35cd7b24..1a4d7c55 100644 --- a/firmware/common/portapack.c +++ b/firmware/common/portapack.c @@ -263,6 +263,12 @@ void portapack_lcd_display_on(void) portapack_lcd_data_write_command_and_data(0x29, cmd_29, ARRAY_SIZEOF(cmd_29)); } +void portapack_lcd_display_off(void) +{ + const uint8_t cmd_28[] = {}; + portapack_lcd_data_write_command_and_data(0x28, cmd_28, ARRAY_SIZEOF(cmd_28)); +} + static void portapack_lcd_ramwr_start(void) { const uint8_t cmd_2c[] = {}; diff --git a/firmware/common/portapack.h b/firmware/common/portapack.h index 14f8dc79..d5c2a48f 100644 --- a/firmware/common/portapack.h +++ b/firmware/common/portapack.h @@ -104,6 +104,8 @@ void portapack_lcd_sleep_in(void); void portapack_lcd_display_on(void); +void portapack_lcd_display_off(void); + bool portapack_present(void); void portapack_backlight(const bool on); From b1dbb4731f06e6eae32cee7f4a36ba5863879d9d Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Thu, 11 Jun 2026 16:21:39 +0100 Subject: [PATCH 6/6] Add portapack_io_update(). --- firmware/common/portapack.c | 43 +++++++++++++++++++++++++++++++++++++ firmware/common/portapack.h | 2 ++ 2 files changed, 45 insertions(+) diff --git a/firmware/common/portapack.c b/firmware/common/portapack.c index 1a4d7c55..41f6c79f 100644 --- a/firmware/common/portapack.c +++ b/firmware/common/portapack.c @@ -67,6 +67,11 @@ void portapack_data_write_high(const uint32_t value) portapack_if.gpio_port_data->mpin = value; } +uint8_t portapack_data_read(void) +{ + return portapack_if.gpio_port_data->mpin >> GPIO_DATA_SHIFT; +} + void portapack_dir_read(void) { portapack_if.gpio_port_data->dir &= ~gpio_data_mask; @@ -168,6 +173,44 @@ void portapack_io_write(const bool address, const uint_fast16_t value) portapack_io_stb_deassert(); } +uint16_t portapack_io_update(const uint8_t value) +{ + /* Very touchy code to save context of PortaPack data bus while the + * resistive touch pin drive is changed. Order of operations is + * important to prevent latching spurious data into the LCD or IO + * registers. + */ + uint8_t save_data = portapack_data_read(); + bool addr = gpio_read(portapack_if.gpio_addr); + bool dir = gpio_read(portapack_if.gpio_dir); + + portapack_io_stb_assert(); + + /* Switch to read */ + portapack_dir_read(); + portapack_addr(0); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + uint8_t new_data = portapack_data_read(); + + /* Switch to write */ + portapack_data_write_low(value); + portapack_dir_write(); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + portapack_io_stb_deassert(); + + portapack_data_write_low(save_data); + if (dir) { /* 0 (write) -> 1 (read) */ + portapack_dir_read(); + } + gpio_write(portapack_if.gpio_addr, addr); + + return new_data; +} + void portapack_if_init(void) { const platform_gpio_t* gpio = platform_gpio(); diff --git a/firmware/common/portapack.h b/firmware/common/portapack.h index d5c2a48f..b83aa5e0 100644 --- a/firmware/common/portapack.h +++ b/firmware/common/portapack.h @@ -89,6 +89,8 @@ void portapack_data_write_low(const uint32_t value); void portapack_io_write(const bool address, const uint_fast16_t value); +uint16_t portapack_io_update(const uint8_t value); + void portapack_lcd_command(const uint32_t value); void portapack_lcd_write_data(const uint32_t value);