diff --git a/.gitignore b/.gitignore index c29d90d..5488b0c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ !*.pdf !*.html !*.yml +!*.zip # specific files !.gitignore @@ -32,6 +33,8 @@ !examples/sidberry !examples/vice !examples/hardsid-sidblaster +!cases +!cases/** # folder contents !examples/hardsid-sidblaster/** diff --git a/CHANGELOG.md b/CHANGELOG.md index 43989e1..9888be2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,19 @@ # Changelog -#### Version: 0.3.0-BETA (Unreleased) +#### Version: 0.2.?-BETA (SNAPSHOT) * ... * Beam me up Scotty! * Continue work on Midi handling + +#### Version: 0.2.3-BETA +* Add workflow for auto version release build * Fix issue in SID tests not stopping - * Add Support for Pico2 (rp2350) green board +* Add Support for Pico2 (rp2350) green board * Add Support for PicoW (rp2040) green board - NOTE: Due to the LED being used by the WiFi chip there is no VU support * Rename Vue to Vu 🤦‍♀️ * Remove `__builtin_` function calls + #### Version: 0.2.2-BETA * Add direct SID functions - Detect SID type @@ -28,11 +32,13 @@ * Enable CC's for bank 9 (temporary workaround) * Refactor some whitespace * Start work on support for PicoW and Pico2 boards + #### Version: 0.2.1-BETA * Start on update for Midi handling * Details will follow at a later time when finished * Fix ASID play * Fix config save error + #### Version: 0.2.0-BETA * Basic Midi support * Fixed to 6 voices polyfonic with 2 SID's up to 12 voices with 2x SKPico. @@ -42,6 +48,7 @@ * Improved GPIO handling * Bus control via DMA and PIO for cycle exact writes and reads * Customizable config (config tool in development) + #### Version: 0.0.1-ALPHA * Basic working functions * Multiple firmware binaries per config type diff --git a/CMakeLists.txt b/CMakeLists.txt index 735d91d..c119c89 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ cmake_minimum_required(VERSION 3.17) set(PROJECT_NAME usbsidpico) set(PROJECT_MANUFACTURER "LouD") set(PRODUCT_STRING "USBSID-Pico") -set(MAGIC_SMOKE "20241208") +set(MAGIC_SMOKE "20241220") set(PROJECT_VERSION "0.2.3-BETA.${MAGIC_SMOKE}") # Must be the same as in config.h ### Want a cookie? @@ -224,6 +224,7 @@ set(SOURCEFILES ${CMAKE_CURRENT_LIST_DIR}/src/sid.c ${CMAKE_CURRENT_LIST_DIR}/src/mcu.c ${CMAKE_CURRENT_LIST_DIR}/src/usb_descriptors.c + ${CMAKE_CURRENT_LIST_DIR}/src/util.c ) ### Libraries to link @@ -245,6 +246,7 @@ set(TARGET_LL pico_stdlib pico_unique_id pico_usb_reset_interface + pico_async_context_threadsafe_background tinyusb_device tinyusb_board ) diff --git a/README.md b/README.md index 1e32175..4dab9ab 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2 (RP2350) based board for interf * [Hardware](#hardware) * [Where to buy](#where-to-buy) * [Schematic and BOM](#schematic-and-bom) + * [Cases](#cases) * [Important PCB information](#important-pcb-information) * [PCB in action](#usbsid-pico-in-action) * [Software examples](#software) @@ -94,8 +95,8 @@ See the [firmware changelog](CHANGELOG.md) for more information on what's change ### Firmware versions Use `usbsidpico.uf2` for Pico1 regular green rp2040 Pico boards. Use `usbsidpico-rgb.uf2` for Pico1 black clone rp2040 Pico boards with RGB LED onboard. -Use `usbsidpico_w.uf2` for PicoW regular green rp2040 Pico boards. -Use `usbsidpico2.uf2` for Pico2 regular green rp2040 Pico boards. +Use `usbsidpico_w.uf2` for PicoW regular green rp2040 PicoW boards. +Use `usbsidpico2.uf2` for Pico2 regular green rp2350 Pico2 boards. **WARNING!** Do _NOT_ use the RGB firmware for any of the (non black) rp2040 or rp2350 Pico boards that do not contain an RGB LED. ### How to flash A Raspberry Pi Pico board is incredibly easy to flash, as it comes with a built in bootloader for flashing new firmwares in the `uf2` format. @@ -177,6 +178,10 @@ If you want and are up to it you can create your own development board by using * v0.1 testboard
+## Cases +All USBSID-Pico community created cases are available in the [cases](cases/) folder, direct links below. +* [Cartridge case](cases/spotUP/USBSID-Pico_Case.zip) by @spotUP + ## Important PCB information [](images/v1.0-explained.png)
_Click image for larger view_ diff --git a/cases/spotUP/USBSID-Pico_Case.zip b/cases/spotUP/USBSID-Pico_Case.zip new file mode 100644 index 0000000..8489930 Binary files /dev/null and b/cases/spotUP/USBSID-Pico_Case.zip differ diff --git a/src/asid.c b/src/asid.c index 2d690a5..b993342 100644 --- a/src/asid.c +++ b/src/asid.c @@ -39,6 +39,7 @@ /* GPIO externals */ extern uint8_t bus_operation(uint8_t command, uint8_t address, uint8_t data); extern void pause_sid(void); +extern void reset_sid(void); /* Well, it does what it does */ void handle_asid_message(uint8_t sid, uint8_t* buffer, int size) @@ -66,27 +67,28 @@ void handle_asid_message(uint8_t sid, uint8_t* buffer, int size) void decode_asid_message(uint8_t* buffer, int size) { switch(buffer[2]) { - case 0x4C: - /* Play start */ + case 0x4C: /* Play start */ midimachine.bus = CLAIMED; break; - case 0x4D: - /* Play stop */ + case 0x4D: /* Play stop */ + reset_sid(); pause_sid(); midimachine.bus = FREE; break; - case 0x4F: - /* Display characters */ + case 0x4F: /* Display characters */ break; - case 0x4E: + case 0x4E: /* SID 1 */ handle_asid_message(0, buffer, size); break; - case 0x50: + case 0x50: /* SID 2 */ handle_asid_message(32, buffer, size); break; - case 0x51: + case 0x51: /* SID 3 */ handle_asid_message(64, buffer, size); break; + case 0x52: /* SID 4 */ + handle_asid_message(96, buffer, size); + break; case 0x60: midimachine.fmopl = 1; /* Not implemented yet */ default: diff --git a/src/config.c b/src/config.c index b779af2..7b20382 100644 --- a/src/config.c +++ b/src/config.c @@ -23,7 +23,9 @@ * */ -#include + +#include "hardware/gpio.h" +#include "hardware/pio.h" #include "globals.h" #include "config.h" @@ -42,6 +44,8 @@ extern char dtype; extern uint8_t *cdc_itf; extern uint8_t *wusb_itf; extern uint8_t *write_buffer_p; +extern double clk_rate, sidfrq, frqpow; +extern uint8_t sid_memory[]; /* SID externals */ extern uint8_t detect_sid_version(uint8_t start_addr); @@ -52,7 +56,6 @@ extern void restart_bus(void); /* Midi externals */ extern void midi_bus_operation(uint8_t a, uint8_t b); -extern int curr_midi_channel; /* MCU externals */ extern void mcu_reset(void); @@ -65,6 +68,15 @@ uint8_t one, two, three, four; const char* project_version = PROJECT_VERSION; static uint8_t p_version_array[MAX_BUFFER_SIZE]; +/* Init string vars */ +const char *sidtypes[4] = { "UNKNOWN", "N/A", "MOS8580", "MOS6581" }; +const char *chiptypes[2] = { "Real", "Clone" }; +const char *clonetypes[6] = { "Disabled", "Other", "SKPico", "ARMSID", "FPGASID", "RedipSID" }; +const char *int_ext[2] = { "Internal", "External" }; +const char *en_dis[2] = { "Enabled", "Disabled" }; +const char *true_false[2] = { "True", "False" }; +const char *single_dual[2] = { "Dual SID", "Single SID" }; + #define USBSID_DEFAULT_CONFIG_INIT { \ .magic = MAGIC_SMOKE, \ .default_config = 1, \ @@ -73,13 +85,19 @@ static uint8_t p_version_array[MAX_BUFFER_SIZE]; .socketOne = { \ .enabled = true, \ .dualsid = false, \ - .sidtype = 0x0, /* empty */ \ + .chiptype = 0x0, /* real */ \ + .clonetype = 0x0, /* disabled */ \ + .sid1type = 0x0, /* unknown */ \ + .sid2type = 0x0, /* unknown */ \ }, \ .socketTwo = { \ .enabled = true, \ .dualsid = false, \ .act_as_one = false, \ - .sidtype = 0x0, /* empty */ \ + .chiptype = 0x0, /* real */ \ + .clonetype = 0x0, /* disabled */ \ + .sid1type = 0x0, /* unknown */ \ + .sid2type = 0x0, /* unknown */ \ }, \ .LED = { \ .enabled = true, \ @@ -111,12 +129,12 @@ void print_cfg(const uint8_t *buf, size_t len) { CFG("[PRINT CFG START]\n"); for (size_t i = 0; i < len; ++i) { if (i == 0) - CFG("[R%d] ", i); + CFG("[R%03d] ", i); CFG("%02x", buf[i]); if (i == (len - 1)) { CFG("\n"); - } else if (i % 16 == 15) { - CFG("\n[R%d] ", i); + } else if ((i != 0) && (i % 16 == 15)) { + CFG("\n[R%03d] ", i); } else { CFG(" "); } @@ -126,30 +144,70 @@ void print_cfg(const uint8_t *buf, size_t len) { void detect_sid_types(void) { - const char *sidtypes[4] = {"NONE", "CLONE", "MOS8580", "MOS6581"}; - int sid1 = 0, sid2 = 0; - if (usbsid_config.socketOne.enabled) { + int sid1 = 0, sid2 = 0, sid3 = 0, sid4 = 0; + + if (numsids >= 1) { sid1 = detect_sid_version(0x00); - usbsid_config.socketOne.sidtype = sid1; - } else { - usbsid_config.socketOne.sidtype = 0; + CFG("[READ SID1] [%02x %s]\n", sid1, sidtypes[sid1]); + } + if (numsids >= 2) { + sid2 = detect_sid_version(0x20); + CFG("[READ SID2] [%02x %s]\n", sid2, sidtypes[sid2]); + } + if (numsids >= 3) { + sid3 = detect_sid_version(0x40); + CFG("[READ SID3] [%02x %s]\n", sid3, sidtypes[sid3]); + } + if (numsids == 4) { + sid4 = detect_sid_version(0x60); + CFG("[READ SID4] [%02x %s]\n", sid4, sidtypes[sid4]); } - if (usbsid_config.socketTwo.enabled) { + + if (usbsid_config.socketOne.enabled && usbsid_config.socketTwo.enabled) { + if (usbsid_config.socketOne.dualsid && usbsid_config.socketTwo.dualsid) { + usbsid_config.socketOne.sid1type = sid1; + usbsid_config.socketOne.sid2type = sid2; + usbsid_config.socketTwo.sid1type = sid3; + usbsid_config.socketTwo.sid2type = sid4; + } + if (!usbsid_config.socketOne.dualsid && usbsid_config.socketTwo.dualsid) { + usbsid_config.socketOne.sid1type = sid1; + usbsid_config.socketOne.sid2type = 1; + usbsid_config.socketTwo.sid1type = sid2; + usbsid_config.socketTwo.sid2type = sid3; + } + if (usbsid_config.socketOne.dualsid && !usbsid_config.socketTwo.dualsid) { + usbsid_config.socketOne.sid1type = sid1; + usbsid_config.socketOne.sid2type = sid2; + usbsid_config.socketTwo.sid1type = sid3; + usbsid_config.socketTwo.sid2type = 1; + } + } else if (usbsid_config.socketOne.enabled && !usbsid_config.socketTwo.enabled) { + usbsid_config.socketTwo.sid1type = 1; + usbsid_config.socketTwo.sid2type = 1; if (usbsid_config.socketOne.dualsid) { - sid2 = detect_sid_version(0x40); - usbsid_config.socketTwo.sidtype = sid2; - } else { - sid2 = detect_sid_version(0x20); - usbsid_config.socketTwo.sidtype = sid2; + usbsid_config.socketOne.sid1type = sid1; + usbsid_config.socketOne.sid2type = sid2; + } else if (!usbsid_config.socketOne.dualsid) { + usbsid_config.socketOne.sid1type = sid1; + usbsid_config.socketOne.sid2type = 1; + } + } else if (!usbsid_config.socketOne.enabled && usbsid_config.socketTwo.enabled) { + usbsid_config.socketOne.sid1type = 1; + usbsid_config.socketOne.sid2type = 1; + if (usbsid_config.socketTwo.dualsid) { + usbsid_config.socketTwo.sid1type = sid1; + usbsid_config.socketTwo.sid2type = sid2; + } else if (!usbsid_config.socketTwo.dualsid) { + usbsid_config.socketTwo.sid1type = sid1; + usbsid_config.socketTwo.sid2type = 1; } - } else { - usbsid_config.socketTwo.sidtype = 0; } - CFG("[SOCKET ONE] %s\n", sidtypes[usbsid_config.socketOne.sidtype]); - CFG("[SOCKET TWO] %s\n", sidtypes[usbsid_config.socketTwo.sidtype]); - CFG("[READ SID1] [%02x %s]\n", sid1, sidtypes[sid1]); - CFG("[READ SID2] [%02x %s]\n", sid2, sidtypes[sid2]); + CFG("[SOCKET ONE SID1 TYPE] %s\n", sidtypes[usbsid_config.socketOne.sid1type]); + CFG("[SOCKET ONE SID2 TYPE] %s\n", sidtypes[usbsid_config.socketOne.sid2type]); + CFG("[SOCKET TWO SID1 TYPE] %s\n", sidtypes[usbsid_config.socketTwo.sid1type]); + CFG("[SOCKET TWO SID2 TYPE] %s\n", sidtypes[usbsid_config.socketTwo.sid2type]); } void read_config(Config* config) @@ -163,11 +221,17 @@ void read_config(Config* config) config_array[9] = config->clock_rate & BYTE; config_array[10] = (int)config->socketOne.enabled; config_array[11] = (int)config->socketOne.dualsid; - config_array[12] = config->socketOne.sidtype; + config_array[12] = config->socketOne.chiptype; + config_array[13] = config->socketOne.clonetype; + config_array[14] = config->socketOne.sid1type; + config_array[15] = config->socketOne.sid2type; config_array[20] = (int)config->socketTwo.enabled; config_array[21] = (int)config->socketTwo.dualsid; - config_array[22] = config->socketTwo.sidtype; - config_array[23] = (int)config->socketTwo.act_as_one; + config_array[22] = (int)config->socketTwo.act_as_one; + config_array[23] = config->socketTwo.chiptype; + config_array[24] = config->socketTwo.clonetype; + config_array[25] = config->socketTwo.sid1type; + config_array[26] = config->socketTwo.sid2type; config_array[30] = (int)config->LED.enabled; config_array[31] = (int)config->LED.idle_breathe; config_array[40] = (int)config->RGBLED.enabled; @@ -195,7 +259,7 @@ void default_config(Config* config) void load_config(Config* config) { - CFG("[COPY CONFIG] [FROM]0x%x [TO]0x%x [SIZE]%u\n", XIP_BASE + FLASH_TARGET_OFFSET, (uint)&config, sizeof(Config)); + CFG("[COPY CONFIG] [FROM]0x%x [TO]0x%x [SIZE]%u\n", XIP_BASE + FLASH_TARGET_OFFSET, (uint)&config, sizeof(Config)); memcpy(config, (void *)(XIP_BASE + FLASH_TARGET_OFFSET), sizeof(Config)); stdio_flush(); if (config->magic != MAGIC_SMOKE) { @@ -245,19 +309,12 @@ void handle_config_request(uint8_t * buffer) /* TODO: loads current config and sends it to the requester ~ when config is finished */ /* ISSUE: Although 4 writes are performed, only the first 2 are received */ CFG("[XIP_BASE]%u [FLASH_PAGE_SIZE]%u [FLASH_SECTOR_SIZE]%u [FLASH_TARGET_OFFSET]%u\r\n", XIP_BASE, FLASH_PAGE_SIZE, FLASH_SECTOR_SIZE, FLASH_TARGET_OFFSET); - CFG("[>]\r\n"); read_config(&usbsid_config); print_cfg(config_array, count_of(config_array)); - CFG("[<]\r\n"); int writes = count_of(config_array) / 64; /* BUG: It should send 4 packets of 64 bytes, but sends only 2 and a zero packet */ - CFG("[>] SEND %d WRITES OF 64 BYTES TO %c [<]\n", writes, dtype); memset(write_buffer_p, 0, 64); for (int i = 0; i < writes; i++) { memcpy(write_buffer_p, config_array + (i * 64), 64); - CFG("[>] SEND WRITE %d OF %d [<]\n", i, writes); - CFG("[>]"); - for (int i = 0; i < 64; i++) CFG(" %x", write_buffer_p[i]); - CFG(" [<]\n"); switch (dtype) { case 'C': cdc_write(cdc_itf, 64); @@ -280,14 +337,54 @@ void handle_config_request(uint8_t * buffer) usbsid_config.clock_rate = clockrates[(int)buffer[2]]; break; case 1: /* socketOne */ + switch (buffer[2]) { + case 0: /* enabled */ + if (buffer[3] <= 1) { /* 1 or 0 */ + usbsid_config.socketOne.enabled = (buffer[3] == 1) ? true : false; + }; + break; + case 1: /* dualsid */ + if (buffer[3] <= 1) { /* 1 or 0 */ + usbsid_config.socketOne.dualsid = (buffer[3] == 1) ? true : false; + }; + break; + case 2: /* chiptype */ + case 3: /* clonetype */ + case 4: /* sid1type */ + case 5: /* sid2type */ + break; + }; break; case 2: /* socketTwo */ + switch (buffer[2]) { + case 0: /* enabled */ + if (buffer[3] <= 1) { /* 1 or 0 */ + usbsid_config.socketTwo.enabled = (buffer[3] == 1) ? true : false; + }; + break; + case 1: /* dualsid */ + if (buffer[3] <= 1) { /* 1 or 0 */ + usbsid_config.socketTwo.dualsid = (buffer[3] == 1) ? true : false; + }; + break; + case 2: /* act_as_one */ + if (buffer[3] <= 1) { /* 1 or 0 */ + usbsid_config.socketTwo.act_as_one = (buffer[3] == 1) ? true : false; + }; + break; + case 3: /* chiptype */ + case 4: /* clonetype */ + case 5: /* sid1type */ + case 6: /* sid2type */ + break; + }; break; case 3: /* LED */ switch (buffer[2]) { case 0: /* enabled */ - if (buffer[3] <= 1) /* 1 or 0 */ + if (buffer[3] <= 1) { /* 1 or 0 */ usbsid_config.LED.enabled = (buffer[3] == 1) ? true : false; + }; break; case 1: /* idle_breathe */ if (buffer[3] <= 1) { /* 1 or 0 */ @@ -300,7 +397,7 @@ void handle_config_request(uint8_t * buffer) break; default: break; - } + }; break; case 4: /* RGBLED */ switch (buffer[2]) { @@ -344,7 +441,7 @@ void handle_config_request(uint8_t * buffer) case 8: /* MIDI */ default: break; - } + }; break; case SAVE_CONFIG: CFG("[SAVE_CONFIG] and RESET_MCU\n"); @@ -371,8 +468,6 @@ void handle_config_request(uint8_t * buffer) usbsid_config.socketTwo.enabled = false; usbsid_config.socketOne.dualsid = false; usbsid_config.socketTwo.dualsid = false; - usbsid_config.socketOne.sidtype = 0; - usbsid_config.socketTwo.sidtype = 0; usbsid_config.socketTwo.act_as_one = true; save_config(&usbsid_config); load_config(&usbsid_config); @@ -384,8 +479,6 @@ void handle_config_request(uint8_t * buffer) usbsid_config.socketTwo.enabled = true; usbsid_config.socketOne.dualsid = false; usbsid_config.socketTwo.dualsid = false; - usbsid_config.socketOne.sidtype = 1; - usbsid_config.socketTwo.sidtype = 1; usbsid_config.socketTwo.act_as_one = false; save_config(&usbsid_config); load_config(&usbsid_config); @@ -397,8 +490,6 @@ void handle_config_request(uint8_t * buffer) usbsid_config.socketTwo.enabled = true; usbsid_config.socketOne.dualsid = true; usbsid_config.socketTwo.dualsid = true; - usbsid_config.socketOne.sidtype = 1; - usbsid_config.socketTwo.sidtype = 1; usbsid_config.socketTwo.act_as_one = false; save_config(&usbsid_config); load_config(&usbsid_config); @@ -410,8 +501,6 @@ void handle_config_request(uint8_t * buffer) usbsid_config.socketTwo.enabled = true; usbsid_config.socketOne.dualsid = true; usbsid_config.socketTwo.dualsid = false; - usbsid_config.socketOne.sidtype = 1; - usbsid_config.socketTwo.sidtype = 1; usbsid_config.socketTwo.act_as_one = false; save_config(&usbsid_config); mcu_reset(); @@ -464,9 +553,14 @@ void handle_config_request(uint8_t * buffer) if (clockrates[(int)buffer[1]] != usbsid_config.clock_rate) { CFG("[CLOCK FROM]%d [CLOCK TO]%d\n", usbsid_config.clock_rate, clockrates[(int)buffer[1]]); usbsid_config.clock_rate = clockrates[(int)buffer[1]]; + /* Cycled write buffer vars */ + clk_rate = usbsid_config.clock_rate; + sidfrq = (clk_rate / 1000 / 1000); + frqpow = (1 / sidfrq); + /* Start clock set */ deinit_sidclock(); init_sidclock(); - /* restart_bus(); */ /* TODO: Enable after bus_clock change */ + restart_bus(); } else { CFG("[CLOCK FROM]%d AND [CLOCK TO]%d ARE THE SAME, SKIPPING SET_CLOCK\n", usbsid_config.clock_rate, clockrates[(int)buffer[1]]); } @@ -533,6 +627,9 @@ void handle_config_request(uint8_t * buffer) printf("A %x %x %d\n", (uint32_t)usbsid_config.magic, (uint32_t)MAGIC_SMOKE, usbsid_config.magic != MAGIC_SMOKE); printf("A %d %d\n", (int)usbsid_config.magic, (int)MAGIC_SMOKE); printf("A %d\n", usbsid_config.magic == MAGIC_SMOKE); + + printf("[USBSID_SID_MEMORY]\n"); + print_cfg(sid_memory, (numsids * 0x20)); break; default: break; @@ -542,65 +639,132 @@ void handle_config_request(uint8_t * buffer) void apply_config(void) { /* Debug logging */ - CFG("[CONFIG LOG START]\n"); - CFG("[USBSID VERSION]%s\n", project_version); - CFG("[CLOCK] %s @%d\n", ((int)usbsid_config.external_clock == 0 ? "Internal" : "External"), (int)usbsid_config.clock_rate); - CFG("[SOCKET ONE] %s as %s\n",((int)usbsid_config.socketOne.enabled == 1 ? "Enabled" : "Disabled"), ((int)usbsid_config.socketOne.dualsid == 1 ? "Dual SID" : "Single SID")); - CFG("[SOCKET TWO] %s as %s\n",((int)usbsid_config.socketTwo.enabled == 1 ? "Enabled" : "Disabled"), ((int)usbsid_config.socketTwo.dualsid == 1 ? "Dual SID" : "Single SID")); - CFG("[SOCKET TWO AS ONE] %s\n", ((int)usbsid_config.socketTwo.act_as_one == 1 ? "True" : "False")); - CFG("[LED] %s, Idle breathe? %s\n", ((int)usbsid_config.LED.enabled == 1 ? "Enabled" : "Disabled"), ((int)usbsid_config.LED.idle_breathe == 1 ? "True" : "False")); - CFG("[RGBLED] %s, Idle breathe? %s\n", ((int)usbsid_config.RGBLED.enabled == 1 ? "Enabled" : "Disabled"), ((int)usbsid_config.RGBLED.idle_breathe == 1 ? "True" : "False")); - CFG("[RGBLED BRIGHTNESS] %d\n", (int)usbsid_config.RGBLED.brightness); - CFG("[CDC] %s\n",((int)usbsid_config.Cdc.enabled == 1 ? "Enabled" : "Disabled")); - CFG("[WebUSB] %s\n",((int)usbsid_config.WebUSB.enabled == 1 ? "Enabled" : "Disabled")); - CFG("[Asid] %s\n",((int)usbsid_config.Asid.enabled == 1 ? "Enabled" : "Disabled")); - CFG("[Midi] %s\n",((int)usbsid_config.Midi.enabled == 1 ? "Enabled" : "Disabled")); - CFG("[CONFIG LOG END]\n"); - - CFG("[APPLY CONFIG START]\n"); + CFG("[PICO] PICO_PIO_VERSION = %d\n", PICO_PIO_VERSION); // pio.h PICO_PIO_VERSION + #if defined(PICO_DEFAULT_LED_PIN) + CFG("[PICO] PICO_DEFAULT_LED_PIN = %d\n", PICO_DEFAULT_LED_PIN); // pio.h PICO_PIO_VERSION + #elif defined(CYW43_WL_GPIO_LED_PIN) + CFG("[PICO] CYW43_WL_GPIO_LED_PIN = %d\n", CYW43_WL_GPIO_LED_PIN); // pio.h PICO_PIO_VERSION + #endif + CFG("[PICO] LED_PWM = %d\n", LED_PWM); // pio.h PICO_PIO_VERSION + CFG("[CONFIG] PRINT SETTINGS START\n"); + CFG("[CONFIG] [USBSID VERSION] %s\n", project_version); + + CFG("[CONFIG] [CLOCK] %s @%d\n", + ((int)usbsid_config.external_clock == 0 ? int_ext[0] : int_ext[1]), + (int)usbsid_config.clock_rate); + + CFG("[CONFIG] [SOCKET ONE] %s as %s\n", + ((int)usbsid_config.socketOne.enabled == 1 ? en_dis[0] : en_dis[1]), + ((int)usbsid_config.socketOne.dualsid == 1 ? single_dual[0] : single_dual[1])); + CFG("[CONFIG] [SOCKET ONE] CHIP TYPE: %s, CLONE TYPE: %s\n", + chiptypes[usbsid_config.socketOne.chiptype], + clonetypes[usbsid_config.socketOne.clonetype]); + CFG("[CONFIG] [SOCKET ONE] SID 1 TYPE: %s, SID 2 TYPE: %s\n", + sidtypes[usbsid_config.socketOne.sid1type], + sidtypes[usbsid_config.socketOne.sid2type]); + CFG("[CONFIG] [SOCKET TWO] %s as %s\n", + ((int)usbsid_config.socketTwo.enabled == 1 ? en_dis[0] : en_dis[1]), + ((int)usbsid_config.socketTwo.dualsid == 1 ? single_dual[0] : single_dual[1])); + CFG("[CONFIG] [SOCKET TWO] CHIP TYPE: %s, CLONE TYPE: %s\n", + chiptypes[usbsid_config.socketTwo.chiptype], + clonetypes[usbsid_config.socketTwo.clonetype]); + CFG("[CONFIG] [SOCKET TWO] SID 1 TYPE: %s, SID 2 TYPE: %s\n", + sidtypes[usbsid_config.socketTwo.sid1type], + sidtypes[usbsid_config.socketTwo.sid2type]); + CFG("[CONFIG] [SOCKET TWO AS ONE] %s\n", + ((int)usbsid_config.socketTwo.act_as_one == 1 ? true_false[0] : true_false[1])); + + CFG("[CONFIG] [LED] %s, Idle breathe? %s\n", + ((int)usbsid_config.LED.enabled == 1 ? en_dis[0] : en_dis[1]), + ((int)usbsid_config.LED.idle_breathe == 1 ? true_false[0] : true_false[1])); + CFG("[CONFIG] [RGBLED] %s, Idle breathe? %s\n", + ((int)usbsid_config.RGBLED.enabled == 1 ? en_dis[0] : en_dis[1]), + ((int)usbsid_config.RGBLED.idle_breathe == 1 ? true_false[0] : true_false[1])); + CFG("[CONFIG] [RGBLED SIDTOUSE] %d\n", + (int)usbsid_config.RGBLED.sid_to_use); + CFG("[CONFIG] [RGBLED BRIGHTNESS] %d\n", + (int)usbsid_config.RGBLED.brightness); + + CFG("[CONFIG] [CDC] %s\n", + ((int)usbsid_config.Cdc.enabled == 1 ? en_dis[0] : en_dis[1])); + CFG("[CONFIG] [WebUSB] %s\n", + ((int)usbsid_config.WebUSB.enabled == 1 ? en_dis[0] : en_dis[1])); + CFG("[CONFIG] [Asid] %s\n", + ((int)usbsid_config.Asid.enabled == 1 ? en_dis[0] : en_dis[1])); + CFG("[CONFIG] [Midi] %s\n", + ((int)usbsid_config.Midi.enabled == 1 ? en_dis[0] : en_dis[1])); + CFG("[CONFIG] PRINT SETTINGS END\n"); + + CFG("[CONFIG APPLY] START\n"); + + act_as_one = usbsid_config.socketTwo.act_as_one; + sock_one = usbsid_config.socketOne.enabled; sock_two = usbsid_config.socketTwo.enabled; - act_as_one = usbsid_config.socketTwo.act_as_one; + sids_one = (sock_one == true) ? (usbsid_config.socketOne.dualsid == true) ? 2 : 1 : 0; sids_two = (sock_two == true) ? (usbsid_config.socketTwo.dualsid == true) ? 2 : 1 : 0; numsids = (sids_one + sids_two); + CFG("[CONFIG] Applying socket settings\n"); + /* one == 0x00, two == 0x20, three == 0x40, four == 0x60 */ + if (act_as_one) { /* act-as-one enabled overrules all settings */ + CFG("[CONFIG] ACT AS ONE\n"); + one = two = 0; /* CS1 low, CS2 low */ + three = four = 0; /* CS1 low, CS2 low */ + } else { + if (sock_one && !sock_two) { /* SocketOne enabled, SocketTwo disabled */ + CFG("[CONFIG] sock_one enabled, sock_two disabled\n"); + one = 0b100; /* CS1 low, CS2 high */ + two = (sids_one == 2) ? 0b100 /* CS1 low, CS2 high */ + : 0b110; /* CS1 high, CS2 high */ + three = four = 0b110; /* CS1 high, CS2 high */ + } + if (!sock_one && sock_two) { /* SocketOne disabled, SocketTwo enabled */ + CFG("[CONFIG] sock_one disabled, sock_two enabled\n"); + one = 0b010; /* CS1 high, CS2 low */ + two = (sids_two == 2) ? 0b010 /* CS1 high, CS2 low */ + : 0b110; /* CS1 high, CS2 high */ + three = four = 0b110; /* CS1 high, CS2 high */ + } + if (sock_one && sock_two) { /* SocketOne enabled, SocketTwo enabled */ + CFG("[CONFIG] sock_one enabled, sock_two enabled\n"); + one = 0b100; /* CS1 low, CS2 high */ + two = (sids_one == 2) ? 0b100 /* CS1 low, CS2 high */ + : 0b110; /* CS1 high, CS2 high */ + three = 0b010; /* CS1 high, CS2 low */ + four = (sids_two == 2) ? 0b010 /* CS1 high, CS2 low */ + : 0b110; /* CS1 high, CS2 high */ + } + } + + CFG("[SOCK_ONE EN]%s [SOCK_TWO EN]%s [ACT_AS_ONE]%s\n[NO SIDS] [SOCK_ONE#]%d [SOCK_TWO#]%d [TOTAL#]%d\n[BUS] [ONE]%02x [TWO]%02x [THREE]%02x [FOUR]%02x\n", + (sock_one ? true_false[0] : true_false[1]), + (sock_two ? true_false[0] : true_false[1]), + (act_as_one ? true_false[0] : true_false[1]), + sids_one, sids_two, numsids, + one, two, three, four); + + CFG("[CONFIG] Applying RGBLED SID\n"); usbsid_config.RGBLED.sid_to_use /* Make sure all SIDs are used if sid to use is higher then the number of sids */ = (usbsid_config.RGBLED.sid_to_use > 2) && (numsids <= 2) ? 0 : usbsid_config.RGBLED.sid_to_use; - /* TODO: Not perfect yet ~ missing remaps for triple sid config settings */ - one = (act_as_one) - ? 0 // CS1 low, CS2 low - : (1 << 2); // CS1 low, CS2 high - two = (sock_two && numsids == 2) - ? (1 << 1) // CS1 high, CS2 low - : (1 << 2); // CS1 low, CS2 high - three = (numsids >= 3) || (sock_two && numsids == 2) - ? (1 << 1) // CS1 high, CS2 low - : (1 << 1) | (1 << 2); // CS1 high, CS2 high - four = (numsids == 4) - ? (1 << 1) // CS1 high, CS2 low - : (1 << 1) | (1 << 2); // CS1 high, CS2 high - - CFG("[CONFIG APPLIED]\n[ONE]%02x [TWO]%02x [THREE]%02x [FOUR]%02x\n[SOCK_ONE EN]%s [SOCK_TWO EN]%s [ACT_AS_ONE]%s\n[NO SIDS][S1#]%d [S2#]%d [T#]%d\n", - one, two, three, four, - (sock_one ? "True" : "False"), - (sock_two ? "True" : "False"), - (act_as_one ? "True" : "False"), - sids_one, sids_two, numsids); + CFG("[CONFIG APPLY] FINISHED\n"); } void detect_default_config(void) { - CFG("[IS DEFAULT CONFIG?] %s\n", (usbsid_config.default_config ? "True" : "False")); + CFG("[CONFIG DETECT DEFAULT] START\n"); + CFG("[IS DEFAULT CONFIG?] %s\n", + (usbsid_config.default_config ? true_false[0] : true_false[1])); if(usbsid_config.default_config == 1) { CFG("[DETECTED DEFAULT CONFIG]\n"); usbsid_config.default_config = 0; save_config(&usbsid_config); } - CFG("[CONFIG LOAD FINISHED]\n"); + CFG("[CONFIG DETECT DEFAULT] FINISHED\n"); } void verify_clockrate(void) diff --git a/src/config.h b/src/config.h index b3846ad..9b37785 100644 --- a/src/config.h +++ b/src/config.h @@ -55,7 +55,7 @@ #define MAGIC_SMOKE 19700101 /* DATEOFRELEASE */ #endif #ifndef PROJECT_VERSION -#define PROJECT_VERSION "0.2.3-BETA.20241208" /* Must be the same as in CMakeLists.txt */ +#define PROJECT_VERSION "0.2.3-BETA.20241220" /* Must be the same as in CMakeLists.txt */ #endif #ifdef PICO_DEFAULT_LED_PIN @@ -78,14 +78,20 @@ typedef struct Config { struct { bool enabled : 1; /* enable / disable this socket */ - bool dualsid : 1; /* enable / disable dual SID support for this socket */ - uint8_t sidtype; /* 0 = empty, 1 = SKPico or other clone, 2 = MOS6581, 3 = MOS8085 */ + bool dualsid : 1; /* enable / disable dual SID support for this socket (requires clone) */ + uint8_t chiptype; /* 0 = real, 1 = clone */ + uint8_t clonetype; /* 0 = disabled, 1 = SKPico, 2 = ARMSID, 3 = FPGASID, 4 = other */ + uint8_t sid1type; /* 0 = unknown, 1 = n/a, 2 = MOS8085, 3 = MOS6581 */ + uint8_t sid2type; /* 0 = unknown, 1 = FMopl, 2 = MOS8085, 3 = MOS6581 */ } socketOne; /* 1 */ struct { bool enabled : 1; /* enable / disable this socket */ - bool dualsid : 1; /* enable / disable dual SID support for this socket */ + bool dualsid : 1; /* enable / disable dual SID support for this socket (requires clone) */ bool act_as_one : 1; /* act as socket 1 */ - uint8_t sidtype; /* 0 = empty, 1 = SKPico or other clone, 2 = MOS6581, 3 = MOS8085 */ + uint8_t chiptype; /* 0 = real, 1 = clone */ + uint8_t clonetype; /* 0 = disabled, 1 = SKPico, 2 = ARMSID, 3 = FPGASID, 4 = other */ + uint8_t sid1type; /* 0 = unknown, 1 = n/a, 2 = MOS8085, 3 = MOS6581 */ + uint8_t sid2type; /* 0 = unknown, 1 = FMopl, 2 = MOS8085, 3 = MOS6581 */ } socketTwo; /* 2 */ struct { bool enabled : 1; diff --git a/src/globals.h b/src/globals.h index 7ace02d..ca8f303 100644 --- a/src/globals.h +++ b/src/globals.h @@ -35,6 +35,8 @@ /* Default includes */ #include +/* Helper macro for constraining a value within a range */ +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) /* USBSID command byte */ enum @@ -43,9 +45,11 @@ enum READ, /* 1 */ PAUSE, /* 2 */ RESET_SID, /* 3 */ - RESET_MCU, /* 4 */ - CLEAR_BUS, /* 5 */ - BOOTLOADER, /* 6 */ + DISABLE_SID, /* 4 */ + ENABLE_SID, /* 5 */ + CLEAR_BUS, /* 6 */ + RESET_MCU, /* 7 */ + BOOTLOADER, /* 8 */ }; /* USB data type */ diff --git a/src/gpio.c b/src/gpio.c index 1446e8c..181b3e6 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -38,10 +38,20 @@ extern int sock_one, sock_two, sids_one, sids_two, numsids, act_as_one; /* Init vars */ PIO bus_pio = pio0; -uint sm_control, sm_data, offset_control, offset_data; -int dma_tx_control, dma_tx_data, dma_rx_data; -uint16_t control_word; -uint32_t data_word, read_data, dir_mask; +static uint sm_control, offset_control; +static uint sm_data, offset_data; +static uint sm_clock, offset_clock; +static int dma_tx_control, dma_tx_data, dma_rx_data; +static uint16_t control_word; +static uint32_t data_word, read_data, dir_mask; + +/* Read GPIO macro + * + * The following 2 lines (var naming changed) are copied from SKPico code by frenetic + * see: https://github.com/frntc/SIDKick-pico + */ +register uint32_t b asm( "r10" ); +volatile const uint32_t *BUSState = &sio_hw->gpio_in; void init_gpio() @@ -93,25 +103,29 @@ void init_vu(void) void setup_piobus(void) { - /* float freq = (float)clock_get_hz(clk_sys) / (usbsid_config.clock_rate * 8) / 2; */ /* Clock frequency is 8 times the SID clock */ + float freq = (float)clock_get_hz(clk_sys) / (usbsid_config.clock_rate * 32) / 2; /* Clock frequency is 32 times the SID clock */ + CFG("[BUS CLK INIT] START\n"); + CFG("[PI CLK]@%dMHz [DIV]@%.2f [BUS CLK]@%.2f [CFG SID CLK]%d\n", ((int)clock_get_hz(clk_sys) / 1000 / 1000), freq, ((float)clock_get_hz(clk_sys) / freq / 2), (int)usbsid_config.clock_rate); { /* control bus */ offset_control = pio_add_program(bus_pio, &bus_control_program); - sm_control = pio_claim_unused_sm(bus_pio, true); + sm_control = 1; /* PIO0 SM1 */ + pio_sm_claim(bus_pio, sm_control); for (uint i = RW; i < CS2 + 1; ++i) pio_gpio_init(bus_pio, i); pio_sm_config c_control = bus_control_program_get_default_config(offset_control); sm_config_set_out_pins(&c_control, RW, 3); sm_config_set_in_pins(&c_control, D0); sm_config_set_jmp_pin(&c_control, RW); - /* sm_config_set_clkdiv(&c_control, freq); */ + sm_config_set_clkdiv(&c_control, freq); pio_sm_init(bus_pio, sm_control, offset_control, &c_control); pio_sm_set_enabled(bus_pio, sm_control, true); } { /* databus */ offset_data = pio_add_program(bus_pio, &data_bus_program); - sm_data = pio_claim_unused_sm(bus_pio, true); + sm_data = 2; /* PIO0 SM2 */ + pio_sm_claim(bus_pio, sm_data); for (uint i = D0; i < A5 + 1; ++i) { pio_gpio_init(bus_pio, i); } @@ -119,20 +133,21 @@ void setup_piobus(void) pio_sm_set_pindirs_with_mask(bus_pio, sm_data, PIO_PINDIRMASK, PIO_PINDIRMASK); /* WORKING */ sm_config_set_out_pins(&c_data, D0, A5 + 1); sm_config_set_fifo_join(&c_data, PIO_FIFO_JOIN_TX); - /* sm_config_set_clkdiv(&c_data, freq); */ + sm_config_set_clkdiv(&c_data, freq); pio_sm_init(bus_pio, sm_data, offset_data, &c_data); pio_sm_set_enabled(bus_pio, sm_data, true); } + + CFG("[BUS CLK INIT] FINISHED\n"); } void setup_dmachannels(void) -{ +{ /* NOTE: Fo not manually assign DMA channels, this causes a Panic on the PicoW */ + CFG("[DMA CHANNELS INIT] START\n"); { /* dma controlbus */ dma_tx_control = dma_claim_unused_channel(true); dma_channel_config tx_config_control = dma_channel_get_default_config(dma_tx_control); channel_config_set_transfer_data_size(&tx_config_control, DMA_SIZE_16); - channel_config_set_read_increment(&tx_config_control, true); - channel_config_set_write_increment(&tx_config_control, false); channel_config_set_dreq(&tx_config_control, pio_get_dreq(bus_pio, sm_control, true)); dma_channel_configure(dma_tx_control, &tx_config_control, &bus_pio->txf[sm_control], NULL, 1, false); } @@ -156,10 +171,25 @@ void setup_dmachannels(void) channel_config_set_dreq(&rx_config, pio_get_dreq(bus_pio, sm_control, false)); dma_channel_configure(dma_rx_data, &rx_config, NULL, &bus_pio->rxf[sm_control], 1, false); } + + CFG("[DMA CHANNELS INIT] FINISHED\n"); } +void sync_pios(void) +{ /* Sync PIO's */ + #if PICO_PIO_VERSION == 0 + CFG("[RESTART PIOS] Pico & Pico_w\n"); + pio_sm_restart(bus_pio, 0b111); + #elif PICO_PIO_VERSION > 0 // NOTE: rp2350 only + CFG("[SYNC PIOS] Pico2\n"); + pio_clkdiv_restart_sm_multi_mask(bus_pio, 0 /* 0b111 */, 0b111, 0); + #endif +} + + void restart_bus(void) { + CFG("[RESTART BUS START]\n"); /* disable databus rx dma */ dma_channel_unclaim(dma_rx_data); /* disable databus tx dma */ @@ -178,6 +208,47 @@ void restart_bus(void) setup_piobus(); /* start dma */ setup_dmachannels(); + /* sync pios */ + sync_pios(); + CFG("[RESTART BUS END]\n"); +} + +/* Detect clock signal */ +int detect_clocksignal(void) +{ + CFG("[DETECT CLOCK] START\n"); + int c = 0, r = 0; + gpio_init(PHI); + gpio_set_pulls(PHI, false, true); + for (int i = 0; i < 20; i++) { + b = *BUSState; /* read complete bus */ + // DBG("[BUS]0x%"PRIu32", 0b"PRINTF_BINARY_PATTERN_INT32"", b, PRINTF_BYTE_TO_BINARY_INT32(b)); + r |= c = (b & bPIN(PHI)) >> PHI; + // DBG(" [PHI2]%d [R]%d\r\n", c, r); + } + CFG("[RESULT] %d: %s\n", r, (r == 0 ? "INTERNAL CLOCK" : "EXTERNAL CLOCK")); + CFG("[DETECT CLOCK] END\n"); + return r; /* 1 if clock detected */ +} + +/* Init nMHz square wave output */ +void init_sidclock(void) +{ + float freq = (float)clock_get_hz(clk_sys) / usbsid_config.clock_rate / 2; + CFG("[SID CLK INIT] START\n"); + CFG("[PI CLK]@%dMHz [DIV]@%.2f [SID CLK]@%.2f [CFG SID CLK]%d\n", (int)clock_get_hz(clk_sys) / 1000 / 1000, freq, ((float)clock_get_hz(clk_sys) / freq / 2), (int)usbsid_config.clock_rate); + offset_clock = pio_add_program(bus_pio, &clock_program); + sm_clock = 0; /* PIO0 SM0 */ + pio_sm_claim(bus_pio, sm_clock); + clock_program_init(bus_pio, sm_clock, offset_clock, PHI, freq); + CFG("[SID CLK INIT] FINISHED\n"); +} + +/* De-init nMHz square wave output */ +void deinit_sidclock(void) +{ + CFG("[DE-INIT CLOCK]\n"); + clock_program_deinit(bus_pio, sm_clock, offset_clock, clock_program); } uint8_t __not_in_flash_func(bus_operation)(uint8_t command, uint8_t address, uint8_t data) @@ -274,9 +345,13 @@ void pause_sid(void) void reset_sid(void) { - disable_sid(); + /* disable_sid(); clear_bus(); - enable_sid(); + enable_sid(); */ + gpio_put(CS1, 1); + gpio_put(CS2, 1); + gpio_put(RES, 0); + gpio_put(RES, 1); } void clear_sid_registers(void) diff --git a/src/gpio.h b/src/gpio.h index cbd097a..1541f29 100644 --- a/src/gpio.h +++ b/src/gpio.h @@ -54,7 +54,7 @@ /* PIO */ #include "bus_control.pio.h" /* Busje komt zo! */ - +#include "clock.pio.h" /* Square wave generator */ /* Uart */ #define BAUD_RATE 115200 diff --git a/src/pio/bus_control.pio b/src/pio/bus_control.pio index e467aab..ad77af7 100644 --- a/src/pio/bus_control.pio +++ b/src/pio/bus_control.pio @@ -22,6 +22,24 @@ ; along with this program. If not, see . ; +; BUS clock = 32 * SID clock +; Example: +; 32MHz BUS clock @ 1MHz SID clock +; 32MHZ is 0.03125µs per cycle +; 32MHZ is 31.25ns per cycle +; 1MHz is 1µs per cycle +; 1MHz is 1000ns per cycle +; A 1MHz/1µs SID cycle _should_ contain 32 BUS cycles +; This _should_ mean that 1 command or NOP == 31.25ns +; +; Except? +; nop 26 waits 15 cycles to and including out pins +; nop 25 waits 15 cycles to and including out pins +; nop 24 waits 14 cycles to and including out pins +; nop 14 waits 9 cycles to and including out pins +; so 10 nops is 5 cycles? WTF!? +; + .define PUBLIC PHI 22 ; Bus control program @@ -29,20 +47,15 @@ .wrap_target pull block ; Pull data from FIFO wait 1 gpio PHI ; Wait for clock to go high - wait 0 gpio PHI ; Wait for clock to go low - nop [31] ; Wait for ~103ns + wait 0 gpio PHI [26] ; Wait for clock to go low out pins, 3 ; Set control pins (19-21) - wait 1 gpio PHI ; Wait for clock to go high - nop [31] ; Wait for ~103ns + wait 1 gpio PHI [24] ; Wait for clock to go high jmp pin read ; Jump to read if IN pin is high - nop [9] ; Wait for ~30ns jmp done ; Jump to done read: - nop [31] in pins, 8 ; Read data bus into isr push block ; Push isr to fifo done: - nop [9] ; Wait for ~30ns wait 0 gpio PHI ; Wait for clock to go low out pins, 3 ; Set control to next 3 bits from fifo .wrap @@ -50,14 +63,11 @@ done: ; Data and address bus program .program data_bus .wrap_target - pull block ; Pull data from FIFO - wait 1 gpio PHI ; Wait for clock to go high - wait 0 gpio PHI ; Wait for clock to go low - nop [31] ; Wait for ~103ns - out pins, 16 ; Set data bus pins - out pindirs 16 ; Set pin directions - wait 1 gpio PHI ; Wait for clock to go high - nop [31] ; Wait for ~103ns - nop [31] ; Wait for ~103ns - nop [9] ; Wait for ~30ns + pull block ; Pull data from FIFO + wait 1 gpio PHI ; Wait for clock to go high + wait 0 gpio PHI [26] ; Wait for clock to go low and throw in some nops + out pins, 16 ; Set data bus pins + out pindirs 16 ; Set pin directions + wait 1 gpio PHI ; Wait for clock to go high + wait 0 gpio PHI ; Wait for clock to go low .wrap diff --git a/src/sid.c b/src/sid.c index 58fc4b0..9c5214a 100644 --- a/src/sid.c +++ b/src/sid.c @@ -40,9 +40,13 @@ uint8_t waveforms[4] = { 16, 32, 64, 128 }; uint8_t detect_sid_version(uint8_t start_addr) /* Not working on real SIDS!? */ { bus_operation(0x10, (start_addr + 0x12), 0xFF); /* Set testbit in voice 3 control register to disable oscillator */ + sleep_ms(1); bus_operation(0x10, (start_addr + 0x0E), 0xFF); /* Set frequency in voice 3 to $ffff */ + sleep_ms(1); bus_operation(0x10, (start_addr + 0x0F), 0xFF); /* Set frequency in voice 3 to $ffff */ + sleep_ms(1); bus_operation(0x10, (start_addr + 0x12), 0x20); /* Set Sawtooth wave and gatebit OFF to start oscillator again */ + sleep_ms(1); uint8_t sidtype = bus_operation(0x11, (start_addr + 0x1B), 0x00); /* Accu now has different value depending on sid model (6581=3/8580=2) */ return sidtype; /* that is: Carry flag is set for 6581, and clear for 8580. */ } diff --git a/src/usbsid.c b/src/usbsid.c index 193b78c..a9e1e96 100644 --- a/src/usbsid.c +++ b/src/usbsid.c @@ -31,22 +31,26 @@ #include "sid.h" #include "logging.h" +/* util.c */ +extern long map(long x, long in_min, long in_max, long out_min, long out_max); +extern int randval(int min, int max); /* Init external vars */ static semaphore_t core1_init; /* Init vars */ +uint8_t __not_in_flash("usbsid_buffer") sid_memory[(0x20 * 4)] = {0}; /* 4x max */ uint8_t __not_in_flash("usbsid_buffer") read_buffer[MAX_BUFFER_SIZE]; uint8_t __not_in_flash("usbsid_buffer") write_buffer[MAX_BUFFER_SIZE]; int usb_connected = 0, usbdata = 0, pwm_value = 0, updown = 1; uint32_t cdcread = 0, cdcwrite = 0, webread = 0, webwrite = 0; -uint sm_clock, offset_clock; -uint8_t *cdc_itf, *wusb_itf; -uint16_t vu; +uint8_t *cdc_itf = 0, *wusb_itf = 0; +uint16_t vu = 0; uint32_t breathe_interval_ms = BREATHE_INTV; uint32_t start_ms = 0; char ntype = '0', dtype = '0', cdc = 'C', asid = 'A', midi = 'M', wusb = 'W'; bool web_serial_connected = false; +double /* cpu_mhz = 0, cpu_us = 0, */ clk_rate = 0, sidfrq = 0, frqpow = 0; /* Init var pointers for external use */ uint8_t (*write_buffer_p)[MAX_BUFFER_SIZE] = &write_buffer; @@ -64,14 +68,18 @@ extern void detect_default_config(void); extern void verify_clockrate(void); /* GPIO externals */ -extern PIO bus_pio; extern void init_gpio(void); extern void init_vu(void); extern void setup_piobus(void); extern void setup_dmachannels(void); +extern void sync_pios(void); +extern void init_sidclock(void); +extern int detect_clocksignal(void); extern void pause_sid(void); -extern void disable_sid(void); extern void reset_sid(void); +extern void enable_sid(void); +extern void disable_sid(void); +extern void clear_bus(void); extern uint8_t __not_in_flash_func(bus_operation)(uint8_t command, uint8_t address, uint8_t data); /* MCU externals */ @@ -139,14 +147,6 @@ const __not_in_flash("usbsid_data") unsigned char color_LUT[43][6][3] = }; #endif -/* Read GPIO macro - * - * The following 2 lines (var naming changed) are copied from SKPico code by frenetic - * see: https://github.com/frntc/SIDKick-pico - */ -register uint32_t b asm( "r10" ); -volatile const uint32_t *BUSState = &sio_hw->gpio_in; - /* WebUSB Description URL */ static const tusb_desc_webusb_url_t desc_url = { @@ -173,32 +173,6 @@ void reset_reason(void) #endif } -/* Detect clock signal */ -int detect_clock(void) -{ - int c = 0, r = 0; - gpio_init(PHI); - gpio_set_pulls(PHI, false, true); - for (int i = 0; i < 20; i++) { - b = *BUSState; /* read complete bus */ - DBG("[BUS]0x%"PRIu32", 0b"PRINTF_BINARY_PATTERN_INT32"", b, PRINTF_BYTE_TO_BINARY_INT32(b)); - r |= c = (b & bPIN(PHI)) >> PHI; - DBG(" [PHI2]%d [R]%d\r\n", c, r); - } - DBG("[RESULT]%d\r\n", r); - return r; /* 1 if clock detected */ -} - -int randval(int min, int max) -{ - return min + rand() / (RAND_MAX / (max - min + 1) + 1); -} - -long map(long x, long in_min, long in_max, long out_min, long out_max) -{ - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; -} - #if defined(USE_RGB) void put_pixel(uint32_t pixel_grb) { // pio_sm_put_blocking(pio_rgb, ws2812_sm, pixel_grb << 8u); @@ -230,22 +204,6 @@ void init_logging(void) #endif } -/* Init nMHz square wave output */ -void init_sidclock(void) -{ - float freq = (float)clock_get_hz(clk_sys) / usbsid_config.clock_rate / 2; - offset_clock = pio_add_program(bus_pio, &clock_program); - sm_clock = pio_claim_unused_sm(bus_pio, true); - clock_program_init(bus_pio, sm_clock, offset_clock, PHI, freq); - DBG("[CLK INIT] [PI CLK]@%dMHz [DIV]@%.2f [SID CLK]@%.2f [CFG]%d\n", (int)clock_get_hz(clk_sys) / 1000 / 1000, freq, ((float)clock_get_hz(clk_sys) / freq / 2), (int)usbsid_config.clock_rate); -} - -/* De-init nMHz square wave output */ -void deinit_sidclock(void) -{ - clock_program_deinit(bus_pio, sm_clock, offset_clock, clock_program); -} - /* Init the RGB LED pio */ void init_rgb(void) { @@ -253,7 +211,8 @@ void init_rgb(void) _rgb = randval(0, 5); r_ = g_ = b_ = 0; offset_ws2812 = pio_add_program(pio_rgb, &ws2812_program); - ws2812_sm = pio_claim_unused_sm(pio_rgb, true); + ws2812_sm = 0; /* PIO1 SM0 */ + pio_sm_claim(pio_rgb, ws2812_sm); ws2812_program_init(pio_rgb, ws2812_sm, offset_ws2812, 23, 800000, IS_RGBW); put_pixel(urgb_u32(0,0,0)); #endif @@ -291,6 +250,7 @@ void __not_in_flash_func(handle_buffer_task)(uint8_t * itf, uint32_t * n) read_buffer[1] = read_buffer[2]; read_buffer[2] = read_buffer[3]; case BYTES_EXPECTED: + usbdata = 1; IODBG("[%c][I]$%02x $%02x $%02x[RE]\r\n", dtype, read_buffer[0], read_buffer[1], read_buffer[2]); switch (read_buffer[0]) { case WRITE: @@ -318,6 +278,18 @@ void __not_in_flash_func(handle_buffer_task)(uint8_t * itf, uint32_t * n) DBG("[RESET_SID]\n"); reset_sid(); break; + case DISABLE_SID: + DBG("[DISABLE_SID]\n"); + disable_sid(); + break; + case ENABLE_SID: + DBG("[ENABLE_SID]\n"); + enable_sid(); + break; + case CLEAR_BUS: + DBG("[CLEAR_BUS]\n"); + clear_bus(); + break; case RESET_MCU: DBG("[RESET_MCU]\n"); mcu_reset(); @@ -336,10 +308,16 @@ void __not_in_flash_func(handle_buffer_task)(uint8_t * itf, uint32_t * n) CFG("\r\n"); handle_config_request(read_buffer); break; - case MAX_BUFFER_SIZE: /* No implementation yet */ - IODBG("[%c][MAX %d]", dtype, *n); - for (int i = 0; i < *n; i ++) IODBG("$%02x ", read_buffer[i]); - IODBG("\r\n"); + case MAX_BUFFER_SIZE: /* Cycled write buffer */ + // ISSUE: Not perfect yet! + usbdata = 1; + for (int i = 0; i < *n; i += 4) { + uint16_t cycles = (read_buffer[i + 2] | read_buffer[i + 3]); + uint64_t sleep_time = ((double)cycles * frqpow); + /* uint32_t delay_cycles = (sleep_time / cpu_us) - 3; */ + sleep_us(sleep_time - 2); + bus_operation(0x10, read_buffer[i], read_buffer[i + 1]); + } break; default: /* Nope not gonna handle that shit, just log it */ @@ -446,11 +424,12 @@ void led_vumeter_task(void) pwm_set_gpio_level(BUILTIN_LED, vu); } - MDBG("[%c:%d] [VOL]$%02x [PWM]$%04x | [V1] $%02X%02X %02X%02X %02X %02X %02X | [V2] $%02X%02X %02X%02X %02X %02X %02X | [V3] $%02X%02X %02X%02X %02X %02X %02X \n", - dtype, usbdata, sid_memory[0x18], vu, - sid_memory[0x00], sid_memory[0x01], sid_memory[0x02], sid_memory[0x03], sid_memory[0x04], sid_memory[0x05], sid_memory[0x06], - sid_memory[0x07], sid_memory[0x08], sid_memory[0x09], sid_memory[0x0A], sid_memory[0x0B], sid_memory[0x0C], sid_memory[0x0D], - sid_memory[0x0E], sid_memory[0x0F], sid_memory[0x10], sid_memory[0x11], sid_memory[0x12], sid_memory[0x13], sid_memory[0x14]); + MDBG("[%c:%d][PWM]$%04x[V1]$%02X%02X$%02X%02X$%02X$%02X$%02X[V2]$%02X%02X$%02X%02X$%02X$%02X$%02X[V3]$%02X%02X$%02X%02X$%02X$%02X$%02X[FC]$%02x%02x$%02x[VOL]$%02x\n", + dtype, usbdata, vu, + sid_memory[0x01], sid_memory[0x00], sid_memory[0x03], sid_memory[0x02], sid_memory[0x04], sid_memory[0x05], sid_memory[0x06], + sid_memory[0x08], sid_memory[0x07], sid_memory[0x0A], sid_memory[0x09], sid_memory[0x0B], sid_memory[0x0C], sid_memory[0x0D], + sid_memory[0x0F], sid_memory[0x0E], sid_memory[0x11], sid_memory[0x10], sid_memory[0x12], sid_memory[0x13], sid_memory[0x14], + sid_memory[0x16], sid_memory[0x15], sid_memory[0x17], sid_memory[0x18]); } #endif @@ -614,9 +593,9 @@ void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize) (void)buffer; (void)bufsize; - usbdata = 1, dtype = wusb; if (web_serial_connected) { /* vendor class has no connect check, thus use this */ wusb_itf = &itf; + usbdata = 1, dtype = wusb; webread = tud_vendor_n_read(*wusb_itf, &read_buffer, MAX_BUFFER_SIZE); tud_vendor_n_read_flush(*wusb_itf); handle_buffer_task(wusb_itf, &webread); @@ -692,7 +671,7 @@ void core1_main(void) /* Apply saved config to used vars */ apply_config(); /* Detect optional external crystal */ - if (detect_clock() == 0) { + if (detect_clocksignal() == 0) { usbsid_config.external_clock = false; gpio_deinit(PHI); /* Disable PHI as gpio */ init_sidclock(); @@ -707,6 +686,14 @@ void core1_main(void) memset(sid_memory, 0, sizeof sid_memory); /* Start the VU */ init_vu(); + + /* Init cycled write buffer vars */ + /* double cpu_mhz = (clock_get_hz(clk_sys) / 1000 / 1000); */ + /* double cpu_us = (1 / cpu_mhz); */ + clk_rate = usbsid_config.clock_rate; + sidfrq = (clk_rate / 1000 / 1000); + frqpow = (1 / sidfrq); + /* Release semaphore when core 1 is started */ sem_release(&core1_init); @@ -734,8 +721,13 @@ int main() { (void)desc_url; /* NOTE: Remove if going to use it */ + #if PICO_RP2040 /* System clock @ 125MHz */ set_sys_clock_pll(1500000000, 6, 2); + #elif PICO_RP2350 + /* System clock @ 150MHz */ + set_sys_clock_pll(1800000000, 6, 2); + #endif /* Init board */ board_init(); /* Init USB */ @@ -760,6 +752,8 @@ int main() init_gpio(); /* Init PIO */ setup_piobus(); + /* Sync PIOS */ + sync_pios(); /* Init DMA */ setup_dmachannels(); /* Init midi */ diff --git a/src/usbsid.h b/src/usbsid.h index beebc58..82ff453 100644 --- a/src/usbsid.h +++ b/src/usbsid.h @@ -44,9 +44,10 @@ /* Pico libs */ #include "pico/stdlib.h" -#include "pico/types.h" /* absolute_time_t */ -#include "pico/multicore.h" /* Multicore */ -#include "pico/sem.h" /* Semaphores */ +#include "pico/types.h" /* absolute_time_t */ +#include "pico/multicore.h" /* Multicore */ +#include "pico/sem.h" /* Semaphores */ +#include "pico/util/queue.h" /* Inter core queue */ /* Hardware api's */ #include "hardware/clocks.h" @@ -72,8 +73,7 @@ #include "tusb.h" /* Tiny USB stack */ #include "tusb_config.h" /* Tiny USB configuration */ -/* PIO */ -#include "clock.pio.h" /* Square wave generator */ +/* RGBLED */ #if defined(USE_RGB) #include "ws2812.pio.h" /* RGB led handler */ #endif diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..d029f50 --- /dev/null +++ b/src/util.c @@ -0,0 +1,38 @@ +/* + * USBSID-Pico is a RPi Pico (RP2040) based board for interfacing one or two + * MOS SID chips and/or hardware SID emulators over (WEB)USB with your computer, + * phone or ASID supporting player + * + * util.c + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * Copyright (c) 2024 LouD + * + * 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, version 2. + * + * 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. If not, see . + * + */ + +/* Pico libs */ +#include +#include "pico/stdlib.h" + +int randval(int min, int max) +{ + return min + rand() / (RAND_MAX / (max - min + 1) + 1); +} + +long map(long x, long in_min, long in_max, long out_min, long out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +}