From 53487358ff2a3bf7ca7593828bd4e004e867063c Mon Sep 17 00:00:00 2001 From: Wenting Zhang Date: Wed, 14 Feb 2024 22:50:33 -0500 Subject: [PATCH 1/3] Add dummy USB support --- fw/CMakeLists.txt | 10 ++- fw/config.h | 2 + fw/fw.c | 163 ++++++++++++++++++++--------------------- fw/tusb_config.h | 111 ++++++++++++++++++++++++++++ fw/usb_descriptors.c | 170 +++++++++++++++++++++++++++++++++++++++++++ fw/usb_descriptors.h | 37 ++++++++++ fw/usbapp.c | 80 ++++++++++++++++++++ fw/usbapp.h | 25 +++++++ 8 files changed, 515 insertions(+), 83 deletions(-) create mode 100644 fw/tusb_config.h create mode 100644 fw/usb_descriptors.c create mode 100644 fw/usb_descriptors.h create mode 100644 fw/usbapp.c create mode 100644 fw/usbapp.h diff --git a/fw/CMakeLists.txt b/fw/CMakeLists.txt index 153d023..535a3cd 100644 --- a/fw/CMakeLists.txt +++ b/fw/CMakeLists.txt @@ -35,10 +35,12 @@ add_executable(fw ptn3460.c tcpm_driver.c tps65185.c + usb_descriptors.c usb_mux.c usb_pd_driver.c usb_pd_policy.c usb_pd_protocol.c + usbapp.c utils.c ) @@ -46,10 +48,14 @@ pico_set_program_name(fw "fw") pico_set_program_version(fw "0.1") pico_enable_stdio_uart(fw 0) -pico_enable_stdio_usb(fw 1) +pico_enable_stdio_usb(fw 0) + +# Make sure TinyUSB can find tusb_config.h +target_include_directories(fw PUBLIC + ${CMAKE_CURRENT_LIST_DIR}) # Add the standard library to the build -target_link_libraries(fw pico_stdlib hardware_sleep) +target_link_libraries(fw pico_stdlib hardware_sleep tinyusb_device tinyusb_board) # Add any user requested libraries target_link_libraries(fw diff --git a/fw/config.h b/fw/config.h index 3b5f98e..f848d23 100644 --- a/fw/config.h +++ b/fw/config.h @@ -61,6 +61,8 @@ #define POWER_GPIO #define POWER_GPIO_VCOM_MEASURE #define INPUT_DVI +#define BOARD_HAS_BUTTON +#define BUTTON_GPIO 2 #else #error "Unknown board revision" #endif diff --git a/fw/fw.c b/fw/fw.c index 945e0da..7bcd02d 100644 --- a/fw/fw.c +++ b/fw/fw.c @@ -1,5 +1,5 @@ // -// Copyright 2022 Wenting Zhang +// Copyright 2024 Wenting Zhang // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -33,6 +33,10 @@ #include "fpga.h" #include "edid.h" #include "caster.h" +#include "usbapp.h" + +void osd_task(void); // OSD handling task +void usb_pd_task(void); // USB PD handling task int main() { @@ -43,28 +47,50 @@ int main() printf("\n"); printf("Glider\n"); - // TODO: Unify both input options -#if defined(INPUT_DVI) power_init(); + +#ifdef INPUT_DVI edid_init(); - power_enable(true); +#endif - //sleep_run_from_xosc(); - //sleep_goto_dormant_until_edge_high(8); - // https://ghubcoder.github.io/posts/awaking-the-pico/ +#ifdef INPUT_TYPEC + int result = tcpm_init(0); + if (result) + fatal("Failed to initialize TCPC\n"); - fpga_init(); + // int cc1, cc2; + // tcpc_config[0].drv->get_cc(0, &cc1, &cc2); + // printf("CC status %d %d\n", cc1, cc2); - //sleep_ms(5000); - //caster_init(); + ptn3460_init(); + pd_init(0); +#endif - gpio_init(2); - gpio_set_dir(2, GPIO_IN); - gpio_pull_up(2); +#ifdef BOARD_HAS_BUTTON + gpio_init(BUTTON_GPIO); + gpio_set_dir(BUTTON_GPIO, GPIO_IN); + gpio_pull_up(BUTTON_GPIO); +#endif - int mode_max = 6; - int mode = 1; - UPDATE_MODE modes[6] = { + //fpga_init(); + //power_enable(true); + + usbapp_init(); + + while (1) { + osd_task(); + usb_pd_task(); + usbapp_task(); + } + + return 0; +} + +void osd_task(void) { +#ifdef BOARD_HAS_BUTTON + static int mode_max = 6; + static int mode = 1; + const UPDATE_MODE modes[6] = { UM_FAST_MONO_NO_DITHER, UM_FAST_MONO_BAYER, UM_FAST_MONO_BLUE_NOISE, @@ -73,73 +99,48 @@ int main() UM_AUTO_LUT_ERROR_DIFFUSION }; - while (1) { - // - if (gpio_get(2) == 0) { - sleep_ms(20); - if (gpio_get(2) == 0) { - int i = 0; - while (gpio_get(2) == 0) { - i++; - sleep_ms(1); - if (i > 500) - break; - } - if (i > 500) { - // Long press, clear screen - caster_redraw(0,0,1600,1200); - } - else { - // Short press, switch mode - mode++; - if (mode >= mode_max) mode = 0; - caster_setmode(0,0,1600,1200,modes[mode]); - } - while (gpio_get(2) == 0); + if (gpio_get(BUTTON_GPIO) == 0) { + sleep_ms(20); + if (gpio_get(BUTTON_GPIO) == 0) { + int i = 0; + while (gpio_get(BUTTON_GPIO) == 0) { + i++; + sleep_ms(1); + if (i > 500) + break; } - while (gpio_get(2) == 0); - } - } -#elif defined(INPUT_TYPEC) - int result = tcpm_init(0); - if (result) - fatal("Failed to initialize TCPC\n"); - - int cc1, cc2; - tcpc_config[0].drv->get_cc(0, &cc1, &cc2); - printf("CC status %d %d\n", cc1, cc2); - - gpio_init(10); - gpio_put(10, 0); - gpio_set_dir(10, GPIO_OUT); - - power_init(); - power_enable(true); // TODO: should be dependent on DP signal valid - fpga_init(); - - ptn3460_init(); - pd_init(0); - sleep_ms(50); - - extern int dp_enabled; - bool hpd_sent = false; - bool dp_valid = false; - - while (1) { - // TODO: Implement interrupt - fusb302_tcpc_alert(0); - pd_run_state_machine(0); - if (dp_enabled && !hpd_sent && !pd_is_vdm_busy(0)) { - printf("DP enabled\n"); - pd_send_hpd(0, hpd_high); - hpd_sent = true; - } - if (dp_valid != ptn3460_is_valid()) { - dp_valid = ptn3460_is_valid(); - printf(dp_valid ? "Input is valid\n" : "Input is invalid\n"); + if (i > 500) { + // Long press, clear screen + caster_redraw(0,0,1600,1200); + } + else { + // Short press, switch mode + mode++; + if (mode >= mode_max) mode = 0; + caster_setmode(0,0,1600,1200,modes[mode]); + } + while (gpio_get(BUTTON_GPIO) == 0); } + while (gpio_get(BUTTON_GPIO) == 0); } #endif - - return 0; +} + +void usb_pd_task(void) { + extern int dp_enabled; + static bool hpd_sent = false; + static bool dp_valid = false; + + // TODO: Implement interrupt + fusb302_tcpc_alert(0); + pd_run_state_machine(0); + if (dp_enabled && !hpd_sent && !pd_is_vdm_busy(0)) { + printf("DP enabled\n"); + pd_send_hpd(0, hpd_high); + hpd_sent = true; + } + if (dp_valid != ptn3460_is_valid()) { + dp_valid = ptn3460_is_valid(); + printf(dp_valid ? "Input is valid\n" : "Input is invalid\n"); + } } diff --git a/fw/tusb_config.h b/fw/tusb_config.h new file mode 100644 index 0000000..868424e --- /dev/null +++ b/fw/tusb_config.h @@ -0,0 +1,111 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by board.mk +#ifndef CFG_TUSB_MCU + #error CFG_TUSB_MCU must be defined +#endif + +// RHPort number used for device can be defined by board.mk, default to port 0 +#ifndef BOARD_DEVICE_RHPORT_NUM + #define BOARD_DEVICE_RHPORT_NUM 0 +#endif + +// RHPort max operational speed can defined by board.mk +// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed +#ifndef BOARD_DEVICE_RHPORT_SPEED + #if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ + CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X) + #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED + #else + #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED + #endif +#endif + +// Device mode with rhport and speed defined by board.mk +#if BOARD_DEVICE_RHPORT_NUM == 0 + #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) +#elif BOARD_DEVICE_RHPORT_NUM == 1 + #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) +#else + #error "Incorrect RHPort configuration" +#endif + +#ifndef CFG_TUSB_OS +#define CFG_TUSB_OS OPT_OS_NONE +#endif + +// CFG_TUSB_DEBUG is defined by compiler in DEBUG build +// #define CFG_TUSB_DEBUG 0 + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- + +#ifndef CFG_TUD_ENDPOINT0_SIZE +#define CFG_TUD_ENDPOINT0_SIZE 64 +#endif + +//------------- CLASS -------------// +#define CFG_TUD_HID 1 +#define CFG_TUD_CDC 0 +#define CFG_TUD_MSC 0 +#define CFG_TUD_MIDI 0 +#define CFG_TUD_VENDOR 0 + +// HID buffer size Should be sufficient to hold ID (if any) + Data +#define CFG_TUD_HID_EP_BUFSIZE 16 + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/fw/usb_descriptors.c b/fw/usb_descriptors.c new file mode 100644 index 0000000..cd48384 --- /dev/null +++ b/fw/usb_descriptors.c @@ -0,0 +1,170 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "tusb.h" + +/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. + * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. + * + * Auto ProductID layout's Bitmap: + * [MSB] HID | MSC | CDC [LSB] + */ +#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) +#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ + _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) + +//--------------------------------------------------------------------+ +// Device Descriptors +//--------------------------------------------------------------------+ +tusb_desc_device_t const desc_device = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = 0xCafe, + .idProduct = USB_PID, + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +uint8_t const * tud_descriptor_device_cb(void) +{ + return (uint8_t const *) &desc_device; +} + +//--------------------------------------------------------------------+ +// HID Report Descriptor +//--------------------------------------------------------------------+ + +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_GENERIC_INOUT(CFG_TUD_HID_EP_BUFSIZE) +}; + +// Invoked when received GET HID REPORT DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) +{ + (void) itf; + return desc_hid_report; +} + +//--------------------------------------------------------------------+ +// Configuration Descriptor +//--------------------------------------------------------------------+ + +enum +{ + ITF_NUM_HID, + ITF_NUM_TOTAL +}; + +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN) + +#define EPNUM_HID 0x01 + +uint8_t const desc_configuration[] = +{ + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), + + // Interface number, string index, protocol, report descriptor len, EP Out & In address, size & polling interval + TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10) +}; + +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + return desc_configuration; +} + +//--------------------------------------------------------------------+ +// String Descriptors +//--------------------------------------------------------------------+ + +// array of pointer to string descriptors +char const* string_desc_arr [] = +{ + (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) + "TinyUSB", // 1: Manufacturer + "TinyUSB Device", // 2: Product + "123456", // 3: Serials, should use chip ID +}; + +static uint16_t _desc_str[32]; + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ + (void) langid; + + uint8_t chr_count; + + if ( index == 0) + { + memcpy(&_desc_str[1], string_desc_arr[0], 2); + chr_count = 1; + }else + { + // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. + // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors + + if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; + + const char* str = string_desc_arr[index]; + + // Cap at max char + chr_count = (uint8_t) strlen(str); + if ( chr_count > 31 ) chr_count = 31; + + // Convert ASCII string into UTF-16 + for(uint8_t i=0; i +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +#include +#include "pico/stdlib.h" +#include "fpga.h" +#include "caster.h" +#include "tusb.h" +#include "usb_descriptors.h" + +void usbapp_init(void) { + tusb_init(); +} + +// Device callbacks +void tud_mount_cb(void) { + +} + +void tud_umount_cb(void) { + +} + +void tud_suspend_cb(bool remote_wakeup_en) { + // TODO: Force Suspend +} + +void tud_resume_cb(void) { + +} + +// Invoked when received GET_REPORT control request +// Application must fill buffer report's content and return its length. +// Return zero will cause the stack to STALL request +uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) +{ + // TODO not Implemented + (void) instance; + (void) report_id; + (void) report_type; + (void) buffer; + (void) reqlen; + + return 0; +} + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) +{ + // This example doesn't use multiple report and report ID + (void) instance; + (void) report_id; + (void) report_type; + + // echo back anything we received from host + tud_hid_report(0, buffer, bufsize); +} + +void usbapp_task(void) { + tud_task(); +} diff --git a/fw/usbapp.h b/fw/usbapp.h new file mode 100644 index 0000000..52ab326 --- /dev/null +++ b/fw/usbapp.h @@ -0,0 +1,25 @@ +// +// Copyright 2024 Wenting Zhang +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +#pragma once + +void usbapp_init(void); +void usbapp_task(void); From 2380384e70a26c91c814f6a8532fe7022da2397b Mon Sep 17 00:00:00 2001 From: Wenting Zhang Date: Thu, 15 Feb 2024 00:28:30 -0500 Subject: [PATCH 2/3] Initial USB command implementation --- fw/caster.c | 19 +++++++++++++------ fw/caster.h | 7 ++++--- fw/fpga.c | 15 ++++++++++++--- fw/fpga.h | 2 +- fw/usbapp.h | 7 +++++++ 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/fw/caster.c b/fw/caster.c index 8044ab6..0d4e012 100644 --- a/fw/caster.c +++ b/fw/caster.c @@ -56,27 +56,33 @@ void caster_init(void) { // fpga_write_reg8(CSR_CONTROL, 1); // Enable refresh } -void caster_load_waveform(uint8_t *waveform, uint8_t frames) { - wait(); +static uint8_t is_busy() { + uint8_t status = fpga_write_reg8(CSR_STATUS, 0x00); + return !!(status & STATUS_OP_QUEUE); +} + +uint8_t caster_load_waveform(uint8_t *waveform, uint8_t frames) { fpga_write_reg8(CSR_LUT_FRAME, 0); // Reset value before loading fpga_write_reg16(CSR_LUT_ADDR, 0); fpga_write_bulk(CSR_LUT_WR, waveform, WAVEFORM_SIZE); waveform_frames = frames; + return 0; } -void caster_redraw(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { - wait(); +uint8_t caster_redraw(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + if (is_busy()) return 1; fpga_write_reg16(CSR_OP_LEFT, x0); fpga_write_reg16(CSR_OP_TOP, y0); fpga_write_reg16(CSR_OP_RIGHT, x1); fpga_write_reg16(CSR_OP_BOTTOM, y1); fpga_write_reg8(CSR_OP_LENGTH, get_update_frames()); fpga_write_reg8(CSR_OP_CMD, OP_EXT_REDRAW); + return 0; } -void caster_setmode(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, +uint8_t caster_setmode(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, UPDATE_MODE mode) { - wait(); + if (is_busy()) return 1; fpga_write_reg16(CSR_OP_LEFT, x0); fpga_write_reg16(CSR_OP_TOP, y0); fpga_write_reg16(CSR_OP_RIGHT, x1); @@ -84,4 +90,5 @@ void caster_setmode(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, fpga_write_reg8(CSR_OP_LENGTH, get_update_frames()); fpga_write_reg8(CSR_OP_PARAM, (uint8_t)mode); fpga_write_reg8(CSR_OP_CMD, OP_EXT_SETMODE); + return 0; } \ No newline at end of file diff --git a/fw/caster.h b/fw/caster.h index 7fbc4aa..cfc25b5 100644 --- a/fw/caster.h +++ b/fw/caster.h @@ -52,6 +52,7 @@ #define CSR_CFG_FBYTES_B2 27 #define CSR_CFG_FBYTES_B1 28 #define CSR_CFG_FBYTES_B0 29 +#define CSR_STATUS 32 // Alias for 16bit registers #define CSR_LUT_ADDR CSR_LUT_ADDR_HI #define CSR_OP_LEFT CSR_OP_LEFT_HI @@ -89,7 +90,7 @@ typedef enum { } UPDATE_MODE; void caster_init(void); -void caster_load_waveform(uint8_t *waveform, uint8_t frames); -void caster_redraw(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); -void caster_setmode(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, +uint8_t caster_load_waveform(uint8_t *waveform, uint8_t frames); +uint8_t caster_redraw(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); +uint8_t caster_setmode(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, UPDATE_MODE mode); diff --git a/fw/fpga.c b/fw/fpga.c index 6913bba..fa7a243 100644 --- a/fw/fpga.c +++ b/fw/fpga.c @@ -60,22 +60,31 @@ static void fpga_send_byte(uint8_t byte) { } } -static void fpga_send_byte_slow(uint8_t byte) { +static uint8_t fpga_send_byte_slow(uint8_t byte) { + uint8_t rxbyte; for (int i = 0; i < 8; i++) { gpio_put(FPGA_MOSI, byte & 0x80); delay_loop(20); + rxbyte |= gpio_get(FPGA_MISO); gpio_put(FPGA_SCLK, 1); delay_loop(20); byte <<= 1; + rxbyte <<= 1; gpio_put(FPGA_SCLK, 0); } + delay_loop(20); + rxbyte |= gpio_get(FPGA_MISO); + gpio_put(FPGA_SCLK, 1); + return rxbyte; } -void fpga_write_reg8(uint8_t addr, uint8_t val) { +uint8_t fpga_write_reg8(uint8_t addr, uint8_t val) { + uint8_t oldval; gpio_put(FPGA_CS, 0); fpga_send_byte_slow(addr); - fpga_send_byte_slow(val); + oldval = fpga_send_byte_slow(val); gpio_put(FPGA_CS, 1); + return oldval; } void fpga_write_reg16(uint8_t addr, uint16_t val) { diff --git a/fw/fpga.h b/fw/fpga.h index f932a80..8acc106 100644 --- a/fw/fpga.h +++ b/fw/fpga.h @@ -24,6 +24,6 @@ void fpga_init(void); void fpga_suspend(void); void fpga_resume(void); -void fpga_write_reg8(uint8_t addr, uint8_t val); +uint8_t fpga_write_reg8(uint8_t addr, uint8_t val); void fpga_write_reg16(uint8_t addr, uint16_t val); void fpga_write_bulk(uint8_t addr, uint8_t *buf, int length); \ No newline at end of file diff --git a/fw/usbapp.h b/fw/usbapp.h index 52ab326..1227f71 100644 --- a/fw/usbapp.h +++ b/fw/usbapp.h @@ -21,5 +21,12 @@ // #pragma once +#define USBCMD_RESET 0x00 +#define USBCMD_POWERDOWN 0x01 +#define USBCMD_POWERUP 0x02 +#define USBCMD_SETINPUT 0x03 +#define USBCMD_REDRAW 0x04 +#define USBCMD_SETMODE 0x05 + void usbapp_init(void); void usbapp_task(void); From 8690fcd1d92789f14c22b547969ebe0f01bf050b Mon Sep 17 00:00:00 2001 From: Wenting Zhang Date: Fri, 5 Apr 2024 11:30:08 -0400 Subject: [PATCH 3/3] USB interface proof-of-concept implementation --- fw/caster.c | 8 +++++++- fw/caster.h | 2 ++ fw/usbapp.c | 38 ++++++++++++++++++++++++++++++++++++-- util/usb_example.py | 26 ++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 util/usb_example.py diff --git a/fw/caster.c b/fw/caster.c index 0d4e012..d5bac10 100644 --- a/fw/caster.c +++ b/fw/caster.c @@ -91,4 +91,10 @@ uint8_t caster_setmode(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, fpga_write_reg8(CSR_OP_PARAM, (uint8_t)mode); fpga_write_reg8(CSR_OP_CMD, OP_EXT_SETMODE); return 0; -} \ No newline at end of file +} + +uint8_t caster_setinput(uint8_t input_src) { + if (is_busy()) return 1; + fpga_write_reg8(CSR_CFG_IN_SRC, input_src); + return 0; +} diff --git a/fw/caster.h b/fw/caster.h index cfc25b5..49188c7 100644 --- a/fw/caster.h +++ b/fw/caster.h @@ -52,6 +52,7 @@ #define CSR_CFG_FBYTES_B2 27 #define CSR_CFG_FBYTES_B1 28 #define CSR_CFG_FBYTES_B0 29 +#define CSR_CFG_IN_SRC 30 #define CSR_STATUS 32 // Alias for 16bit registers #define CSR_LUT_ADDR CSR_LUT_ADDR_HI @@ -94,3 +95,4 @@ uint8_t caster_load_waveform(uint8_t *waveform, uint8_t frames); uint8_t caster_redraw(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); uint8_t caster_setmode(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, UPDATE_MODE mode); +uint8_t caster_setinput(uint8_t input_src); diff --git a/fw/usbapp.c b/fw/usbapp.c index f982e4a..a2d83ea 100644 --- a/fw/usbapp.c +++ b/fw/usbapp.c @@ -71,8 +71,42 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_ (void) report_id; (void) report_type; - // echo back anything we received from host - tud_hid_report(0, buffer, bufsize); + // Process the request + uint16_t cmd = (buffer[1] << 8) | buffer[0]; + uint16_t param = (buffer[3] << 8) | buffer[2]; + uint16_t x0 = (buffer[5] << 8) | buffer[4]; + uint16_t y0 = (buffer[7] << 8) | buffer[6]; + uint16_t x1 = (buffer[9] << 8) | buffer[8]; + uint16_t y1 = (buffer[11] << 8) | buffer[10]; + uint16_t id = (buffer[13] << 8) | buffer[12]; + uint16_t chksum = (buffer[15] << 8) | buffer[14]; + uint8_t retval = 1; + switch (buffer[0]) { + case USBCMD_RESET: + // reset system + (*((volatile uint32_t*)(PPB_BASE + 0x0ED0C))) = 0x5FA0004; // Reset via NVIC + break; + case USBCMD_POWERDOWN: + // TODO + break; + case USBCMD_POWERUP: + // TODO + break; + case USBCMD_SETINPUT: + retval = caster_setinput((uint8_t)param); + break; + case USBCMD_REDRAW: + retval = caster_redraw(x0, y0, x1, y1); + break; + case USBCMD_SETMODE: + retval = caster_setmode(x0, y0, x1, y1, (UPDATE_MODE)param); + break; + } + + uint8_t txbuf[1]; + txbuf[0] = retval; + + tud_hid_report(0, txbuf, 1); } void usbapp_task(void) { diff --git a/util/usb_example.py b/util/usb_example.py new file mode 100644 index 0000000..f1edfff --- /dev/null +++ b/util/usb_example.py @@ -0,0 +1,26 @@ +# Install python3 HID package https://pypi.org/project/hid/ +import hid +import struct + +vid = 0xcafe +pid = 0x4004 + +dev = hid.Device(vid, pid) + +if not dev: + print("Unable to open device") + exit() + +cmd = 0x00 +param = 0x00 +x0 = 0 +y0 = 0 +x1 = 1600 - 1 +y1 = 1200 - 1 +pid = 0 +chksum = 0 + +str_out = struct.pack('>h>h>h>h>h>h>h>h', cmd, param, x0, y0, x1, y1, pid, chksum) +dev.write(str_out) +str_in = dev.read(1) +print("Received from HID Device:", str_in, '\n')