diff --git a/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.dll b/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.dll index a1f002e..b3b1e4e 100644 Binary files a/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.dll and b/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.dll differ diff --git a/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.exe b/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.exe index 4378fff..492042b 100644 Binary files a/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.exe and b/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.exe differ diff --git a/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.pdb b/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.pdb index 993ba16..7cafda8 100644 Binary files a/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.pdb and b/host/Ausiomixer.Host/bin/Release/net8.0/Ausiomixer.Host.pdb differ diff --git a/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.AssemblyInfo.cs b/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.AssemblyInfo.cs index f4e04f2..9d8625d 100644 --- a/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.AssemblyInfo.cs +++ b/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.AssemblyInfo.cs @@ -13,7 +13,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("Ausiomixer.Host")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+2d66ba8ac482dae0ecbd020874072faa1e6b9b71")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+84124f58445f0c28ff8aa917a3103433e1537406")] [assembly: System.Reflection.AssemblyProductAttribute("Ausiomixer.Host")] [assembly: System.Reflection.AssemblyTitleAttribute("Ausiomixer.Host")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.AssemblyInfoInputs.cache b/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.AssemblyInfoInputs.cache index dd8eb8a..1abdc08 100644 --- a/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.AssemblyInfoInputs.cache +++ b/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.AssemblyInfoInputs.cache @@ -1 +1 @@ -5fed34eb147c8b7e5d15e4e94ecb680edbdc2839b7dd76ab1097e9b47a21aa76 +25a5dabf1bef3583800509cf3f8e0861a1096ff051e2e3daa149589a7054ae5c diff --git a/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.dll b/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.dll index a1f002e..b3b1e4e 100644 Binary files a/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.dll and b/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.dll differ diff --git a/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.pdb b/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.pdb index 993ba16..7cafda8 100644 Binary files a/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.pdb and b/host/Ausiomixer.Host/obj/Release/net8.0/Ausiomixer.Host.pdb differ diff --git a/host/Ausiomixer.Host/obj/Release/net8.0/apphost.exe b/host/Ausiomixer.Host/obj/Release/net8.0/apphost.exe index 4378fff..492042b 100644 Binary files a/host/Ausiomixer.Host/obj/Release/net8.0/apphost.exe and b/host/Ausiomixer.Host/obj/Release/net8.0/apphost.exe differ diff --git a/host/Ausiomixer.Host/obj/Release/net8.0/ref/Ausiomixer.Host.dll b/host/Ausiomixer.Host/obj/Release/net8.0/ref/Ausiomixer.Host.dll index d9d2adc..24ecc8d 100644 Binary files a/host/Ausiomixer.Host/obj/Release/net8.0/ref/Ausiomixer.Host.dll and b/host/Ausiomixer.Host/obj/Release/net8.0/ref/Ausiomixer.Host.dll differ diff --git a/host/Ausiomixer.Host/obj/Release/net8.0/refint/Ausiomixer.Host.dll b/host/Ausiomixer.Host/obj/Release/net8.0/refint/Ausiomixer.Host.dll index d9d2adc..24ecc8d 100644 Binary files a/host/Ausiomixer.Host/obj/Release/net8.0/refint/Ausiomixer.Host.dll and b/host/Ausiomixer.Host/obj/Release/net8.0/refint/Ausiomixer.Host.dll differ diff --git a/ili9341.c b/ili9341.c index 345658d..491f904 100644 --- a/ili9341.c +++ b/ili9341.c @@ -366,6 +366,8 @@ void lcd_init(void) { spi_set_format(LCD_SPI_INST, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); gpio_set_function(PIN_LCD_SCK, GPIO_FUNC_SPI); gpio_set_function(PIN_LCD_MOSI, GPIO_FUNC_SPI); + /* MISO optional for LCD; kept for future touch on same bus */ + gpio_set_function(PIN_LCD_MISO, GPIO_FUNC_SPI); printf("LCD 320x240 madctl=0x%02X baud~%u\n", MADCTL_FULL, baud); stdio_flush(); diff --git a/main.c b/main.c index 44e036c..4df4d2b 100644 --- a/main.c +++ b/main.c @@ -44,15 +44,37 @@ static uint8_t pot_read_pct(void) { return (uint8_t)((raw * 100u) / 4095u); } +static void toggle_init(void) { + gpio_init(PIN_TOGGLE); + gpio_set_dir(PIN_TOGGLE, GPIO_IN); + gpio_pull_up(PIN_TOGGLE); +} + +static void toggle_poll(void) { + static absolute_time_t next; + static int last = -1; + + if (!time_reached(next)) { + return; + } + next = make_timeout_time_ms(30); + + int level = gpio_get(PIN_TOGGLE) ? 1 : 0; + if (level == last) { + return; + } + last = level; + /* active-low: 0 = closed to GND */ + printf("TOGGLE GP%d = %d (%s)\n", + PIN_TOGGLE, level, level ? "open" : "closed"); + stdio_flush(); +} + int main(void) { led_init(); stdio_init_all(); tusb_init(); - /* - * Pump USB hard until mounted (COM appears). Never sleep 100ms between - * tud_task — that breaks Windows enumeration again. - */ absolute_time_t mount_deadline = make_timeout_time_ms(3000); absolute_time_t next_blink = make_timeout_time_ms(80); bool led = false; @@ -66,7 +88,6 @@ int main(void) { tight_loop_contents(); } - /* Optional: wait a bit for the serial monitor to open (still pumping). */ absolute_time_t cdc_deadline = make_timeout_time_ms(8000); while (!time_reached(cdc_deadline) && !tud_cdc_connected()) { tud_task(); @@ -84,10 +105,11 @@ int main(void) { printf("VID=0x%04X PID=0x%04X mounted=%d cdc=%d\n", AUSIO_USB_VID, AUSIO_USB_PID, (int)tud_mounted(), (int)tud_cdc_connected()); + printf("TOGGLE test: GP%d (pull-up, closed→GND prints closed)\n", PIN_TOGGLE); stdio_flush(); lcd_init(); - /* Skip RDID after init — bitbang read was corrupting the panel (bottom noise). */ + toggle_init(); ui_mixer_init(); hid_mixer_init(); @@ -120,6 +142,7 @@ int main(void) { while (true) { hid_mixer_task(); ui_mixer_task(); + toggle_poll(); encoder_poll(&enc1); encoder_poll(&enc2); diff --git a/pins.h b/pins.h index 91c0df5..72dbab8 100644 --- a/pins.h +++ b/pins.h @@ -13,19 +13,30 @@ /* Potentiometer wiper → ADC */ #define PIN_POT 26 /* ADC0 */ +/* Тумблер: GP9, второй контакт замыкать на землю (internal pull-up) */ +#define PIN_TOGGLE 9 + /* - * TPM408-2.8 (ILI9341 240x320) + shared SPI touch/SD: + * TPM408-2.8 (ILI9341 240x320): * SCK → GP18 * SDI → GP19 (MOSI) - * SDO → GP16 (MISO, optional) - * CS → GP17 (LCD) + * SDO → GP16 (MISO) — LCD SDO, optional + * CS → GP17 * DC → GP20 * RES → GP21 * LED → GP22 + * SD_CS→ GP7 (hold HIGH if unused) * - * MUST hold inactive (HIGH) or SPI bus fights the LCD → edge garbage: - * T_CS → GP6 (touch XPT2046 CS) — or tie to 3.3V if unused - * SD_CS → GP7 (microSD CS) — or tie to 3.3V if unused + * Touch XPT2046 — on THIS panel T_* does NOT share tracks with LCD + * (continuity check failed). Wire all 5 touch pins to Pico: + * + * T_CLK → GP18 (jumper to same net as LCD SCK) + * T_DIN → GP19 (jumper to same net as LCD MOSI) + * T_DO → GP16 (touch DO — NOT LCD SDO if they are separate pads) + * T_CS → GP6 + * T_IRQ → GP8 + * + * During a touch sample we bit-bang CLK/DIN/DO; LCD SPI is restored after. */ #define PIN_LCD_MISO 16 #define PIN_LCD_CS 17 @@ -35,7 +46,19 @@ #define PIN_LCD_RES 21 #define PIN_LCD_BL 22 -#define PIN_TOUCH_CS 6 +#define PIN_T_CLK 18 +#define PIN_T_DIN 19 +#define PIN_T_DO 16 +#define PIN_T_CS 6 +#define PIN_T_IRQ 8 + +#define PIN_TOUCH_CS PIN_T_CS +#define PIN_TOUCH_IRQ PIN_T_IRQ +#define PIN_TOUCH_SCK PIN_T_CLK +#define PIN_TOUCH_MOSI PIN_T_DIN +#define PIN_TOUCH_MISO PIN_T_DO + #define PIN_SD_CS 7 -#define LCD_SPI_INST spi0 +#define LCD_SPI_INST spi0 +#define TOUCH_SPI_INST LCD_SPI_INST diff --git a/touch.c b/touch.c new file mode 100644 index 0000000..d8e63c9 --- /dev/null +++ b/touch.c @@ -0,0 +1,291 @@ +#include "touch.h" +#include "pins.h" +#include "lcd.h" + +#include "hardware/gpio.h" +#include "hardware/spi.h" +#include "pico/stdlib.h" + +#include + +#define LCD_SPI_HZ (16 * 1000 * 1000) + +/* PD1=PD0=0 → power-down after conversion, PENIRQ enabled */ +#define XPT_CMD_X 0xD0 +#define XPT_CMD_Y 0x90 +#define XPT_CMD_Z1 0xB0 +#define XPT_CMD_PWR 0x80 + +#define RAW_X_MIN 250 +#define RAW_X_MAX 3900 +#define RAW_Y_MIN 200 +#define RAW_Y_MAX 3800 + +#define TOUCH_JUMP_REJECT 1800 +#define TOUCH_Z_MIN 300 + +static uint16_t s_prev_rx, s_prev_ry; +static bool s_have_prev; + +static inline void bb_delay(void) +{ + busy_wait_us(2); +} + +static void spi_pins_to_gpio(void) +{ + gpio_init(PIN_T_CLK); + gpio_set_dir(PIN_T_CLK, GPIO_OUT); + gpio_put(PIN_T_CLK, 0); + + gpio_init(PIN_T_DIN); + gpio_set_dir(PIN_T_DIN, GPIO_OUT); + gpio_put(PIN_T_DIN, 0); + + gpio_init(PIN_T_DO); + gpio_set_dir(PIN_T_DO, GPIO_IN); +} + +static void spi_pins_restore(void) +{ + gpio_set_function(PIN_T_CLK, GPIO_FUNC_SPI); + gpio_set_function(PIN_T_DIN, GPIO_FUNC_SPI); + gpio_set_function(PIN_T_DO, GPIO_FUNC_SPI); + spi_set_baudrate(TOUCH_SPI_INST, LCD_SPI_HZ); +} + +static void bb_clk_pulse(void) +{ + gpio_put(PIN_T_CLK, 1); + bb_delay(); + gpio_put(PIN_T_CLK, 0); + bb_delay(); +} + +static void bb_write8(uint8_t v) +{ + for (int i = 7; i >= 0; i--) { + gpio_put(PIN_T_DIN, (v >> i) & 1u); + bb_delay(); + bb_clk_pulse(); + } +} + +/* DOUT valid after falling CLK — sample with CLK low. */ +static uint16_t bb_read12(void) +{ + uint16_t v = 0; + bb_clk_pulse(); /* busy */ + for (int i = 0; i < 12; i++) { + gpio_put(PIN_T_CLK, 1); + bb_delay(); + gpio_put(PIN_T_CLK, 0); + bb_delay(); + v = (uint16_t)((v << 1) | (gpio_get(PIN_T_DO) ? 1u : 0u)); + } + bb_clk_pulse(); + bb_clk_pulse(); + bb_clk_pulse(); + return v; +} + +static uint16_t xpt_sample(uint8_t cmd) +{ + bb_write8(cmd); + return bb_read12(); +} + +static uint16_t xpt_read_avg(uint8_t cmd) +{ + (void)xpt_sample(cmd); + busy_wait_us(100); + + uint32_t sum = 0; + for (int i = 0; i < 3; i++) { + sum += xpt_sample(cmd); + busy_wait_us(30); + } + return (uint16_t)(sum / 3u); +} + +static void xpt_power_down_penirq(void) +{ + /* Must end with PD1=PD0=0 or PENIRQ stays dead until reset. */ + bb_write8(XPT_CMD_PWR); + for (int i = 0; i < 16; i++) { + bb_clk_pulse(); + } +} + +void touch_init(void) +{ + gpio_init(PIN_T_CS); + gpio_set_dir(PIN_T_CS, GPIO_OUT); + gpio_put(PIN_T_CS, 1); + + gpio_init(PIN_T_IRQ); + gpio_set_dir(PIN_T_IRQ, GPIO_IN); + gpio_pull_up(PIN_T_IRQ); + + gpio_init(PIN_SD_CS); + gpio_set_dir(PIN_SD_CS, GPIO_OUT); + gpio_put(PIN_SD_CS, 1); + + gpio_put(PIN_LCD_CS, 1); + gpio_set_function(PIN_T_DO, GPIO_FUNC_SPI); + + /* Ensure chip starts with PENIRQ armed. */ + spi_pins_to_gpio(); + gpio_put(PIN_T_CS, 0); + busy_wait_us(5); + xpt_power_down_penirq(); + gpio_put(PIN_T_CS, 1); + spi_pins_restore(); +} + +bool touch_pressed(void) +{ + return gpio_get(PIN_T_IRQ) == 0; +} + +bool touch_read_raw_ex(uint16_t *out_x, uint16_t *out_y, uint16_t *out_z) +{ + if (!out_x || !out_y) { + return false; + } + + /* + * Do NOT disable IRQs for the whole transfer — that starved TinyUSB + * (serial dropped) and could abort mid-frame leaving PENIRQ disabled. + */ + gpio_put(PIN_LCD_CS, 1); + gpio_put(PIN_SD_CS, 1); + + spi_pins_to_gpio(); + gpio_put(PIN_T_CS, 0); + busy_wait_us(10); + + uint16_t z1 = xpt_read_avg(XPT_CMD_Z1); + uint16_t x = xpt_read_avg(XPT_CMD_X); + uint16_t y = xpt_read_avg(XPT_CMD_Y); + + xpt_power_down_penirq(); + + gpio_put(PIN_T_CS, 1); + spi_pins_restore(); + + if (out_z) { + *out_z = z1; + } + *out_x = x; + *out_y = y; + return true; +} + +bool touch_read_raw(uint16_t *out_x, uint16_t *out_y) +{ + uint16_t z = 0; + return touch_read_raw_ex(out_x, out_y, &z); +} + +static int16_t map_clamp(int32_t v, int32_t in_min, int32_t in_max, + int32_t out_min, int32_t out_max) +{ + if (in_max == in_min) { + return (int16_t)out_min; + } + if (v < in_min) { + v = in_min; + } + if (v > in_max) { + v = in_max; + } + /* out_max < out_min is fine (axis flip). */ + return (int16_t)(out_min + (v - in_min) * (out_max - out_min) / (in_max - in_min)); +} + +static void map_to_screen(uint16_t rx, uint16_t ry, int16_t *sx, int16_t *sy) +{ + /* + * Landscape + MADCTL_MV: screen X ← touch raw_y, screen Y ← touch raw_x. + * Mirrors match this panel (X was reversed in bring-up). + */ + int16_t x = map_clamp(ry, RAW_Y_MIN, RAW_Y_MAX, 0, LCD_WIDTH - 1); + int16_t y = map_clamp(rx, RAW_X_MIN, RAW_X_MAX, 0, LCD_HEIGHT - 1); + +#if TOUCH_MIRROR_X + x = (int16_t)((LCD_WIDTH - 1) - x); +#endif +#if TOUCH_MIRROR_Y + y = (int16_t)((LCD_HEIGHT - 1) - y); +#endif + if (sx) { + *sx = x; + } + if (sy) { + *sy = y; + } +} + +bool touch_read_screen(int16_t *out_x, int16_t *out_y) +{ + uint16_t rx, ry; + if (!touch_read_raw(&rx, &ry)) { + return false; + } + map_to_screen(rx, ry, out_x, out_y); + return true; +} + +bool touch_read(uint16_t *raw_x, uint16_t *raw_y, int16_t *sx, int16_t *sy) +{ + return touch_read_diag(raw_x, raw_y, NULL, sx, sy); +} + +bool touch_read_diag(uint16_t *raw_x, uint16_t *raw_y, uint16_t *z, + int16_t *sx, int16_t *sy) +{ + uint16_t rx = 0, ry = 0, zz = 0; + if (!touch_read_raw_ex(&rx, &ry, &zz)) { + return false; + } + + if (zz < TOUCH_Z_MIN) { + s_have_prev = false; + return false; + } + + if (s_have_prev) { + int dx = (int)rx - (int)s_prev_rx; + int dy = (int)ry - (int)s_prev_ry; + if (dx < 0) { + dx = -dx; + } + if (dy < 0) { + dy = -dy; + } + if (dx > TOUCH_JUMP_REJECT || dy > TOUCH_JUMP_REJECT) { + return false; + } + } + s_prev_rx = rx; + s_prev_ry = ry; + s_have_prev = true; + + if (raw_x) { + *raw_x = rx; + } + if (raw_y) { + *raw_y = ry; + } + if (z) { + *z = zz; + } + map_to_screen(rx, ry, sx, sy); + return true; +} + +void touch_filter_reset(void) +{ + s_have_prev = false; +} diff --git a/touch.h b/touch.h new file mode 100644 index 0000000..e5aee7c --- /dev/null +++ b/touch.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +/* Axis flips after raw→screen map (1 = invert). */ +#define TOUCH_MIRROR_X 1 +#define TOUCH_MIRROR_Y 1 + +void touch_init(void); + +/* IRQ low — finger down. */ +bool touch_pressed(void); + +bool touch_read_raw(uint16_t *out_x, uint16_t *out_y); +bool touch_read_raw_ex(uint16_t *out_x, uint16_t *out_y, uint16_t *out_z); +bool touch_read_screen(int16_t *out_x, int16_t *out_y); +bool touch_read(uint16_t *raw_x, uint16_t *raw_y, int16_t *sx, int16_t *sy); +bool touch_read_diag(uint16_t *raw_x, uint16_t *raw_y, uint16_t *z, + int16_t *sx, int16_t *sy); +void touch_filter_reset(void);