diff --git a/firmware/common/portapack.c b/firmware/common/portapack.c index b84bf03c..41f6c79f 100644 --- a/firmware/common/portapack.c +++ b/firmware/common/portapack.c @@ -50,30 +50,35 @@ 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) +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; 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 +120,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 +144,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 +158,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 +173,45 @@ static void portapack_io_write(const bool address, const uint_fast16_t value) portapack_io_stb_deassert(); } -static void portapack_if_init(void) +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(); const platform_scu_t* scu = platform_scu(); @@ -214,13 +257,19 @@ 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_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, const size_t data_count) @@ -231,7 +280,17 @@ static void portapack_lcd_data_write_command_and_data( } } -static void portapack_lcd_sleep_out(void) +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[] = {}; portapack_lcd_data_write_command_and_data(0x11, cmd_11, ARRAY_SIZEOF(cmd_11)); @@ -241,12 +300,18 @@ 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)); } +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[] = {}; @@ -301,7 +366,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 +376,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..b83aa5e0 100644 --- a/firmware/common/portapack.h +++ b/firmware/common/portapack.h @@ -65,6 +65,49 @@ typedef struct { 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); + +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); + +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); + +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_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); 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