From e634d538bd1082a1c399d735738fe168934a9c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Hamal=20Dvo=C5=99=C3=A1k?= Date: Sun, 15 Jun 2025 22:02:02 +0200 Subject: [PATCH] Initial import - audio output --- .gitignore | 1 + .gitmodules | 3 + etc/regmap.py | 149 +++++++++++++++++++++++++++++++ src/.clangd | 2 + src/CMakeLists.txt | 49 ++++++++++ src/main.c | 88 ++++++++++++++++++ src/vendor/pico-stdio-usb-simple | 1 + 7 files changed, 293 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 etc/regmap.py create mode 100644 src/.clangd create mode 100644 src/CMakeLists.txt create mode 100644 src/main.c create mode 160000 src/vendor/pico-stdio-usb-simple diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84c048a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f44378f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/vendor/pico-stdio-usb-simple"] + path = src/vendor/pico-stdio-usb-simple + url = https://github.com/mordae/pico-stdio-usb-simple diff --git a/etc/regmap.py b/etc/regmap.py new file mode 100644 index 0000000..71ece34 --- /dev/null +++ b/etc/regmap.py @@ -0,0 +1,149 @@ +from dataclasses import dataclass +from fnmatch import fnmatch +from sys import argv + +from lxml.etree import XML + +# List of . patterns to mark as unsafe. +UNSAFE: list[str] = [ + "SIO.SPINLOCK[0-9]*", + "ADC.FIFO", + "SSI.*CR", + "SIO.DIV_QUOTIENT", + "SIO.DIV_REMAINDER", + "SIO.FIFO_RD", + "M0PLUS.SYST_CSR", + "I2C*.IC_CLR*", + "TIMER.TIME[HL]R", + "PIO*.RXF*", + "PPB.*", + "XIP.*", +] + + +def is_unsafe(peri: str, reg: str) -> bool: + for pattern in UNSAFE: + if fnmatch(f"{peri}.{reg}", pattern): + return True + + return False + + +with open(argv[1], "rb") as fp: + xml = XML(fp.read()) + + +@dataclass +class Register: + name: str + offset: int + reset: int + read: bool + write: bool + + +@dataclass +class Peripheral: + name: str + base: int + regs: list[Register] + + +peripherals: dict[str, Peripheral] = {} + +for peri in xml.cssselect("peripheral"): + if "derivedFrom" in peri.attrib: + orig = peripherals[peri.attrib["derivedFrom"]] + names = peri.cssselect("peripheral > name") + assert len(names) == 1 + + peripheral = Peripheral(name=names[0].text, base=orig.base, regs=orig.regs) + continue + + names = peri.cssselect("peripheral > name") + assert len(names) == 1 + + bases = peri.cssselect("peripheral > baseAddress") + assert len(bases) == 1 + + base = int(bases[0].text, 16) + peripheral = Peripheral(name=names[0].text, base=base, regs=[]) + + for reg in peri.cssselect("peripheral > registers > register"): + names = reg.cssselect("register > name") + assert len(names) == 1 + + offsets = reg.cssselect("register > addressOffset") + assert len(offsets) == 1 + + resets = reg.cssselect("register > resetValue") + assert len(resets) == 1 + + accesses = reg.cssselect("access") + assert len(accesses) > 0 + + write = read = False + + for access in accesses: + match access.text: + case "read-only": + read = True + + case "read-write": + write = read = True + + case "write-only": + write = True + + case mode: + assert False, f"unknown access mode {mode!r}" + + offset = int(offsets[0].text, 16) + reset = int(resets[0].text, 16) + register = Register( + name=names[0].text, + offset=offset, + reset=reset, + write=write, + read=read, + ) + peripheral.regs.append(register) + + peripherals[peripheral.name] = peripheral + +print( + """ +#include "regmap.h" + +struct reg_info regmap[] = { +""".strip() +) + +for peripheral in peripherals.values(): + for register in peripheral.regs: + print("{ ", end="") + print(f"{hex(peripheral.base + register.offset)}, ", end="") + print(f"{hex(register.reset)}, ", end="") + print(f"{hex(register.reset)}, ", end="") + print(f'"{peripheral.name}", ', end="") + print(f'"{register.name}", ', end="") + + if register.read: + print("1, ", end="") + else: + print("0, ", end="") + + if register.write: + print("1, ", end="") + else: + print("0, ", end="") + + if is_unsafe(peripheral.name, register.name): + print("1", end="") + else: + print("0", end="") + + print(" },") + +print("{ 0, 0, 0, NULL, NULL, 0, 0, 0 },") +print("};") diff --git a/src/.clangd b/src/.clangd new file mode 100644 index 0000000..9ad2e07 --- /dev/null +++ b/src/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + CompilationDatabase: ../build diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..43bf553 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.21) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +include($ENV{PICO_SDK_PATH}/pico_sdk_init.cmake) + +project(pdmtest) +pico_sdk_init() + +add_executable(pdmtest main.c) + +add_subdirectory(vendor/pico-stdio-usb-simple) + +target_link_libraries( + pdmtest + pico_stdio_usb_simple + + pico_divider + pico_multicore + pico_stdlib + pico_util + hardware_adc + hardware_pwm + hardware_divider + hardware_dma + hardware_pio + hardware_timer + hardware_vreg +) + +target_compile_definitions(pdmtest PRIVATE + PLL_SYS_REFDIV=1 + PLL_SYS_VCO_FREQ_HZ=1584000000 + PLL_SYS_POSTDIV1=6 + PLL_SYS_POSTDIV2=2 + SYS_CLK_HZ=132000000 +) + +pico_add_extra_outputs(pdmtest) + +set_property(TARGET pdmtest PROPERTY C_STANDARD 23) +target_compile_options(pdmtest PRIVATE -Wall -Wextra -Wnull-dereference) +target_compile_definitions(pdmtest PUBLIC PICO_MAX_SHARED_IRQ_HANDLERS=8u) +target_compile_definitions(pdmtest PUBLIC PICO_STDIO_ENABLE_CRLF_SUPPORT=1) +target_compile_definitions(pdmtest PUBLIC PICO_STDIO_DEFAULT_CRLF=1) + +target_include_directories(pdmtest PRIVATE include) + +#pico_set_binary_type(pdmtest no_flash) +#pico_set_binary_type(pdmtest copy_to_ram) diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..02c673d --- /dev/null +++ b/src/main.c @@ -0,0 +1,88 @@ +#include +#include + +#include + +#include + +#define IR_BIAS_PIN 3 +#define IR_RX_PIN 6 +#define IR_FB_PIN 7 + +#define HP_GND_PIN 13 +#define HP_LEFT_PIN 14 +#define HP_RIGHT_PIN 15 + +#define HP_GND_SLICE 6 +#define HP_GND_CHAN PWM_CHAN_B + +#define HP_LR_SLICE 7 + +#define HP_PWM_RATE (16 * 48 * 1000) +#define HP_PWM_SCALE (SYS_CLK_HZ / HP_PWM_RATE) +#define HP_PWM_MID (HP_PWM_SCALE / 2) + +int main() +{ + stdio_usb_init(); + + for (int i = 0; i < 30; i++) { + if (stdio_usb_connected()) + break; + + sleep_ms(100); + } + + printf("\nWelcome to PDM Test!\n"); + + gpio_disable_pulls(HP_GND_PIN); + gpio_disable_pulls(HP_LEFT_PIN); + gpio_disable_pulls(HP_RIGHT_PIN); + + gpio_set_function(HP_GND_PIN, GPIO_FUNC_PWM); + gpio_set_function(HP_LEFT_PIN, GPIO_FUNC_PWM); + gpio_set_function(HP_RIGHT_PIN, GPIO_FUNC_PWM); + + gpio_set_drive_strength(HP_GND_PIN, GPIO_DRIVE_STRENGTH_2MA); + gpio_set_drive_strength(HP_LEFT_PIN, GPIO_DRIVE_STRENGTH_2MA); + gpio_set_drive_strength(HP_RIGHT_PIN, GPIO_DRIVE_STRENGTH_2MA); + + /* LR at 48 kHz */ + pwm_config pc = pwm_get_default_config(); + pwm_config_set_clkdiv_int(&pc, 1); + pwm_config_set_phase_correct(&pc, false); + pwm_config_set_wrap(&pc, HP_PWM_SCALE - 1); + pwm_init(HP_LR_SLICE, &pc, false); + + /* GND at high rate, 50:50 for virtual ground */ + pwm_config_set_wrap(&pc, 1); + pwm_init(HP_GND_SLICE, &pc, false); + pwm_set_chan_level(HP_GND_SLICE, HP_GND_CHAN, 1); + + /* Start at 50:50. */ + pwm_set_both_levels(HP_LR_SLICE, HP_PWM_MID, HP_PWM_MID); + + /* Start both */ + pwm_set_enabled(HP_GND_SLICE, true); + pwm_set_enabled(HP_LR_SLICE, true); + + while (true) { + for (int i = 0; i < 50; i++) { + sleep_us(2272); + pwm_set_both_levels(HP_LR_SLICE, HP_PWM_MID + 1, HP_PWM_MID + 1); + + sleep_us(2272); + pwm_set_both_levels(HP_LR_SLICE, HP_PWM_MID - 1, HP_PWM_MID - 1); + } + + for (int i = 0; i < 55; i++) { + sleep_us(2020); + pwm_set_both_levels(HP_LR_SLICE, HP_PWM_MID + 1, HP_PWM_MID + 1); + + sleep_us(2020); + pwm_set_both_levels(HP_LR_SLICE, HP_PWM_MID - 1, HP_PWM_MID - 1); + } + + sleep_ms(500); + } +} diff --git a/src/vendor/pico-stdio-usb-simple b/src/vendor/pico-stdio-usb-simple new file mode 160000 index 0000000..0897a68 --- /dev/null +++ b/src/vendor/pico-stdio-usb-simple @@ -0,0 +1 @@ +Subproject commit 0897a68ac3ca865715368ce824f49275222ed57e