diff --git a/src/globals.h b/src/globals.h index 698333a..258ee99 100644 --- a/src/globals.h +++ b/src/globals.h @@ -41,17 +41,33 @@ /* USBSID command byte */ enum { - WRITE = 0, /* 0 */ - READ, /* 1 */ - PAUSE, /* 2 */ - RESET_SID, /* 3 */ - DISABLE_SID, /* 4 */ - ENABLE_SID, /* 5 */ - CLEAR_BUS, /* 6 */ - RESET_MCU, /* 7 */ - BOOTLOADER, /* 8 */ - MUTE, /* 9 */ - UNMUTE, /* 10 */ + PACKET_TYPE = 0xC0, /* 0b11000000 ~ 192 */ + BYTE_MASK = 0x3F, /* 0b111111 ~ 63 */ + COMMAND_MASK = 0x1F, /* 0b11111 ~ 31 */ + + /* BYTE 0 */ + /* Top 2 bits */ + WRITE = 0, /* 0b0 ~ 0x00 */ + READ = 1, /* 0b1 ~ 0x40 */ + CYCLED_WRITE = 2, /* 0b10 ~ 0x80 */ + COMMAND = 3, /* 0b11 ~ 0xC0 */ + /* Lower 6 bits for byte count */ + /* Lower 6 bits for Commands */ + PAUSE = 10, /* 0b1010 ~ 0x0A */ + UNPAUSE = 11, /* 0b1011 ~ 0x0B */ + MUTE = 12, /* 0b1100 ~ 0x0C */ + UNMUTE = 13, /* 0b1101 ~ 0x0D */ + RESET_SID = 14, /* 0b1110 ~ 0x0E */ + DISABLE_SID = 15, /* 0b1111 ~ 0x0F */ + ENABLE_SID = 16, /* 0b10000 ~ 0x10 */ + CLEAR_BUS = 17, /* 0b10001 ~ 0x11 */ + CONFIG = 18, /* 0b10010 ~ 0x12 */ + RESET_MCU = 19, /* 0b10011 ~ 0x13 */ + BOOTLOADER = 20, /* 0b10100 ~ 0x14 */ + + /* GPIO COMMANDS */ + G_PAUSE = 2, + G_CLEAR_BUS = 3, }; /* USB data type */ diff --git a/src/gpio.c b/src/gpio.c index 2305dfb..58e98dc 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -303,11 +303,11 @@ uint8_t __not_in_flash_func(bus_operation)(uint8_t command, uint8_t address, uin pio_sm_exec(bus_pio, sm_control, pio_encode_irq_set(false, 4)); /* Preset the statemachine IRQ to not wait for a 1 */ pio_sm_exec(bus_pio, sm_data, pio_encode_irq_set(false, 5)); /* Preset the statemachine IRQ to not wait for a 1 */ switch (command & 0x0F) { - case PAUSE: + case G_PAUSE: control_word = 0b110110; dma_channel_set_read_addr(dma_tx_control, &control_word, true); /* Control lines RW, CS1 & CS2 DMA transfer */ break; - case CLEAR_BUS: + case G_CLEAR_BUS: dir_mask = 0b1111111111111111; data_word = (dir_mask << 16) | 0x0; dma_channel_set_read_addr(dma_tx_data, &data_word, true); /* Data & Address DMA transfer */ @@ -350,12 +350,12 @@ uint8_t __not_in_flash_func(bus_operation)(uint8_t command, uint8_t address, uin dma_channel_wait_for_finish_blocking(dma_rx_data); GPIODBG("[R]$%08x 0b"PRINTF_BINARY_PATTERN_INT32" $%04x 0b"PRINTF_BINARY_PATTERN_INT16"\r\n", read_data, PRINTF_BYTE_TO_BINARY_INT32(read_data), control_word, PRINTF_BYTE_TO_BINARY_INT16(control_word)); return (read_data >> 24) & 0xFF; - case PAUSE: + case G_PAUSE: case WRITE: dma_channel_wait_for_finish_blocking(dma_tx_control); GPIODBG("[W]$%08x 0b"PRINTF_BINARY_PATTERN_INT32" $%04x 0b"PRINTF_BINARY_PATTERN_INT16"\r\n", data_word, PRINTF_BYTE_TO_BINARY_INT32(data_word), control_word, PRINTF_BYTE_TO_BINARY_INT16(control_word)); return 0; - case CLEAR_BUS: + case G_CLEAR_BUS: /* don't wait, just fall through */ default: return 0; @@ -399,18 +399,24 @@ void __not_in_flash_func(cycled_bus_operation)(uint8_t address, uint8_t data, ui void unmute_sid(void) { + DBG("[UNMUTE] "); for (int i = 0; i < numsids; i++) { if ((volume_state[i] & 0xF) == 0) volume_state[i] = (volume_state[i] & 0xF0) | 0x0E; bus_operation((0x10 | WRITE), ((0x20 * i) + 0x18), volume_state[i]); /* Volume back */ + DBG("[%d] 0x%02X ", i, volume_state[i]); } + DBG("\n"); } void mute_sid(void) { + DBG("[MUTE] "); for (int i = 0; i < numsids; i++) { volume_state[i] = sid_memory[((0x20 * i) + 0x18)]; bus_operation((0x10 | WRITE), ((0x20 * i) + 0x18), (volume_state[i] & 0xF0)); /* Volume to 0 */ + DBG("[%d] 0x%02X ", i, volume_state[i]); } + DBG("\n"); } void enable_sid(void) @@ -431,15 +437,22 @@ void disable_sid(void) void clear_bus(void) { - bus_operation((0x10 | CLEAR_BUS), 0x0, 0x0); + bus_operation((0x10 | G_CLEAR_BUS), 0x0, 0x0); } void pause_sid(void) { + bus_operation((0x10 | G_PAUSE), 0x0, 0x0); +} + +void pause_sid_withmute(void) +{ + DBG("[PAUSE STATE PRE] %d\n", paused_state); if (paused_state == 0) mute_sid(); if (paused_state == 1) unmute_sid(); - bus_operation((0x10 | PAUSE), 0x0, 0x0); + bus_operation((0x10 | G_PAUSE), 0x0, 0x0); paused_state = !paused_state; + DBG("[PAUSE STATE POST] %d\n", paused_state); } void reset_sid(void) @@ -453,6 +466,9 @@ void reset_sid(void) void reset_sid_registers(void) { + paused_state = 0; + gpio_put(CS1, 1); + gpio_put(CS2, 1); gpio_put(RES, 0); sleep_us(10); gpio_put(RES, 1); diff --git a/src/pio/bus_control.pio b/src/pio/bus_control.pio index 680e0d4..e1b14d7 100644 --- a/src/pio/bus_control.pio +++ b/src/pio/bus_control.pio @@ -46,43 +46,40 @@ ; Delay counter program .program delay_timer -.side_set 1 opt .wrap_target - pull block side 1 ; Pull data from FIFO - out x 16 side 1 ; Move data into scratch register x + pull block ; Pull data from FIFO + out x 16 ; Move data into scratch register x delay: - wait 1 gpio PHI side 1 ; Wait for clock to go high - wait 0 gpio PHI side 0 ; Wait for clock to go low + wait 1 gpio PHI ; Wait for clock to go high + wait 0 gpio PHI ; Wait for clock to go low jmp x-- delay ; Decrease x and restart count - irq set BUSIRQ side 0 ; Set IRQ and continue - irq wait DATAIRQ side 0 ; Set IRQ and wait for its release + irq set BUSIRQ ; Set IRQ and continue + irq wait DATAIRQ ; Set IRQ and wait for its release .wrap ; Bus control program .program bus_control .wrap_target - pull block ; Pull data from FIFO - wait 1 irq BUSIRQ ; Wait for IRQ signal - ; wait 1 gpio PHI ; Wait for clock to go high ; ISSUE: For async this is shit, for sync this is great - wait 0 gpio PHI [26] ; Wait for clock to go low - out pins, 3 ; Set control pins (19-21) - wait 1 gpio PHI [24] ; Wait for clock to go high - jmp pin read ; Jump to read if IN pin is high - jmp done ; Jump to done if write and wait + pull block ; Pull data from FIFO + wait 1 irq BUSIRQ ; Wait for IRQ signal + wait 0 gpio PHI [26] ; Wait for clock to go low + out pins, 3 ; Set control pins (19-21) + wait 1 gpio PHI [24] ; Wait for clock to go high + jmp pin read ; Jump to read if IN pin is high + jmp done ; Jump to done if write and wait read: - in pins, 8 ; Read data bus into isr - push block ; Push isr to fifo + in pins, 8 ; Read data bus into isr + push block ; Push isr to fifo done: - out pins, 3 ; Set control to next 3 bits from fifo - wait 0 gpio PHI ; Wait for clock to go low + out pins, 3 ; Set control to next 3 bits from fifo + wait 0 gpio PHI ; Wait for clock to go low .wrap ; Data and address bus program .program data_bus .wrap_target pull block ; Pull data from FIFO - wait 1 irq DATAIRQ ; Wait for data irq signal - ; wait 1 gpio PHI ; Wait for clock to go high ; ISSUE: For async this is shit, for sync this is great + wait 1 irq DATAIRQ ; Wait for data irq signal ~ should trigger exactly 1 cycle after datairq wait 0 gpio PHI [26] ; Wait for clock to go low out pins, 16 ; Set data bus pins out pindirs 16 ; Set pin directions diff --git a/src/tusb_config.h b/src/tusb_config.h index 8e19b9c..01acb51 100644 --- a/src/tusb_config.h +++ b/src/tusb_config.h @@ -111,20 +111,20 @@ #define CFG_TUD_VENDOR 1 // CDC Endpoint transfer buffer size, more is faster -#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) // Even at 512KB only 64KB will be used // CDC FIFO size of TX and RX -#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) // Even at 512KB only 64KB will be used +#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) // Even at 512KB only 64KB will be used // MIDI FIFO size of TX and RX -#define CFG_TUD_MIDI_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -#define CFG_TUD_MIDI_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#define CFG_TUD_MIDI_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) // Even at 512KB only 64KB will be used +#define CFG_TUD_MIDI_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) // Even at 512KB only 64KB will be used // Vendor FIFO size of TX and RX // If not configured vendor endpoints will not be buffered -#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) // Even at 512KB only 64KB will be used +#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) // Even at 512KB only 64KB will be used #ifdef __cplusplus diff --git a/src/usbsid.c b/src/usbsid.c index 130697d..fb509ba 100644 --- a/src/usbsid.c +++ b/src/usbsid.c @@ -40,8 +40,10 @@ 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") sid_buffer[MAX_BUFFER_SIZE]; uint8_t __not_in_flash("usbsid_buffer") read_buffer[MAX_BUFFER_SIZE]; uint8_t __not_in_flash("usbsid_buffer") write_buffer[MAX_BUFFER_SIZE]; +uint8_t __not_in_flash("usbsid_buffer") config_buffer[5]; int usb_connected = 0, usbdata = 0, pwm_value = 0, updown = 1; uint32_t cdcread = 0, cdcwrite = 0, webread = 0, webwrite = 0; uint8_t *cdc_itf = 0, *wusb_itf = 0; @@ -76,9 +78,11 @@ extern void sync_pios(void); extern void init_sidclock(void); extern int detect_clocksignal(void); extern void pause_sid(void); +extern void pause_sid_withmute(void); extern void mute_sid(void); extern void unmute_sid(void); extern void reset_sid(void); +extern void reset_sid_registers(void); extern void enable_sid(void); extern void disable_sid(void); extern void clear_bus(void); @@ -247,91 +251,96 @@ void webserial_write(uint8_t * itf, uint32_t n) /* Process received usb data */ void __not_in_flash_func(handle_buffer_task)(uint8_t * itf, uint32_t * n) -{ /* BUG: PICO_W IS BROKEN ATM! */ - switch (*n) { - case BACKWARD_BYTES: /* For backward compatability */ - 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: - bus_operation(0x10, read_buffer[1], read_buffer[2]); /* write the address and value to the SID */ - break; - case READ: - write_buffer[0] = bus_operation((0x10 | READ), read_buffer[1], read_buffer[2]); /* write the address to the SID and read the data back */ - switch (dtype) { /* write the result to the USB client */ - case 'C': - cdc_write(itf, BYTES_TO_SEND); - break; - case 'W': - webserial_write(itf, BYTES_TO_SEND); - break; - default: - IODBG("[WRITE ERROR]%c\r\n", dtype); - break; - } - break; - case PAUSE: - DBG("[PAUSE_SID]\n"); - pause_sid(); - break; - case MUTE: - DBG("[MUTE_SID]\n"); - mute_sid(); - break; - case UNMUTE: - DBG("[UNMUTE_SID]\n"); - unmute_sid(); - break; - case RESET_SID: - 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(); - break; - case BOOTLOADER: - DBG("[BOOTLOADER]\n"); - mcu_jump_to_bootloader(); - break; - default: - break; - } - break; - case CONFIG_BYTES: - CFG("[%c][CFG %d] ", dtype, *n); - for (int i = 0; i < *n; i ++) CFG("$%02x ", read_buffer[i]); - CFG("\r\n"); - handle_config_request(read_buffer); - break; - case MAX_BUFFER_SIZE: /* Cycled write buffer */ +{ + usbdata = 1; + uint8_t command = ((sid_buffer[0] & PACKET_TYPE) >> 6); + uint8_t subcommand = (sid_buffer[0] & COMMAND_MASK); + uint8_t n_bytes = (sid_buffer[0] & BYTE_MASK); + + if (command == CYCLED_WRITE) { + n_bytes = (n_bytes == 0) ? 4 : n_bytes; /* if byte count is zero, this is a single write packet */ + for (int i = 1; i <= n_bytes; i += 4) { usbdata = 1; - for (int i = 0; i < *n; i += 4) { - cycled_bus_operation(read_buffer[i], read_buffer[i + 1], (read_buffer[i + 2] << 8 | read_buffer[i + 3])); + if (sid_buffer[i] == 0xFF && sid_buffer[i + 1] == 0xF0 && sid_buffer[i + 2] == 0xFF && sid_buffer[i + 3] == 0xFF) { + /* EXPERIMENTAL ~ NOT WORKING YET */ + reset_sid(); + return; + }; + cycled_bus_operation(sid_buffer[i], sid_buffer[i + 1], (sid_buffer[i + 2] << 8 | sid_buffer[i + 3])); + }; + return; + }; + if (command == WRITE) { + n_bytes = (n_bytes == 0) ? 2 : n_bytes; /* if byte count is zero, this is a single write packet */ + for (int i = 1; i <= n_bytes; i += 2) { + bus_operation(0x10, sid_buffer[i], sid_buffer[i + 1]); /* write the address and value to the SID */ + }; + return; + }; + if (command == READ) { /* READING CAN ONLY HANDLE ONE AT A TIME, PERIOD. */ + write_buffer[0] = bus_operation((0x10 | READ), sid_buffer[1], sid_buffer[2]); /* write the address to the SID and read the data back */ + switch (dtype) { /* write the result to the USB client */ + case 'C': + cdc_write(itf, BYTES_TO_SEND); + break; + case 'W': + webserial_write(itf, BYTES_TO_SEND); + break; + default: + IODBG("[WRITE ERROR]%c\r\n", dtype); + break; + }; + return; + }; + if (command == COMMAND) { + switch (subcommand) { + case PAUSE: + DBG("[PAUSE_SID]\n"); + pause_sid(); + break; + case MUTE: + DBG("[MUTE_SID]\n"); + mute_sid(); + break; + case UNMUTE: + DBG("[UNMUTE_SID]\n"); + unmute_sid(); + break; + case RESET_SID: + DBG("[RESET_SID]\n"); + if (sid_buffer[1] == 0) reset_sid(); + if (sid_buffer[1] == 1) reset_sid_registers(); + 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 CONFIG: + DBG("[CONFIG]\n"); + memcpy(config_buffer, (sid_buffer + 1), 5); + handle_config_request(config_buffer); + memset(config_buffer, 0, count_of(config_buffer)); + break; + case RESET_MCU: + DBG("[RESET_MCU]\n"); + mcu_reset(); + break; + case BOOTLOADER: + DBG("[BOOTLOADER]\n"); + mcu_jump_to_bootloader(); + break; + default: + break; } - break; - default: - /* Nope not gonna handle that shit, just log it */ - DBG("[%c][DEFAULT %d]", dtype, *n); - for (int i = 0; i < *n; i ++) DBG("$%02x ", read_buffer[i]); - DBG("\r\n"); - break; - } + }; } @@ -526,7 +535,10 @@ void tud_cdc_rx_cb(uint8_t itf) vu = vu == 0 ? 100 : vu; /* NOTICE: Testfix for core1 setting dtype to 0 */ cdcread = tud_cdc_n_read(*cdc_itf, &read_buffer, MAX_BUFFER_SIZE); /* Read data from client */ tud_cdc_n_read_flush(*cdc_itf); + memcpy(sid_buffer, read_buffer, cdcread); handle_buffer_task(cdc_itf, &cdcread); + memset(read_buffer, 0, count_of(read_buffer)); + memset(sid_buffer, 0, count_of(sid_buffer)); } void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) @@ -604,7 +616,10 @@ void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize) usbdata = 1, dtype = wusb; webread = tud_vendor_n_read(*wusb_itf, &read_buffer, MAX_BUFFER_SIZE); tud_vendor_n_read_flush(*wusb_itf); + memcpy(sid_buffer, read_buffer, webread); handle_buffer_task(wusb_itf, &webread); + memset(read_buffer, 0, count_of(read_buffer)); + memset(sid_buffer, 0, count_of(sid_buffer)); } } diff --git a/src/usbsid.h b/src/usbsid.h index 83089f1..c6aea3d 100644 --- a/src/usbsid.h +++ b/src/usbsid.h @@ -78,45 +78,41 @@ #include "ws2812.pio.h" /* RGB led handler */ #endif - -/* Maximum incoming and outgoing buffer size - * +/* Maximum incoming and outgoing USB (CDC/WebUSB) buffer size * NOTE: 64 byte zero padded packets take longer to process - */ -#define MAX_BUFFER_SIZE 64 - -/* Incoming USB (CDC/WebUSB) data buffer * - * 3 bytes: - * Byte 0 ~ command byte - * Byte 1 ~ address byte - * Byte 2 ~ data byte + * Incoming Data buffer write example + * 3 bytes minimum, 63 bytes maximum + * Byte 0 ~ command byte (see globals.h) + * Byte 1 ~ address byte + * Byte 2 ~ data byte + * Byte n+ ~ repetition of byte 1 and 2 * - */ -#define BYTES_EXPECTED 3 - -/* Backwards compatible incoming USB (CDC/WebUSB) data buffer + * Incoming Data buffer with clock cycles write example + * 5 bytes minimum, 61 bytes maximum + * Byte 0 ~ command byte (see globals.h) + * Byte 1 ~ address low byte + * Byte 2 ~ data byte + * Byte 3 ~ clock cycles high byte + * Byte 4 ~ clock cycles low byte + * Byte n+ ~ repetition of byte 1, 2, 3 and 4 + * + * Incoming Command buffer example + * 2 bytes, trailing bytes will be ignored + * Byte 0 ~ command byte (see globals.h) + * Byte 1 ~ optional command argument * - * 4 bytes: - * Byte 0 ~ command byte - * Byte 1 ~ address high byte - * Byte 2 ~ address low byte - * Byte 3 ~ data byte + * Incoming Config data buffer command example + * 5 bytes, trailing bytes will be ignored + * Byte 0 ~ command byte (see globals.h) + * Byte 1 ~ config command + * Byte 2 ~ struct setting e.g. socketOne or clock_rate + * Byte 3 ~ setting entry e.g. dualsid + * Byte 4 ~ new value + * Byte 5 ~ reserved * */ -#define BACKWARD_BYTES 4 - -/* Incoming Config data buffer - * - * 5 bytes: - * Byte 0 ~ command - * Byte 1 ~ struct setting e.g. socketOne or clock_rate - * Byte 2 ~ setting entry e.g. dualsid - * Byte 3 ~ new value - * Byte 4 ~ reserved - * - */ -#define CONFIG_BYTES 5 +#define MAX_BUFFER_SIZE 64 /* Outgoing USB (CDC/WebUSB) data buffer *