diff options
20 files changed, 3149 insertions, 1 deletions
diff --git a/examples/baremetal/msp430f5529/msp430f5529.qbs b/examples/baremetal/msp430f5529/msp430f5529.qbs index 7f9799208..f4a6f95b9 100644 --- a/examples/baremetal/msp430f5529/msp430f5529.qbs +++ b/examples/baremetal/msp430f5529/msp430f5529.qbs @@ -53,6 +53,7 @@ import qbs Project { name: "Examples for msp430f5529 board" references: [ - "redblink/redblink.qbs" + "redblink/redblink.qbs", + "nes-gamepads/nes-gamepads.qbs" ] } diff --git a/examples/baremetal/msp430f5529/nes-gamepads/README.md b/examples/baremetal/msp430f5529/nes-gamepads/README.md new file mode 100644 index 000000000..442bb587a --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/README.md @@ -0,0 +1,36 @@ +This example demonstrates how to build a bare-metal application using +different MSP430 toolchains. It is designed for the MSP-EXP430F5529LP +target board (based on msp430f5529 chip): + +* http://www.ti.com/tool/MSP-EXP430F5529LP + +It implements a USB HID device that connects two 8-buttons NES +(Dendy) gamepads to a PC. The gamepads are connected to the +msp430f5529 chip as follows: + +1. CLK - it is an output clock signal which generates by chip from + the port 6, pin 0 (P6.0). This pin should be connected to the CLK + inputs for both gamepads. + +2. DATA1 - it is an input data signal which comes to chip on the + the port 6, pin 1 (P6.1). This pin should be connected to the DATA + output from the gamepad #1. + +3. DATA2 - it is an input data signal which comes to chip on the + the port 6, pin 2 (P6.2). This pin should be connected to the DATA + output from the gamepad #2. + +4. LATCH - it is an output clock signal which generates by chip from + the port 6, pin 3 (P6.3). This pin should be connected to the LATCH + inputs for both gamepads. + +Actual schematic and pinouts depends on an used gamepads (with 7, 9 +or other pins connectors) and a development boards. + +Also, do not forget to connect the +3.3V and GND wires to the gamepads. +Then it is possible to play 8-bit NES games using various PC simulators. + +The following toolchains are supported: + + * IAR Embedded Workbench + * GCC diff --git a/examples/baremetal/msp430f5529/nes-gamepads/gamepads.ld b/examples/baremetal/msp430f5529/nes-gamepads/gamepads.ld new file mode 100644 index 000000000..a3906a474 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/gamepads.ld @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +g_setupdat = 0x2380; /* Setup packet block address. */ + +g_ep0 = 0x0920; /* Input ep0 configuration address. */ +g_ep0_in_buf = 0x2378; /* Input ep0 buffer address. */ + +g_ep1_in = 0x23C8; /* Input ep1 configuration address. */ +g_ep1_in_xbuf = 0x1C80; /* Ep1 X-buffer address. */ diff --git a/examples/baremetal/msp430f5529/nes-gamepads/gpio.c b/examples/baremetal/msp430f5529/nes-gamepads/gpio.c new file mode 100644 index 000000000..b5e58bc7c --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/gpio.c @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hwdefs.h" +#include "gpio.h" + +enum { INVALID_ADDRESS = 0xFFFF }; + +static uint16_t gpio_port_address_get(enum gpio_port port) +{ + switch (port) { + case GPIO_PORT_P1: + return P1_BASE; + case GPIO_PORT_P2: + return P2_BASE; + case GPIO_PORT_P3: + return P3_BASE; + case GPIO_PORT_P4: + return P4_BASE; + case GPIO_PORT_P5: + return P5_BASE; + case GPIO_PORT_P6: + return P6_BASE; + case GPIO_PORT_P7: + return P7_BASE; + case GPIO_PORT_P8: + return P8_BASE; + case GPIO_PORT_PJ: + return PJ_BASE; + default: + break; + } + return INVALID_ADDRESS; +} + +static uint16_t gpio_pins_adjust(enum gpio_port port, uint16_t pins) +{ + if ((port & 1) ^ 1) + pins <<= 8; + return pins; +} + +void gpio_pins_set_as_out(enum gpio_port port, uint16_t pins) +{ + const uint16_t base_address = gpio_port_address_get(port); + if (base_address == INVALID_ADDRESS) + return; + pins = gpio_pins_adjust(port, pins); + HWREG16(base_address + OFS_PASEL) &= ~pins; + HWREG16(base_address + OFS_PADIR) |= pins; +} + +void gpio_pins_set_as_in(enum gpio_port port, uint16_t pins) +{ + const uint16_t base_address = gpio_port_address_get(port); + if (base_address == INVALID_ADDRESS) + return; + pins = gpio_pins_adjust(port, pins); + HWREG16(base_address + OFS_PASEL) &= ~pins; + HWREG16(base_address + OFS_PADIR) &= ~pins; + HWREG16(base_address + OFS_PAREN) &= ~pins; +} + +void gpio_pins_set_as_pf_out(enum gpio_port port, uint16_t pins) +{ + const uint16_t base_address = gpio_port_address_get(port); + if (base_address == INVALID_ADDRESS) + return; + pins = gpio_pins_adjust(port, pins); + HWREG16(base_address + OFS_PADIR) |= pins; + HWREG16(base_address + OFS_PASEL) |= pins; +} + +void gpio_pins_set_as_pf_in(enum gpio_port port, uint16_t pins) +{ + const uint16_t base_address = gpio_port_address_get(port); + if (base_address == INVALID_ADDRESS) + return; + pins = gpio_pins_adjust(port, pins); + HWREG16(base_address + OFS_PADIR) &= ~pins; + HWREG16(base_address + OFS_PASEL) |= pins; +} + +void gpio_pins_set_high(enum gpio_port port, + uint16_t pins) +{ + const uint16_t base_address = gpio_port_address_get(port); + if (base_address == INVALID_ADDRESS) + return; + pins = gpio_pins_adjust(port, pins); + HWREG16(base_address + OFS_PAOUT) |= pins; +} + +void gpio_pins_set_low(enum gpio_port port, uint16_t pins) +{ + const uint16_t base_address = gpio_port_address_get(port); + if (base_address == INVALID_ADDRESS) + return; + pins = gpio_pins_adjust(port, pins); + HWREG16(base_address + OFS_PAOUT) &= ~pins; +} + +void gpio_pins_toggle(enum gpio_port port, uint16_t pins) +{ + const uint16_t base_address = gpio_port_address_get(port); + if (base_address == INVALID_ADDRESS) + return; + pins = gpio_pins_adjust(port, pins); + HWREG16(base_address + OFS_PAOUT) ^= pins; +} + +enum gpio_pin_status gpio_pin_get(enum gpio_port port, uint16_t pins) +{ + const uint16_t base_address = gpio_port_address_get(port); + if (base_address == INVALID_ADDRESS) + return GPIO_INPUT_PIN_LOW; + pins = gpio_pins_adjust(port, pins); + const uint16_t value = HWREG16(base_address + OFS_PAIN) & pins; + return (value > 0) ? GPIO_INPUT_PIN_HIGH : GPIO_INPUT_PIN_LOW; +} diff --git a/examples/baremetal/msp430f5529/nes-gamepads/gpio.h b/examples/baremetal/msp430f5529/nes-gamepads/gpio.h new file mode 100644 index 000000000..d69a543b5 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/gpio.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MSP430_GPIO_H +#define MSP430_GPIO_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +enum gpio_port { + GPIO_PORT_P1 = 1, + GPIO_PORT_P2 = 2, + GPIO_PORT_P3 = 3, + GPIO_PORT_P4 = 4, + GPIO_PORT_P5 = 5, + GPIO_PORT_P6 = 6, + GPIO_PORT_P7 = 7, + GPIO_PORT_P8 = 8, + GPIO_PORT_PJ = 13, +}; + +enum gpio_pin { + GPIO_PIN0 = 0x0001, + GPIO_PIN1 = 0x0002, + GPIO_PIN2 = 0x0004, + GPIO_PIN3 = 0x0008, + GPIO_PIN4 = 0x0010, + GPIO_PIN5 = 0x0020, + GPIO_PIN6 = 0x0040, + GPIO_PIN7 = 0x0080, + GPIO_PIN8 = 0x0100, + GPIO_PIN9 = 0x0200, + GPIO_PIN10 = 0x0400, + GPIO_PIN11 = 0x0800, + GPIO_PIN12 = 0x1000, + GPIO_PIN13 = 0x2000, + GPIO_PIN14 = 0x4000, + GPIO_PIN15 = 0x8000, +}; + +enum gpio_pin_status { + GPIO_INPUT_PIN_HIGH = 0x01, + GPIO_INPUT_PIN_LOW = 0x00 +}; + +void gpio_pins_set_as_out(enum gpio_port port, uint16_t pins); +void gpio_pins_set_as_in(enum gpio_port port, uint16_t pins); +void gpio_pins_set_as_pf_out(enum gpio_port port, uint16_t pins); +void gpio_pins_set_as_pf_in(enum gpio_port port, uint16_t pins); +void gpio_pins_set_high(enum gpio_port port, uint16_t pins); +void gpio_pins_set_low(enum gpio_port port, uint16_t pins); +void gpio_pins_toggle(enum gpio_port port, uint16_t pins); + +enum gpio_pin_status gpio_pin_get(enum gpio_port port, uint16_t pins); + +#ifdef __cplusplus +} +#endif + +#endif // MSP430_GPIO_H diff --git a/examples/baremetal/msp430f5529/nes-gamepads/hid.h b/examples/baremetal/msp430f5529/nes-gamepads/hid.h new file mode 100644 index 000000000..1307301dc --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/hid.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MSP430_HID_H +#define MSP430_HID_H + +#include <stdbool.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +enum hid_constants { + HID_CONFIG_NUMBER = 1, // Number of valid configuration. + HID_IFACE_NUMBER = 0, // Number of valid interface. + HID_ALT_IFACE_NUMBER = 0, // Number of valid alternate interface. + HID_EP_IN = 0x81 // Active end point address. +}; + +enum hid_gamepad_id { + HID_REPORT_ID_GAMEPAD1 = 1, + HID_REPORT_ID_GAMEPAD2 = 2 +}; + +enum { + HID_REPORTS_COUNT = 2, + HID_REPORT_BITS_COUNT = 8 +}; + +void hid_ep0_init(void); + +// Called only in interrupt context. +void hid_ep0_setup_handler(void); +void hid_ep0_in_handler(void); + +void hid_ep0_in_nak(void); +void hid_ep0_in_stall(void); +void hid_ep0_in_clear(void); +bool hid_ep0_in_is_stalled(void); + +void hid_ep0_out_nak(void); +void hid_ep0_out_stall(void); +void hid_ep0_out_clear(void); + +const uint8_t *hid_ep0_desc_get(uint8_t type, uint16_t *length); + +uint8_t hid_ep0_setup_bm_request_type_get(void); +uint8_t hid_ep0_setup_request_get(void); +uint8_t hid_ep0_setup_lvalue_get(void); +uint8_t hid_ep0_setup_hvalue_get(void); +uint8_t hid_ep0_setup_lindex_get(void); +uint8_t hid_ep0_setup_hindex_get(void); + +void hid_ep0_enumerated_set(bool enumerated); +bool hid_ep0_is_enumerated(void); + +void hid_ep1_init(void); +void hid_ep1_task(void); + +void hid_ep1_in_stall(void); +void hid_ep1_in_unstall(void); +bool hid_ep1_in_is_stalled(void); + +#ifdef __cplusplus +} +#endif + +#endif // MSP430_HID_H diff --git a/examples/baremetal/msp430f5529/nes-gamepads/hiddesc.c b/examples/baremetal/msp430f5529/nes-gamepads/hiddesc.c new file mode 100644 index 000000000..eb391d6c0 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/hiddesc.c @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hid.h" +#include "usb.h" + +#include <stdint.h> + +#define usb_word_msb_get(word) \ + (uint8_t)(((uint16_t)(word) >> 8) & 0xFF) +#define usb_word_lsb_get(word) \ + (uint8_t)((uint16_t)(word) & 0xFF) + +enum usb_bcd_version { + SPEC_BCD_VERSION = 0x0200, + DEVICE_BCD_VERSION = 0x1234, + HID_BCD_VERSION = 0x0111 +}; + +enum usb_ids { + DEVICE_VID = 0xFFFF, + DEVICE_PID = 0xFFFF +}; + +enum usb_lang_id { + LANG_ID = 0x0409 +}; + +enum usb_descriptor_string_index { + DESC_LANGID_STRING_INDEX = 0, + DESC_MFG_STRING_INDEX, + DESC_PRODUCT_STRING_INDEX, + DESC_SERIAL_STRING_INDEX +}; + +enum usb_descr_length { + // Standard length. + DESC_DEVICE_LEN = 18, + DESC_DEVICE_QUAL_LEN = 10, + DESC_CONF_LEN = 9, + DESC_OTHER_SPEED_CONF_LEN = 9, + DESC_INTERFACE_LEN = 9, + DESC_HID_LEN = 9, + DESCR_HID_REP_LEN = 56, + DESC_ENDPOINT_LEN = 7, + + // Total length. + DESC_DEVICE_TOTAL_LEN = DESC_DEVICE_LEN, + DESC_DEVICE_QUAL_TOTAL_LEN = DESC_DEVICE_QUAL_LEN, + DESC_CONF_TOTAL_LEN = DESC_CONF_LEN + DESC_INTERFACE_LEN + DESC_HID_LEN + DESC_ENDPOINT_LEN, + DESC_OTHER_SPEED_CONF_TOTAL_LEN = DESC_OTHER_SPEED_CONF_LEN + DESC_INTERFACE_LEN, + DESCR_HID_REP_TOTAL_LEN = DESCR_HID_REP_LEN +}; + +enum usb_descr_attributes { + // Attributes (b7 - buspwr, b6 - selfpwr, b5 - rwu). + USB_DESC_ATTRIBUTES = 0xA0, + // 100 mA (div 2). + USB_DESC_POWER_CONSUMPTION = 50 +}; + +enum usb_descr_numbers { + USB_DESC_CONFIG_COUNT = 1 +}; + +static const uint8_t g_hid_report_desc[DESCR_HID_REP_TOTAL_LEN] = { + // Pad #1 configuration. + 0x05, 0x01, // Usage page (Generic Desktop). + 0x09, 0x05, // Usage (Game Pad). + 0xa1, 0x01, // Collection (Application). + 0xa1, 0x00, // Collection (Physical). + 0x85, HID_REPORT_ID_GAMEPAD1, // Report id (1). + 0x05, 0x09, // Usage page (Button). + 0x19, 0x01, // Usage minimum (Button 1). + 0x29, 0x08, // Usage maximum (Button 8). + 0x15, 0x00, // Logical minimum (0). + 0x25, 0x01, // Logical maximum (1). + 0x95, HID_REPORT_BITS_COUNT, // Report count (8). + 0x75, 0x01, // Report size (1). + 0x81, 0x02, // Input (Data,Var,Abs). + 0xc0, // End collection. + 0xc0, // End collection. + // Pad #2 configuration. + 0x05, 0x01, // Usage page (Generic Desktop). + 0x09, 0x05, // Usage (Game Pad). + 0xa1, 0x01, // Collection (Application). + 0xa1, 0x00, // Collection (Physical). + 0x85, HID_REPORT_ID_GAMEPAD2, // Report id (2). + 0x05, 0x09, // Usage page (Button). + 0x19, 0x01, // Usage minimum (Button 1). + 0x29, 0x08, // Usage maximum (Button 8). + 0x15, 0x00, // Logical minimum (0). + 0x25, 0x01, // Logical maximum (1). + 0x95, HID_REPORT_BITS_COUNT, // Report count (8). + 0x75, 0x01, // Report size (1). + 0x81, 0x02, // Input (Data,Var,Abs). + 0xc0, // End collection + 0xc0 // End collection. +}; + +static const uint8_t g_device_desc[DESC_DEVICE_TOTAL_LEN] = { + DESC_DEVICE_LEN, // Descriptor length. + DESC_DEVICE, // Descriptor type. + usb_word_lsb_get(SPEC_BCD_VERSION), // USB BCD version, lo. + usb_word_msb_get(SPEC_BCD_VERSION), // USB BCD version, hi. + 0x00, // Device class. + 0x00, // Device sub-class. + 0x00, // Device protocol. + EP0_MAX_PACKET_SIZE, // Maximum packet size (ep0 size). + usb_word_lsb_get(DEVICE_VID), // Vendor ID, lo. + usb_word_msb_get(DEVICE_VID), // Vendor ID, hi. + usb_word_lsb_get(DEVICE_PID), // Product ID, lo. + usb_word_msb_get(DEVICE_PID), // Product ID, hi. + usb_word_lsb_get(DEVICE_BCD_VERSION), // Device BCD version, lo. + usb_word_msb_get(DEVICE_BCD_VERSION), // Device BCD version, hi. + DESC_MFG_STRING_INDEX, + DESC_PRODUCT_STRING_INDEX, + DESC_SERIAL_STRING_INDEX, + USB_DESC_CONFIG_COUNT // Configurations count. +}; + +static const uint8_t g_device_qual_desc[DESC_DEVICE_QUAL_TOTAL_LEN] = { + DESC_DEVICE_QUAL_LEN, // Descriptor length. + DESC_DEVICE_QUAL, // Descriptor type. + usb_word_lsb_get(SPEC_BCD_VERSION), // USB BCD version, lo. + usb_word_msb_get(SPEC_BCD_VERSION), // USB BCD version, hi. + 0x00, // Device class. + 0x00, // Device sub-class. + 0x00, // Device protocol. + EP0_MAX_PACKET_SIZE, // Maximum packet size (ep0 size). + USB_DESC_CONFIG_COUNT, // Configurations count. + 0x00 // Reserved. +}; + +static const uint8_t g_config_desc[DESC_CONF_TOTAL_LEN] = { + DESC_CONF_LEN, // Descriptor length. + DESC_CONF, // Descriptor type. + usb_word_lsb_get(DESC_CONF_TOTAL_LEN), // Total length, lo. + usb_word_msb_get(DESC_CONF_TOTAL_LEN), // Total length, hi. + 0x01, // Interfaces count. + HID_CONFIG_NUMBER, // Configuration number. + 0x00, // Configuration string index. + USB_DESC_ATTRIBUTES, // Attributes. + USB_DESC_POWER_CONSUMPTION, // Power consumption. + + // Interface descriptor. + DESC_INTERFACE_LEN, // Descriptor length. + DESC_INTERFACE, // Descriptor type. + HID_IFACE_NUMBER, // Zero-based index of this interfacce. + HID_ALT_IFACE_NUMBER, // Alternate setting. + 0x01, // End points count (ep1 in). + 0x03, // Class code (HID). + 0x00, // Subclass code (boot). + 0x00, // Protocol code (none). + 0x00, // Interface string descriptor index. + + // HID descriptor. + DESC_HID_LEN, // Descriptor length. + DESC_HID, // Descriptor type. + usb_word_lsb_get(HID_BCD_VERSION), // HID class BCD version, lo. + usb_word_msb_get(HID_BCD_VERSION), // HID class BCD version, hi. + 0x00, // Country code (HW country code). + 0x01, // Number of HID class descriptors to follow. + DESC_REPORT, // Repord descriptor type (HID). + usb_word_lsb_get(DESCR_HID_REP_LEN), // Report descriptor total length, lo. + usb_word_msb_get(DESCR_HID_REP_LEN), // Report descriptor total length, hi. + + // End point descriptor. + DESC_ENDPOINT_LEN, // Descriptor length. + DESC_ENDPOINT, // Descriptor type. + HID_EP_IN, // End point address (ep1 in). + 0x03, // End point type (interrupt). + usb_word_lsb_get(EP_MAX_PACKET_SIZE), // Maximum packet size, lo (ep1 size). + usb_word_msb_get(EP_MAX_PACKET_SIZE), // Maximum packet size, hi (ep1 size). + 0x01 // Polling interval (1 ms). +}; + +static const uint8_t g_lang_id_desc[] = { + 0x04, // Descriptor length. + DESC_STRING, // Descriptor type. + usb_word_lsb_get(LANG_ID), // Language id, lo. + usb_word_msb_get(LANG_ID) // Language id, hi. +}; + +static const uint8_t g_manuf_str_desc[] = { + 0x18, // Descriptor length. + DESC_STRING, // Descriptor type. + // Unicode string: + 'Q', 0, 'B', 0, 'S', 0, ' ', 0, + 'e', 0, 'x', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0 +}; + +static const uint8_t g_product_str_desc[] = { + 0x1A, // Descriptor length. + DESC_STRING, // Descriptor type. + // Unicode string: + 'N', 0, 'E', 0, 'S', 0, ' ', 0, + 'G', 0, 'a', 0, 'm', 0, 'e', 0, + 'P', 0, 'a', 0, 'd', 0, 's', 0 +}; + +static const uint8_t g_serialno_str_desc[] = { + 0x1A, // Descriptor length. + DESC_STRING, // Descriptor type. + // Unicode string: + '0', 0 ,'1', 0, '0', 0, '2', 0, '0', 0, '3', 0, + '0', 0, '4', 0, '0', 0, '5', 0, '0', 0, '6', 0 +}; + +static const uint8_t *ep0_string_desc_get(uint16_t *length) +{ + const uint8_t index = hid_ep0_setup_lvalue_get(); + switch (index) { + case DESC_LANGID_STRING_INDEX: + *length = sizeof(g_lang_id_desc); + return g_lang_id_desc; + case DESC_MFG_STRING_INDEX: + *length = sizeof(g_manuf_str_desc); + return g_manuf_str_desc; + case DESC_PRODUCT_STRING_INDEX: + *length = sizeof(g_product_str_desc); + return g_product_str_desc; + case DESC_SERIAL_STRING_INDEX: + *length = sizeof(g_serialno_str_desc); + return g_serialno_str_desc; + default: + break; + } + return 0; +} + +const uint8_t *hid_ep0_desc_get(uint8_t type, uint16_t *length) +{ + switch (type) { + case DESC_DEVICE: + *length = DESC_DEVICE_TOTAL_LEN; + return g_device_desc; + case DESC_CONF: + *length = DESC_CONF_TOTAL_LEN; + return g_config_desc; + case DESC_STRING: + return ep0_string_desc_get(length); + case DESC_DEVICE_QUAL: + *length = DESC_DEVICE_QUAL_TOTAL_LEN; + return g_device_qual_desc; + case DESC_HID: + *length = DESC_HID_LEN; + return &g_config_desc[DESC_CONF_LEN + DESC_INTERFACE_LEN]; + case DESC_REPORT: + *length = DESCR_HID_REP_TOTAL_LEN; + return g_hid_report_desc; + default: + break; + } + return 0; +} diff --git a/examples/baremetal/msp430f5529/nes-gamepads/hidep0.c b/examples/baremetal/msp430f5529/nes-gamepads/hidep0.c new file mode 100644 index 000000000..c4a267a59 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/hidep0.c @@ -0,0 +1,554 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hid.h" +#include "hwdefs.h" +#include "usb.h" + +enum usb_ep0_action { + STATUS_ACTION_NOTHING, + STATUS_ACTION_DATA_IN +}; + +struct usb_ep0 { + uint8_t IEPCNFG; // Input ep0 configuration register. + uint8_t IEPBCNT; // Input ep0 buffer byte count. + uint8_t OEPCNFG; // Output ep0 configuration register. + uint8_t OEPBCNT; // Output ep0 buffer byte count. +}; + +struct usb_ep0_data { + uint8_t data[EP_MAX_FIFO_SIZE]; + uint16_t length; + uint16_t offset; + enum usb_ep0_action action; + bool host_ask_more_data_than_available; +}; + +#if defined(__ICC430__) +#pragma location = 0x0920 // Input ep0 configuration address. +__no_init struct usb_ep0 __data16 g_ep0; +#pragma location = 0x2378 // Input ep0 buffer address. +__no_init uint8_t __data16 g_ep0_in_buf[EP0_MAX_PACKET_SIZE]; +#pragma location = 0x2380 // Setup packet block address. +__no_init uint8_t __data16 g_setupdat[EP0_MAX_PACKET_SIZE]; +#elif defined(__GNUC__) +extern struct usb_ep0 g_ep0; +extern uint8_t g_ep0_in_buf[EP0_MAX_PACKET_SIZE]; +extern uint8_t g_setupdat[EP0_MAX_PACKET_SIZE]; +#endif + +static volatile bool g_enumerated = false; +static bool g_rwuen = false; +static bool g_selfpwr = false; +static struct usb_ep0_data g_ep0_response; + +static bool ep0_in_response_create(const uint8_t *data, uint16_t length) +{ + if (sizeof(g_ep0_response.data) < length) + return false; + + for (uint16_t i = 0; i < length; ++i) + g_ep0_response.data[i] = data[i]; + + g_ep0_response.length = length; + g_ep0_response.offset = 0; + + const uint16_t setup_length = (g_setupdat[7] << 8) | g_setupdat[6]; + if (g_ep0_response.length >= setup_length) { + g_ep0_response.length = setup_length; + g_ep0_response.host_ask_more_data_than_available = false; + } else { + g_ep0_response.host_ask_more_data_than_available = true; + } + + return true; +} + +void ep0_in_frame_send(void) +{ + uint8_t frame_size = 0; + + if (g_ep0_response.length != EP_NO_MORE_DATA) { + if (g_ep0_response.length > EP0_MAX_PACKET_SIZE) { + frame_size = EP0_MAX_PACKET_SIZE; + g_ep0_response.length -= EP0_MAX_PACKET_SIZE; + g_ep0_response.action = STATUS_ACTION_DATA_IN; + } else if (g_ep0_response.length < EP0_MAX_PACKET_SIZE) { + frame_size = g_ep0_response.length; + g_ep0_response.length = EP_NO_MORE_DATA; + g_ep0_response.action = STATUS_ACTION_NOTHING; + } else { + frame_size = EP0_MAX_PACKET_SIZE; + if (g_ep0_response.host_ask_more_data_than_available) { + g_ep0_response.length = 0; + g_ep0_response.action = STATUS_ACTION_DATA_IN; + } else { + g_ep0_response.length = EP_NO_MORE_DATA; + g_ep0_response.action = STATUS_ACTION_NOTHING; + } + } + + for (uint8_t i = 0; i < frame_size; ++i) { + g_ep0_in_buf[i] = g_ep0_response.data[g_ep0_response.offset]; + ++g_ep0_response.offset; + } + + g_ep0.IEPBCNT = frame_size; + } else { + g_ep0_response.action = STATUS_ACTION_NOTHING; + } +} + +static bool ep0_dev_status_get(void) +{ + uint16_t status = 0; + if (g_selfpwr) + status |= STATUS_SELF_POWERED; + if (g_rwuen) + status |= STATUS_REMOTE_WAKEUP; + ep0_in_response_create((uint8_t *)&status, sizeof(status)); + return true; +} + +static bool ep0_iface_status_get(void) +{ + uint16_t status = 0; + ep0_in_response_create((uint8_t *)&status, sizeof(status)); + return true; +} + +static bool ep0_ep_status_get(void) +{ + uint16_t status = 0; + const uint8_t ep = hid_ep0_setup_lindex_get(); + const uint8_t ep_num = ep & ~SETUP_DIR; + if (ep_num == 0) { + status = hid_ep0_in_is_stalled() ? 1 : 0; + } else if ((ep_num == 1) && (ep & SETUP_DIR) == SETUP_INPUT) { + // We support only one input ep1 in. + status = hid_ep1_in_is_stalled() ? 1 : 0; + } else { + return false; + } + + ep0_in_response_create((uint8_t *)&status, sizeof(status)); + return true; +} + +static bool ep0_get_status_proc(void) +{ + const uint8_t bm_req_type = hid_ep0_setup_bm_request_type_get(); + if ((bm_req_type & SETUP_DIR) != SETUP_INPUT) + return false; + const uint8_t recipient = bm_req_type & SETUP_RECIPIENT; + switch (recipient) { + case SETUP_DEVICE: + return ep0_dev_status_get(); + case SETUP_IFACE: + return ep0_iface_status_get(); + case SETUP_EP: + return ep0_ep_status_get(); + default: + break; + } + return false; +} + +static bool ep0_dev_feature_clear(void) +{ + const uint8_t feature = hid_ep0_setup_lvalue_get(); + if (feature != FEATURE_REMOTE_WAKEUP) + return false; + g_rwuen = false; + return true; +} + +static bool ep0_ep_feature_clear(void) +{ + const uint8_t feature = hid_ep0_setup_lvalue_get(); + if (feature != FEATURE_STALL) + return false; + const uint8_t ep = hid_ep0_setup_lindex_get(); + const uint8_t ep_num = ep & ~SETUP_DIR; + if (ep_num == 0) { + // Do nothing. + } else if ((ep_num == 1) && (ep & SETUP_DIR) == SETUP_INPUT) { + // We support only one input ep1 in. + hid_ep1_in_unstall(); + } else { + return false; + } + + hid_ep0_in_clear(); + return true; +} + +static bool ep0_clear_feature_proc(void) +{ + const uint8_t bm_req_type = hid_ep0_setup_bm_request_type_get(); + if ((bm_req_type & SETUP_DIR) != SETUP_INPUT) + return false; + const uint8_t recipient = bm_req_type & SETUP_RECIPIENT; + switch (recipient) { + case SETUP_DEVICE: + return ep0_dev_feature_clear(); + case SETUP_EP: + return ep0_ep_feature_clear(); + default: + break; + } + return false; +} + +static bool ep0_dev_feature_set(void) +{ + const uint8_t feature = hid_ep0_setup_lvalue_get(); + switch (feature) { + case FEATURE_REMOTE_WAKEUP: + g_rwuen = true; + return true; + case FEATURE_TEST_MODE: + // This is "test mode", just return the handshake. + return true; + default: + break; + } + return false; +} + +static bool ep0_ep_feature_set(void) +{ + const uint8_t feature = hid_ep0_setup_lvalue_get(); + if (feature != FEATURE_STALL) + return false; + const uint8_t ep = hid_ep0_setup_lindex_get(); + const uint8_t ep_num = ep & ~SETUP_DIR; + if (ep_num == 0) { + // Do nothing. + } else if ((ep_num == 1) && (ep & SETUP_DIR) == SETUP_INPUT) { + // We support only one input ep1 in. + hid_ep1_in_stall(); + } else { + return false; + } + hid_ep0_in_clear(); + return true; +} + +static bool ep0_set_feature_proc(void) +{ + const uint8_t bm_req_type = hid_ep0_setup_bm_request_type_get(); + switch (bm_req_type & SETUP_RECIPIENT) { + case SETUP_DEVICE: + return ep0_dev_feature_set(); + case SETUP_EP: + return ep0_ep_feature_set(); + default: + break; + } + return false; +} + +static bool ep0_set_address_proc(void) +{ + hid_ep0_out_stall(); + const uint8_t address = hid_ep0_setup_lvalue_get(); + if (address >= 128) + return false; + USBFUNADR = address; + hid_ep0_in_clear(); + return true; +} + +static bool ep0_descriptor_proc(uint8_t type) +{ + uint16_t length = 0; + const uint8_t *pdesc = hid_ep0_desc_get(type, &length); + if (!pdesc) + return false; + ep0_in_response_create(pdesc, length); + return true; +} + +static bool ep0_get_descriptor_proc(void) +{ + const uint8_t descr_type = hid_ep0_setup_hvalue_get(); + switch (descr_type) { + case DESC_DEVICE: + case DESC_CONF: + case DESC_STRING: + case DESC_DEVICE_QUAL: + case DESC_OTHER_SPEED_CONF: + case DESC_HID: + case DESC_REPORT: + return ep0_descriptor_proc(descr_type); + } + return false; +} + +static bool ep0_get_config_proc(void) +{ + // We only support configuration 1. + const uint8_t cfg_num = HID_CONFIG_NUMBER; + ep0_in_response_create(&cfg_num, sizeof(cfg_num)); + return true; +} + +static bool ep0_set_config_proc(void) +{ + const uint8_t cfg_num = hid_ep0_setup_lvalue_get(); + // We only support configuration 1. + const bool is_valid = (cfg_num & HID_CONFIG_NUMBER); + hid_ep0_enumerated_set(is_valid); + return is_valid; +} + +static bool ep0_get_iface_proc(void) +{ + const uint8_t iface_num = hid_ep0_setup_lindex_get(); + if (iface_num != HID_IFACE_NUMBER) + return false; + ep0_in_response_create(&iface_num, sizeof(iface_num)); + return true; +} + +static bool ep0_set_iface_proc(void) +{ + const uint8_t iface_num = hid_ep0_setup_lindex_get(); + if (iface_num != HID_IFACE_NUMBER) + return false; + + const uint8_t alt_iface_num = hid_ep0_setup_lvalue_get(); + if (alt_iface_num != HID_ALT_IFACE_NUMBER) + return false; + + hid_ep0_out_stall(); + hid_ep0_in_clear(); + return true; +} + +static bool ep0_std_proc(void) +{ + const uint8_t request_code = hid_ep0_setup_request_get(); + switch (request_code) { + case SETUP_GET_STATUS: + return ep0_get_status_proc(); + case SETUP_CLEAR_FEATURE: + return ep0_clear_feature_proc(); + case SETUP_SET_FEATURE: + return ep0_set_feature_proc(); + case SETUP_SET_ADDRESS: + return ep0_set_address_proc(); + case SETUP_GET_DESCRIPTOR: + return ep0_get_descriptor_proc(); + case SETUP_GET_CONFIGURATION: + return ep0_get_config_proc(); + case SETUP_SET_CONFIGURATION: + return ep0_set_config_proc(); + case SETUP_GET_INTERFACE: + return ep0_get_iface_proc(); + case SETUP_SET_INTERFACE: + return ep0_set_iface_proc(); + default: + break; + } + return false; +} + +static bool ep0_setup(void) +{ + const uint8_t bm_req_type = hid_ep0_setup_bm_request_type_get(); + const uint8_t setup_type = bm_req_type & SETUP_TYPE; + switch (setup_type) { + case SETUP_STANDARD: + return ep0_std_proc(); + default: + break; + } + return false; +} + +static bool ep0_has_another_setup(void) +{ + if ((USBIFG & STPOWIFG) != 0) { + USBIFG &= ~(STPOWIFG | SETUPIFG); + return true; + } + return false; +} + +void hid_ep0_init(void) +{ + hid_ep0_in_nak(); + hid_ep0_out_nak(); + + g_ep0.IEPCNFG = UBME | STALL | USBIIE; + g_ep0.OEPCNFG = UBME | STALL | USBIIE; + + // Enable only ep0in interrupts. + USBIEPIE |= BIT0; +} + +void hid_ep0_setup_handler(void) +{ + USBCTL |= FRSTE; + + g_ep0_response.length = 0; + g_ep0_response.offset = 0; + g_ep0_response.action = STATUS_ACTION_NOTHING; + g_ep0_response.host_ask_more_data_than_available = false; + + for (;;) { + const uint8_t bm_req_type = hid_ep0_setup_bm_request_type_get(); + if ((bm_req_type & SETUP_INPUT) == SETUP_INPUT) + USBCTL |= DIR; + else + USBCTL &= ~DIR; + + const bool success = ep0_setup(); + if (success) { + hid_ep0_out_clear(); + ep0_in_frame_send(); + } else { + hid_ep0_in_stall(); + } + + if (!ep0_has_another_setup()) + return; + } +} + +void hid_ep0_in_handler(void) +{ + USBCTL |= FRSTE; + hid_ep0_out_clear(); + if (g_ep0_response.action == STATUS_ACTION_DATA_IN) + ep0_in_frame_send(); + else + hid_ep0_in_stall(); +} + +void hid_ep0_in_nak(void) +{ + g_ep0.IEPBCNT = NAK; +} + +void hid_ep0_in_stall(void) +{ + g_ep0.IEPCNFG |= STALL; +} + +void hid_ep0_in_clear(void) +{ + g_ep0_response.length = EP_NO_MORE_DATA; + g_ep0_response.action = STATUS_ACTION_NOTHING; + g_ep0.IEPBCNT = 0; +} + +bool hid_ep0_in_is_stalled(void) +{ + return (g_ep0.IEPCNFG & STALL); +} + +void hid_ep0_out_nak(void) +{ + g_ep0.OEPBCNT = NAK; +} + +void hid_ep0_out_stall(void) +{ + g_ep0.OEPCNFG |= STALL; +} + +void hid_ep0_out_clear(void) +{ + g_ep0.OEPBCNT = 0; +} + +uint8_t hid_ep0_setup_bm_request_type_get(void) +{ + return g_setupdat[0]; +} + +uint8_t hid_ep0_setup_request_get(void) +{ + return g_setupdat[1]; +} + +uint8_t hid_ep0_setup_lvalue_get(void) +{ + return g_setupdat[2]; +} + +uint8_t hid_ep0_setup_hvalue_get(void) +{ + return g_setupdat[3]; +} + +uint8_t hid_ep0_setup_lindex_get(void) +{ + return g_setupdat[4]; +} + +uint8_t hid_ep0_setup_hindex_get(void) +{ + return g_setupdat[5]; +} + +void hid_ep0_enumerated_set(bool enumerated) +{ + g_enumerated = enumerated; +} + +bool hid_ep0_is_enumerated(void) +{ + return g_enumerated; +} diff --git a/examples/baremetal/msp430f5529/nes-gamepads/hidep1.c b/examples/baremetal/msp430f5529/nes-gamepads/hidep1.c new file mode 100644 index 000000000..2d29490ec --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/hidep1.c @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "gpio.h" +#include "hid.h" +#include "hwdefs.h" +#include "usb.h" + +// We use this empirical value to make a GPIO polling +// every ~10 msec (rough). It is a simplest way, because +// instead we need to use a timers with interrupts callbacks. +enum { POLLING_COUNTER = 888 }; + +// Pins on the port 6. +enum gpio_pins { + GPIO_CLK_PIN = BIT0, + GPIO_DATA1_PIN = BIT1, + GPIO_DATA2_PIN = BIT2, + GPIO_LATCH_PIN = BIT3, +}; + +struct usb_ep { + uint8_t EPCNF; // Endpoint configuration. + uint8_t EPBBAX; // Endpoint X buffer base address. + uint8_t EPBCTX; // Endpoint X Buffer byte count. + uint8_t SPARE0; // No used. + uint8_t SPARE1; // No used. + uint8_t EPBBAY; // Endpoint Y buffer Base address. + uint8_t EPBCTY; // Endpoint Y buffer byte count. + uint8_t EPSIZXY; // Endpoint XY buffer size. +}; + +#if defined(__ICC430__) +#pragma location = 0x23C8 // Input ep1 configuration address. +__no_init struct usb_ep __data16 g_ep1_in; + +#pragma location = 0x1C80 // Input ep1 X-buffer address. +__no_init uint8_t __data16 g_ep1_in_xbuf[EP_MAX_PACKET_SIZE]; +#elif defined(__GNUC__) +extern struct usb_ep g_ep1_in; +extern uint8_t g_ep1_in_xbuf[EP_MAX_PACKET_SIZE]; +#endif + +static struct { + const uint8_t data_pin; + const uint8_t id; + uint8_t buttons; + bool ready; +} g_reports[HID_REPORTS_COUNT] = { + {GPIO_DATA1_PIN, HID_REPORT_ID_GAMEPAD1, 0, false}, + {GPIO_DATA2_PIN, HID_REPORT_ID_GAMEPAD2, 0, false} +}; + +static uint16_t g_poll_counter = 0; + +// Pulse width around ~10 usec. +static void ep1_latch_pulse(void) +{ + gpio_pins_set_high(GPIO_PORT_P6, GPIO_LATCH_PIN); + gpio_pins_set_low(GPIO_PORT_P6, GPIO_LATCH_PIN); +} + +// Pulse width around ~10 usec. +static void ep1_clk_pulse(void) +{ + gpio_pins_set_high(GPIO_PORT_P6, GPIO_CLK_PIN); + gpio_pins_set_low(GPIO_PORT_P6, GPIO_CLK_PIN); +} + +static void ep1_reports_clean(void) +{ + for (uint8_t index = 0; index < HID_REPORTS_COUNT; ++index) { + g_reports[index].buttons = 0; + g_reports[index].ready = false; + } +} + +static void ep1_reports_update(void) +{ + for (uint8_t index = 0; index < HID_REPORTS_COUNT; ++index) + g_reports[index].ready = true; +} + +static void ep1_gamepads_poll(void) +{ + ep1_reports_clean(); + + ep1_latch_pulse(); + + for (uint8_t pos = 0; pos < HID_REPORT_BITS_COUNT; ++pos) { + // TODO: Add some nops here? + + for (uint8_t index = 0; index < HID_REPORTS_COUNT; ++index) { + const uint8_t pin = g_reports[index].data_pin; + const enum gpio_pin_status st = gpio_pin_get(GPIO_PORT_P6, pin); + // Low state means that a button is pressed. + const bool v = (st == GPIO_INPUT_PIN_LOW); + g_reports[index].buttons |= (v << pos); + } + + ep1_clk_pulse(); + } + + ep1_reports_update(); +} + +static void ep1_report_send(uint8_t report_index) +{ + if (!g_reports[report_index].ready) + return; + + if ((g_ep1_in.EPBCTX & NAK) == 0) + return; + + g_ep1_in_xbuf[0] = g_reports[report_index].id; + g_ep1_in_xbuf[1] = g_reports[report_index].buttons; + g_ep1_in.EPBCTX = 2; + + g_reports[report_index].ready = false; +} + +void hid_ep1_init(void) +{ + enum { + USBSTABUFF_ADDRESS = 0x1C00, // Start of buffer space address. + USBIEPBBAX_1_ADDRESS = 0x1C80 // Input ep1 X-buffer address. + }; + + g_ep1_in.EPCNF = UBME | USBIIE; + g_ep1_in.EPBBAX = ((USBIEPBBAX_1_ADDRESS - USBSTABUFF_ADDRESS) >> 3) & 0x00FF; + g_ep1_in.EPBCTX = NAK; + g_ep1_in.EPSIZXY = EP_MAX_PACKET_SIZE; + + gpio_pins_set_as_out(GPIO_PORT_P6, GPIO_CLK_PIN | GPIO_LATCH_PIN); + gpio_pins_set_as_in(GPIO_PORT_P6, GPIO_DATA1_PIN | GPIO_DATA2_PIN); +} + +void hid_ep1_task(void) +{ + if (!hid_ep0_is_enumerated()) + return; + + for (uint8_t index = 0; index < HID_REPORTS_COUNT; ++index) + ep1_report_send(index); + + if (g_poll_counter <= POLLING_COUNTER) { + ++g_poll_counter; + } else { + g_poll_counter = 0; + ep1_gamepads_poll(); + } +} + +void hid_ep1_in_stall(void) +{ + g_ep1_in.EPCNF |= STALL; +} + +void hid_ep1_in_unstall(void) +{ + g_ep1_in.EPCNF &= ~(STALL | TOGGLE); +} + +bool hid_ep1_in_is_stalled(void) +{ + return (g_ep1_in.EPCNF & STALL); +} diff --git a/examples/baremetal/msp430f5529/nes-gamepads/hwdefs.h b/examples/baremetal/msp430f5529/nes-gamepads/hwdefs.h new file mode 100644 index 000000000..89dbcf5af --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/hwdefs.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MSP430_HW_DEFS_H +#define MSP430_HW_DEFS_H + +#include <msp430.h> +#include <msp430f5xx_6xxgeneric.h> + +#if defined(__ICC430__) +# define _PPTOSTR_(x) #x +# define _PPARAM_(address) _PPTOSTR_(vector=address) +# define INTERRUPT(isr_name, vector) \ + _Pragma(_PPARAM_(vector)) __interrupt void isr_name(void) +#elif defined(__GNUC__) +# define INTERRUPT(isr_name, vector) \ + void __attribute__ ((interrupt(vector))) isr_name(void) +#else +# error "Unsupported toolchain" +#endif + +#include <stdbool.h> +#include <stdint.h> + +#define HWREG8(x) \ + (*((volatile uint8_t *)((uint16_t)x))) + +#define HWREG16(x) \ + (*((volatile uint16_t *)((uint16_t)x))) + +#define HWREG32(x) \ + (*((volatile uint32_t *)((uint16_t)x))) + +#endif // MSP430_HW_DEFS_H diff --git a/examples/baremetal/msp430f5529/nes-gamepads/main.c b/examples/baremetal/msp430f5529/nes-gamepads/main.c new file mode 100644 index 000000000..97c499eef --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/main.c @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hwdefs.h" +#include "pmm.h" +#include "ucs.h" +#include "usb.h" +#include "wdt_a.h" + +static void hw_clocks_init(uint32_t mclk_freq) +{ + ucs_init(UCS_FLLREF, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1); + ucs_init(UCS_ACLK, UCS_REFOCLK_SELECT, UCS_CLOCK_DIVIDER_1); + ucs_fll_settle_init(mclk_freq / 1000, mclk_freq / 32768); + + // Use REFO for FLL and ACLK. + UCSCTL3 = (UCSCTL3 & ~SELREF_7) | SELREF__REFOCLK; + UCSCTL4 = (UCSCTL4 & ~SELA_7) | SELA__REFOCLK; +} + +static void hw_init(void) +{ + __disable_interrupt(); + + wdt_a_stop(); + pmm_voltage_init(PMM_VOLTAGE_1_85V); + hw_clocks_init(8000000); + usb_init(); + + __enable_interrupt(); +} + +static void hw_loop_exec(void) +{ + for (;;) { + usb_task(); + } +} + +int main(void) +{ + hw_init(); + hw_loop_exec(); + return 0; +} diff --git a/examples/baremetal/msp430f5529/nes-gamepads/nes-gamepads.qbs b/examples/baremetal/msp430f5529/nes-gamepads/nes-gamepads.qbs new file mode 100644 index 000000000..37dfe8ca6 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/nes-gamepads.qbs @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import qbs + +CppApplication { + condition: { + if (!qbs.architecture.contains("msp430")) + return false; + return qbs.toolchain.contains("iar") + || qbs.toolchain.contains("gcc") + } + name: "msp430f5529-nes-gamepads" + cpp.cLanguageVersion: "c99" + cpp.positionIndependentCode: false + + // + // IAR-specific properties and sources. + // + + Properties { + condition: qbs.toolchain.contains("iar") + + property path dlibIncludePath: cpp.toolchainInstallPath + "/../lib/dlib/dl430xssfn.h" + property path dlibRuntimePath: cpp.toolchainInstallPath + "/../lib/dlib/dl430xssfn.r43" + + cpp.entryPoint: "__program_start" + + cpp.defines: ["__MSP430F5529__"] + + cpp.driverFlags: [ + "-e", + "--core=430X", + "--data_model=small", + "--code_model=small", + "--dlib_config", dlibIncludePath + ] + + cpp.driverLinkerFlags: [ + "-D_STACK_SIZE=A0", + "-D_DATA16_HEAP_SIZE=A0", + "-D_DATA20_HEAP_SIZE=50" + ] + + cpp.staticLibraries: [ + // Explicitly link with the runtime dlib library (which contains + // all required startup code and other stuff). + dlibRuntimePath + ] + } + + Group { + condition: qbs.toolchain.contains("iar") + name: "IAR Linker Script" + prefix: cpp.toolchainInstallPath + "/../config/linker/" + fileTags: ["linkerscript"] + // Explicitly use the default linker scripts for current target. + files: ["lnk430f5529.xcl"] + } + + // + // GCC-specific properties and soucres. + // + + Properties { + condition: qbs.toolchain.contains("gcc") + property path supportFilesPath + // A path to the MSP430 support files, which are + // provided by the Texas Instruments separately: + // e.g. 'c:/msp430-gcc-support-files/include/' + cpp.includePaths: supportFilesPath + cpp.libraryPaths: supportFilesPath + cpp.driverFlags: ["-mmcu=msp430f5529"] + } + + Group { + condition: qbs.toolchain.contains("gcc") + name: "GCC Linker Script" + fileTags: ["linkerscript"] + files: ["gamepads.ld"] + } + + files: [ + "gpio.c", + "gpio.h", + "hid.h", + "hiddesc.c", + "hidep0.c", + "hidep1.c", + "hwdefs.h", + "main.c", + "pmm.c", + "pmm.h", + "ucs.c", + "ucs.h", + "usb.c", + "usb.h", + "wdt_a.c", + "wdt_a.h", + ] +} diff --git a/examples/baremetal/msp430f5529/nes-gamepads/pmm.c b/examples/baremetal/msp430f5529/nes-gamepads/pmm.c new file mode 100644 index 000000000..b588e7ad3 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/pmm.c @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hwdefs.h" +#include "pmm.h" + +#define PMMCTL0_H_ADDRESS (PMM_BASE + OFS_PMMCTL0_H) +#define PMMCTL0_L_ADDRESS (PMM_BASE + OFS_PMMCTL0_L) +#define PMMRIE_ADDRESS (PMM_BASE + OFS_PMMRIE) +#define PMMIFG_ADDRESS (PMM_BASE + OFS_PMMIFG) +#define SVSMHCTL_ADDRESS (PMM_BASE + OFS_SVSMHCTL) +#define SVSMLCTL_ADDRESS (PMM_BASE + OFS_SVSMLCTL) + +#define PMM_OTHER_BITSL \ + (SVSLRVL0 | SVSLRVL1 | SVSMLRRL0 | SVSMLRRL1 | SVSMLRRL2) + +#define PMM_OTHER_BITSH \ + (SVSHRVL0 | SVSHRVL1 | SVSMHRRL0 | SVSMHRRL1 | SVSMHRRL2) + +#define PMM_CLEANUP_FLAGS \ + (SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG | SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG) + +static void pmm_write_access_allow(bool allow) +{ + HWREG8(PMMCTL0_H_ADDRESS) = allow ? PMMPW_H : 0; +} + +static void pmm_interrupt_flags_clear(uint16_t flags) +{ + HWREG16(PMMIFG_ADDRESS) &= ~flags; +} + +static void pmm_interrupt_flags_wait(uint16_t flags) +{ + while ((HWREG16(PMMIFG_ADDRESS) & flags) == 0) { + ; + } +} + +static uint8_t pmm_level_mask(enum ppm_voltage voltage) +{ + switch (voltage) { + case PMM_VOLTAGE_1_35V: + return PMMCOREV_0; + case PMM_VOLTAGE_1_55V: + return PMMCOREV_1; + case PMM_VOLTAGE_1_75V: + return PMMCOREV_2; + case PMM_VOLTAGE_1_85V: + return PMMCOREV_3; + default: + break; + } + return PMMCOREV_0; +} + +static bool pmm_voltage_set_up(uint8_t level) +{ + pmm_write_access_allow(true); + + // Disable interrupts and backup all registers. + uint16_t pmmrie_backup = HWREG16(PMMRIE_ADDRESS); + HWREG16(PMMRIE_ADDRESS) &= ~(SVMHVLRPE | SVSHPE | SVMLVLRPE | SVSLPE + | SVMHVLRIE | SVMHIE | SVSMHDLYIE | SVMLVLRIE + | SVMLIE | SVSMLDLYIE); + uint16_t svsmhctl_backup = HWREG16(SVSMHCTL_ADDRESS); + uint16_t svsmlctl_backup = HWREG16(SVSMLCTL_ADDRESS); + + // Clear all interrupt flags. + pmm_interrupt_flags_clear(0xFFFF); + + // Set SVM high side to new level and check if voltage increase is possible. + HWREG16(SVSMHCTL_ADDRESS) = SVMHE | SVSHE | (SVSMHRRL0 * level); + pmm_interrupt_flags_wait(SVSMHDLYIFG); + pmm_interrupt_flags_clear(SVSMHDLYIFG); + + // Check if a voltage increase is possible. + if ((HWREG16(PMMIFG_ADDRESS) & SVMHIFG) == SVMHIFG) { + // Vcc is too low for a voltage increase, recover the previous settings. + HWREG16(PMMIFG_ADDRESS) &= ~SVSMHDLYIFG; + HWREG16(SVSMHCTL_ADDRESS) = svsmhctl_backup; + pmm_interrupt_flags_wait(SVSMHDLYIFG); + pmm_interrupt_flags_clear(PMM_CLEANUP_FLAGS); + // Restore interrupt enable register. + HWREG16(PMMRIE_ADDRESS) = pmmrie_backup; + pmm_write_access_allow(false); + return false; + } + + // Set SVS high side to new level. + HWREG16(SVSMHCTL_ADDRESS) |= (SVSHRVL0 * level); + pmm_interrupt_flags_wait(SVSMHDLYIFG); + pmm_interrupt_flags_clear(SVSMHDLYIFG); + + // Set new voltage level. + HWREG8(PMMCTL0_L_ADDRESS) = PMMCOREV0 * level; + + // Set SVM, SVS low side to new level. + HWREG16(SVSMLCTL_ADDRESS) = SVMLE | (SVSMLRRL0 * level) + | SVSLE | (SVSLRVL0 * level); + pmm_interrupt_flags_wait(SVSMLDLYIFG); + pmm_interrupt_flags_clear(SVSMLDLYIFG); + + // Restore low side settings and clear all other bits. + HWREG16(SVSMLCTL_ADDRESS) &= PMM_OTHER_BITSL; + // Clear low side level settings in backup register and keep all other bits. + svsmlctl_backup &= ~PMM_OTHER_BITSL; + // Restore low side SVS monitor settings. + HWREG16(SVSMLCTL_ADDRESS) |= svsmlctl_backup; + + // Restore high side settings and clear all other bits. + HWREG16(SVSMHCTL_ADDRESS) &= PMM_OTHER_BITSH; + // Clear high side level settings in backup register and keep all other bits. + svsmhctl_backup &= ~PMM_OTHER_BITSH; + // Restore high side SVS monitor settings. + HWREG16(SVSMHCTL_ADDRESS) |= svsmhctl_backup; + + pmm_interrupt_flags_wait(SVSMLDLYIFG | SVSMHDLYIFG); + pmm_interrupt_flags_clear(PMM_CLEANUP_FLAGS); + + // Restore interrupt enable register. + HWREG16(PMMRIE_ADDRESS) = pmmrie_backup; + pmm_write_access_allow(false); + + return true; +} + +static uint16_t pmm_voltage_set_down(uint8_t level) +{ + pmm_write_access_allow(true); + + // Disable interrupts and backup all registers. + uint16_t pmmrie_backup = HWREG16(PMMRIE_ADDRESS); + HWREG16(PMMRIE_ADDRESS) &= ~(SVMHVLRPE | SVSHPE | SVMLVLRPE | + SVSLPE | SVMHVLRIE | SVMHIE | + SVSMHDLYIE | SVMLVLRIE | SVMLIE | + SVSMLDLYIE + ); + uint16_t svsmhctl_backup = HWREG16(SVSMHCTL_ADDRESS); + uint16_t svsmlctl_backup = HWREG16(SVSMLCTL_ADDRESS); + + pmm_interrupt_flags_clear(SVMHIFG | SVSMHDLYIFG | SVMLIFG | SVSMLDLYIFG); + + // Set SVM, SVS high & low side to new settings in normal mode. + HWREG16(SVSMHCTL_ADDRESS) = SVMHE | (SVSMHRRL0 * level) | SVSHE | (SVSHRVL0 * level); + HWREG16(SVSMLCTL_ADDRESS) = SVMLE | (SVSMLRRL0 * level) | SVSLE | (SVSLRVL0 * level); + + pmm_interrupt_flags_wait(SVSMHDLYIFG | SVSMLDLYIFG); + pmm_interrupt_flags_clear(SVSMHDLYIFG | SVSMLDLYIFG); + + // Set new voltage level. + HWREG8(PMMCTL0_L_ADDRESS) = PMMCOREV0 * level; + + // Restore low side settings and clear all other bits. + HWREG16(SVSMLCTL_ADDRESS) &= PMM_OTHER_BITSL; + // Clear low side level settings in backup register and keep all other bits. + svsmlctl_backup &= ~PMM_OTHER_BITSL; + //Restore low side SVS monitor settings. + HWREG16(SVSMLCTL_ADDRESS) |= svsmlctl_backup; + + // Restore high side settings and clear all other bits. + HWREG16(SVSMHCTL_ADDRESS) &= PMM_OTHER_BITSH; + // Clear high side level settings in backup register and keep all other bits. + svsmhctl_backup &= ~PMM_OTHER_BITSH; + // Restore high side SVS monitor settings. + HWREG16(SVSMHCTL_ADDRESS) |= svsmhctl_backup; + + pmm_interrupt_flags_wait(SVSMLDLYIFG | SVSMHDLYIFG); + pmm_interrupt_flags_clear(PMM_CLEANUP_FLAGS); + + // Restore interrupt enable register. + HWREG16(PMMRIE_ADDRESS) = pmmrie_backup; + pmm_write_access_allow(false); + + return true; +} + +bool pmm_voltage_init(enum ppm_voltage voltage) +{ + const uint8_t exp_level = pmm_level_mask(voltage) & PMMCOREV_3; + uint8_t act_level = (HWREG16(PMM_BASE + OFS_PMMCTL0) & PMMCOREV_3); + bool result = true; + while ((exp_level != act_level) && result) { + if (exp_level > act_level) + result = pmm_voltage_set_up(++act_level); + else + result = pmm_voltage_set_down(--act_level); + } + return result; +} diff --git a/examples/baremetal/msp430f5529/nes-gamepads/pmm.h b/examples/baremetal/msp430f5529/nes-gamepads/pmm.h new file mode 100644 index 000000000..049fddc69 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/pmm.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MSP430_PMM_H +#define MSP430_PMM_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +enum ppm_voltage { + PMM_VOLTAGE_1_35V, + PMM_VOLTAGE_1_55V, + PMM_VOLTAGE_1_75V, + PMM_VOLTAGE_1_85V +}; + +bool pmm_voltage_init(enum ppm_voltage voltage); + +#ifdef __cplusplus +} +#endif + +#endif // MSP430_PMM_H diff --git a/examples/baremetal/msp430f5529/nes-gamepads/ucs.c b/examples/baremetal/msp430f5529/nes-gamepads/ucs.c new file mode 100644 index 000000000..a4e17b8ac --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/ucs.c @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hwdefs.h" +#include "ucs.h" + +#if defined(__GNUC__) +#define __delay_cycles(x) \ + ({ \ + for (uint16_t j = 0; j < x; j++) { \ + __no_operation(); \ + } \ + }) +#endif + +static uint16_t ucs_source_mask(enum ucs_source source) +{ + switch (source) { + case UCS_XT1CLK_SELECT: + return SELM__XT1CLK; + case UCS_VLOCLK_SELECT: + return SELM__VLOCLK; + case UCS_REFOCLK_SELECT: + return SELM__REFOCLK; + case UCS_DCOCLK_SELECT: + return SELM__DCOCLK; + case UCS_DCOCLKDIV_SELECT: + return SELM__DCOCLKDIV; + case UCS_XT2CLK_SELECT: + return SELM__XT2CLK; + default: + break; + } + return SELM__XT1CLK; +} + +static uint16_t ucs_divider_mask(enum ucs_divider divider) +{ + switch (divider) { + case UCS_CLOCK_DIVIDER_1: + return DIVM__1; + case UCS_CLOCK_DIVIDER_2: + return DIVM__2; + case UCS_CLOCK_DIVIDER_4: + return DIVM__4; + case UCS_CLOCK_DIVIDER_8: + return DIVM__8; + case UCS_CLOCK_DIVIDER_12: + return DIVM__32; + case UCS_CLOCK_DIVIDER_16: + return DIVM__16; + case UCS_CLOCK_DIVIDER_32: + return DIVM__32; + default: + break; + } + return DIVM__1; +} + +static void ucs_fll_init(uint16_t fsystem, uint16_t ratio) +{ + const uint16_t sr_reg_backup = __get_SR_register() & SCG0; + + uint16_t mode = 0; + uint16_t d = ratio; + if (fsystem > 16000) { + d >>= 1; + mode = 1; + } else { + fsystem <<= 1; + } + + uint16_t dco_div_bits = FLLD__2; + while (d > 512) { + dco_div_bits = dco_div_bits + FLLD0; + d >>= 1; + } + + // Disable FLL. + __bis_SR_register(SCG0); + // Set DCO to lowest tap. + HWREG8(UCS_BASE + OFS_UCSCTL0_H) = 0; + // Reset FN bits. + HWREG16(UCS_BASE + OFS_UCSCTL2) &= ~(0x03FF); + HWREG16(UCS_BASE + OFS_UCSCTL2) = dco_div_bits | (d - 1); + + if (fsystem <= 630) { // fsystem < 0.63MHz + HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_0; + } else if (fsystem < 1250) { // 0.63MHz < fsystem < 1.25MHz + HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_1; + } else if (fsystem < 2500) { // 1.25MHz < fsystem < 2.5MHz + HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_2; + } else if (fsystem < 5000) { // 2.5MHz < fsystem < 5MHz + HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_3; + } else if (fsystem < 10000) { // 5MHz < fsystem < 10MHz + HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_4; + } else if (fsystem < 20000) { // 10MHz < fsystem < 20MHz + HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_5; + } else if (fsystem < 40000) { // 20MHz < fsystem < 40MHz + HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_6; + } else { + HWREG8(UCS_BASE + OFS_UCSCTL1) = DCORSEL_7; + } + + // Re-enable FLL. + __bic_SR_register(SCG0); + + while (HWREG8(UCS_BASE + OFS_UCSCTL7_L) & DCOFFG) { + // Clear OSC fault flags. + HWREG8(UCS_BASE + OFS_UCSCTL7_L) &= ~(DCOFFG); + // Clear OFIFG fault flag. + HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; + } + + // Restore previous SCG0. + __bis_SR_register(sr_reg_backup); + + if (mode == 1) { + // Select DCOCLK because fsystem > 16000. + HWREG16(UCS_BASE + OFS_UCSCTL4) &= ~(SELM_7 + SELS_7); + HWREG16(UCS_BASE + OFS_UCSCTL4) |= SELM__DCOCLK + SELS__DCOCLK; + } else { + // Select DCODIVCLK. + HWREG16(UCS_BASE + OFS_UCSCTL4) &= ~(SELM_7 + SELS_7); + HWREG16(UCS_BASE + OFS_UCSCTL4) |= SELM__DCOCLKDIV + SELS__DCOCLKDIV; + } +} + +void ucs_init(enum ucs_signal signal, + enum ucs_source source, + enum ucs_divider divider) +{ + uint16_t source_msk = ucs_source_mask(source); + uint16_t divider_msk = ucs_divider_mask(divider); + + switch (signal) { + case UCS_ACLK: + HWREG16(UCS_BASE + OFS_UCSCTL4) &= ~SELA_7; + source_msk |= source_msk << 8; + HWREG16(UCS_BASE + OFS_UCSCTL4) |= source_msk; + HWREG16(UCS_BASE + OFS_UCSCTL5) &= ~DIVA_7; + divider_msk = divider_msk << 8; + HWREG16(UCS_BASE + OFS_UCSCTL5) |= divider_msk; + break; + case UCS_SMCLK: + HWREG16(UCS_BASE + OFS_UCSCTL4) &= ~SELS_7; + source_msk = source_msk << 4; + HWREG16(UCS_BASE + OFS_UCSCTL4) |= source_msk; + HWREG16(UCS_BASE + OFS_UCSCTL5) &= ~DIVS_7; + divider_msk = divider_msk << 4; + HWREG16(UCS_BASE + OFS_UCSCTL5) |= divider_msk; + break; + case UCS_MCLK: + HWREG16(UCS_BASE + OFS_UCSCTL4) &= ~SELM_7; + HWREG16(UCS_BASE + OFS_UCSCTL4) |= source_msk; + HWREG16(UCS_BASE + OFS_UCSCTL5) &= ~DIVM_7; + HWREG16(UCS_BASE + OFS_UCSCTL5) |= divider_msk; + break; + case UCS_FLLREF: + HWREG8(UCS_BASE + OFS_UCSCTL3) &= ~SELREF_7; + source_msk = source_msk << 4; + HWREG8(UCS_BASE + OFS_UCSCTL3) |= source_msk; + HWREG8(UCS_BASE + OFS_UCSCTL3) &= ~FLLREFDIV_7; + + switch (divider) { + case UCS_CLOCK_DIVIDER_12: + HWREG8(UCS_BASE + OFS_UCSCTL3) |= FLLREFDIV__12; + break; + case UCS_CLOCK_DIVIDER_16: + HWREG8(UCS_BASE + OFS_UCSCTL3) |= FLLREFDIV__16; + break; + default: + HWREG8(UCS_BASE + OFS_UCSCTL3) |= divider_msk; + break; + } + break; + default: + break; + } +} + +bool ucs_xt2_blocking_turn_on(uint16_t drive, uint16_t timeout) +{ + // Check if drive value is expected one. + if ((HWREG16(UCS_BASE + OFS_UCSCTL6) & XT2DRIVE_3) != drive) { + // Clear XT2 drive field. + HWREG16(UCS_BASE + OFS_UCSCTL6) &= ~XT2DRIVE_3; + HWREG16(UCS_BASE + OFS_UCSCTL6) |= drive; + } + + HWREG16(UCS_BASE + OFS_UCSCTL6) &= ~XT2BYPASS; + // Switch on XT2 oscillator. + HWREG16(UCS_BASE + OFS_UCSCTL6) &= ~XT2OFF; + + do { + // Clear OSC fault Flags. + HWREG8(UCS_BASE + OFS_UCSCTL7) &= ~XT2OFFG; + // Clear OFIFG fault flag. + HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; + } while ((HWREG8(UCS_BASE + OFS_UCSCTL7) & XT2OFFG) && --timeout); + + return timeout > 0; +} + +void ucs_xt2_turn_off(void) +{ + HWREG16(UCS_BASE + OFS_UCSCTL6) |= XT2OFF; +} + +void ucs_fll_settle_init(uint16_t fsystem, uint16_t ratio) +{ + volatile uint16_t x = ratio * 32; + ucs_fll_init(fsystem, ratio); + while (x--) { + __delay_cycles(30); + } +} diff --git a/examples/baremetal/msp430f5529/nes-gamepads/ucs.h b/examples/baremetal/msp430f5529/nes-gamepads/ucs.h new file mode 100644 index 000000000..1741c37ff --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/ucs.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MSP430_UCS_H +#define MSP430_UCS_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum ucs_signal { + UCS_ACLK = 0x01, + UCS_MCLK = 0x02, + UCS_SMCLK = 0x04, + UCS_FLLREF = 0x08 +}; + +enum ucs_source { + UCS_XT1CLK_SELECT, + UCS_VLOCLK_SELECT, + UCS_REFOCLK_SELECT, + UCS_DCOCLK_SELECT, + UCS_DCOCLKDIV_SELECT, + UCS_XT2CLK_SELECT +}; + +enum ucs_divider { + UCS_CLOCK_DIVIDER_1, + UCS_CLOCK_DIVIDER_2, + UCS_CLOCK_DIVIDER_4, + UCS_CLOCK_DIVIDER_8, + UCS_CLOCK_DIVIDER_12, + UCS_CLOCK_DIVIDER_16, + UCS_CLOCK_DIVIDER_32 +}; + +enum ucs_fault_flag { + UCS_XT2OFFG, + UCS_XT1HFOFFG, + UCS_XT1LFOFFG, + UCS_DCOFFG +}; + +void ucs_clocks_init(void); + +void ucs_init(enum ucs_signal signal, + enum ucs_source source, + enum ucs_divider divider); + +bool ucs_xt2_blocking_turn_on(uint16_t drive, uint16_t timeout); + +void ucs_xt2_turn_off(void); +void ucs_fll_settle_init(uint16_t fsystem, uint16_t ratio); + +#ifdef __cplusplus +} +#endif + +#endif // MSP430_UCS_H diff --git a/examples/baremetal/msp430f5529/nes-gamepads/usb.c b/examples/baremetal/msp430f5529/nes-gamepads/usb.c new file mode 100644 index 000000000..2a6485803 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/usb.c @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "gpio.h" +#include "hid.h" +#include "hwdefs.h" +#include "ucs.h" +#include "usb.h" + +static uint16_t usb_khz_freq_get(void) +{ + uint16_t freq = 0; + const uint8_t selm_curr = (UCSCTL4_L & SELM_7); + if (selm_curr <= 4) { + uint16_t fll_ref_freq = 33; // It is 32.768 kHz. + if ((UCSCTL3_L & SELREF_7) >= 0x50) + fll_ref_freq = (4.0) * 1000; + + uint16_t flln_curr = (UCSCTL2 & 0x03FF) + 1; + if (selm_curr == SELM_3) { + uint16_t flld_curr = (UCSCTL2 & FLLD_7); + flld_curr >>= 12; + flln_curr <<= flld_curr; + } + + const uint8_t fll_ref_div = (UCSCTL3_L & FLLREFDIV_7); + if (fll_ref_div == 0) + freq = flln_curr * (fll_ref_freq / 1); + else if (fll_ref_div == 1) + freq = flln_curr * (fll_ref_freq / 2); + else if (fll_ref_div == 2) + freq = flln_curr * (fll_ref_freq / 4); + else if (fll_ref_div == 3) + freq = flln_curr * (fll_ref_freq / 8); + else if (fll_ref_div == 4) + freq = flln_curr * (fll_ref_freq / 12); + else if (fll_ref_div == 5) + freq = flln_curr * (fll_ref_freq / 16); + } else { + freq = (4.0) * 1000; + } + return freq >> (UCSCTL5_L & DIVM_7); +} + +static uint16_t usb_delay_250us_get(void) +{ + const uint16_t mclk_freq = usb_khz_freq_get(); + const uint16_t delay_250us = ((mclk_freq >> 6) | (mclk_freq >> 7) + | (mclk_freq >> 9)); + return delay_250us; +} + +static void usb_cfg_access_allow(bool allow) +{ + enum { ALLOW_KEY = 0x9628, DENIED_KEY = 0x9600 }; + USBKEYPID = allow ? ALLOW_KEY : DENIED_KEY; +} + +static bool usb_pll_enable(void) +{ + if (!(USBPWRCTL & USBBGVBV)) + return false; + + if ((USBCNF & USB_EN) && (USBPLLCTL & UPLLEN)) + return true; + + gpio_pins_set_as_pf_out(GPIO_PORT_P5, GPIO_PIN2); + gpio_pins_set_as_pf_out(GPIO_PORT_P5, GPIO_PIN3); + + usb_cfg_access_allow(true); + + if (!ucs_xt2_blocking_turn_on(XT2DRIVE_0, 50000)) + return false; + + USBPLLDIVB = USBPLL_SETCLK_4_0; + USBPLLCTL = UPFDEN | UPLLEN; + + const uint16_t delay_250us = usb_delay_250us_get(); + uint8_t j = 0; + do { + USBPLLIR = 0; + for (uint8_t k = 0; k < 2; ++k) { + for (uint16_t i = 0; i < delay_250us; ++i) { + __no_operation(); + } + } + + if (j++ > 10) { + usb_cfg_access_allow(false); + return false; + } + } while (USBPLLIR != 0); + + USBCNF |= USB_EN; + usb_cfg_access_allow(false); + return true; +} + +static void usb_reset(void) +{ + usb_cfg_access_allow(true); + + hid_ep0_enumerated_set(false); + + USBCTL = 0; + USBFUNADR = 0; + USBOEPIE = 0; + USBIEPIE = 0; + + hid_ep0_init(); + hid_ep1_init(); + + USBCTL = FEN; + USBIFG = 0; + USBIE = SETUPIE | RSTRIE | SUSRIE; + usb_cfg_access_allow(false); +} + +static void usb_connect(void) +{ + usb_cfg_access_allow(true); + USBCNF |= PUR_EN; + USBPWRCTL |= VBOFFIE; + usb_cfg_access_allow(false); +} + +static void usb_pwr_vbus_wait(void) +{ + const uint16_t delay_250us = usb_delay_250us_get(); + for (uint8_t j = 0; j < 4; ++j) { + for (uint16_t i = 0; i < delay_250us; ++i) { + __no_operation(); + } + } +} + +static void usb_pwr_vbus_on_handler(void) +{ + usb_pwr_vbus_wait(); + + if (USBPWRCTL & USBBGVBV) { + usb_cfg_access_allow(true); + USBPWRCTL |= VBOFFIE; + USBPWRCTL &= ~ (VBONIFG + VBOFFIFG); + usb_cfg_access_allow(false); + } +} + +static void usb_pwr_vbus_off_handler(void) +{ + usb_pwr_vbus_wait(); + + if (!(USBPWRCTL & USBBGVBV)) { + usb_cfg_access_allow(true); + USBCNF = 0; + USBPLLCTL &= ~UPLLEN; + USBPWRCTL &= ~(VBOFFIE + VBOFFIFG + SLDOEN); + usb_cfg_access_allow(false); + } +} + +void usb_suspend(void) +{ + usb_cfg_access_allow(true); + USBCTL |= FRSTE; + USBIFG &= ~SUSRIFG; + USBPLLCTL &= ~UPLLEN; + ucs_xt2_turn_off(); + USBIE = RESRIE; + usb_cfg_access_allow(false); +} + +void usb_resume(void) +{ + usb_pll_enable(); + USBIFG &= ~(RESRIFG | SUSRIFG); + USBIE = SETUPIE | RSTRIE | SUSRIE; +} + +void usb_init(void) +{ + const uint16_t gie_backup = (__get_SR_register() & GIE); + + usb_cfg_access_allow(true); + USBPHYCTL = PUSEL; + USBPWRCTL = VUSBEN | SLDOAON; + + const uint16_t delay_250us = usb_delay_250us_get(); + for (uint8_t j = 0; j < 20; ++j) { + for (uint16_t i = 0; i < delay_250us; ++i) { + __no_operation(); + } + } + + USBPWRCTL |= VBONIE; + usb_cfg_access_allow(false); + + __bis_SR_register(gie_backup); + + if (USBPWRCTL & USBBGVBV) { + if (usb_pll_enable()) { + usb_reset(); + usb_connect(); + } + } +} + +void usb_task(void) +{ + hid_ep1_task(); +} + +INTERRUPT(usb_ubm_isr, USB_UBM_VECTOR) +{ + bool wake_up = false; + + if (USBIFG & SETUPIFG) { + hid_ep0_setup_handler(); + USBIFG &= ~SETUPIFG; + } + + switch (__even_in_range(USBVECINT & 0x3F, USBVECINT_OUTPUT_ENDPOINT7)) { + case USBVECINT_PWR_DROP: + __no_operation(); + break; + case USBVECINT_PLL_RANGE: + wake_up = true; + break; + case USBVECINT_PWR_VBUSOn: + usb_pwr_vbus_on_handler(); + if (usb_pll_enable()) { + usb_reset(); + usb_connect(); + } + wake_up = true; + break; + case USBVECINT_PWR_VBUSOff: + usb_pwr_vbus_off_handler(); + ucs_xt2_turn_off(); + wake_up = true; + break; + case USBVECINT_INPUT_ENDPOINT0: + hid_ep0_in_handler(); + break; + case USBVECINT_RSTR: + usb_reset(); + wake_up = true; + break; + case USBVECINT_SUSR: + usb_suspend(); + wake_up = true; + break; + case USBVECINT_RESR: + usb_resume(); + wake_up = true; + break; + case USBVECINT_SETUP_PACKET_RECEIVED: + hid_ep0_in_nak(); + hid_ep0_out_nak(); + hid_ep0_setup_handler(); + break; + default: + break; + } + + if (wake_up) { + __bic_SR_register_on_exit(LPM3_bits); + __no_operation(); + } +} diff --git a/examples/baremetal/msp430f5529/nes-gamepads/usb.h b/examples/baremetal/msp430f5529/nes-gamepads/usb.h new file mode 100644 index 000000000..503f3cf07 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/usb.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MSP430_USB_H +#define MSP430_USB_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum usb_setup_bmreq_bits { + SETUP_DIR = 0x80, + SETUP_TYPE = 0x60, + SETUP_RECIPIENT = 0x1F +}; + +// Setup request direction. +enum usb_setup_req_direction_bits { + SETUP_OUTPUT = 0, // From host to device direction. + SETUP_INPUT = 0x80 // From device to host direction. +}; + +// Setup request type. +enum usb_setup_req_type_bits { + SETUP_STANDARD = 0, // Standard request. + SETUP_CLASS = 0x20, // Class request. + SETUP_VENDOR = 0x40 // Vendor request. +}; + +// Setup request recipient. +enum usb_setup_req_recipient_bits { + SETUP_DEVICE = 0, // Device recipient. + SETUP_IFACE = 0x01, // Interface recipient. + SETUP_EP = 0x02, // End point recipient. + SETUP_OTHER = 0x03 // Other recipient. +}; + +// Setup request code. +enum usb_setup_req_code { + SETUP_GET_STATUS = 0x00, // Get status code. + SETUP_CLEAR_FEATURE = 0x01, // Clear feature code. + SETUP_RESERVED1 = 0x02, // Reserved code. + SETUP_SET_FEATURE = 0x03, // Set feature code. + SETUP_RESERVED2 = 0x04, // Reserved code. + SETUP_SET_ADDRESS = 0x05, // Set address code. + SETUP_GET_DESCRIPTOR = 0x06, // Get descriptor code. + SETUP_SET_DESCRIPTOR = 0x07, // Set descriptor code. + SETUP_GET_CONFIGURATION = 0x08, // Get configuration code. + SETUP_SET_CONFIGURATION = 0x09, // Set configuration code. + SETUP_GET_INTERFACE = 0x0A, // Get interface code. + SETUP_SET_INTERFACE = 0x0B, // Set interface code. + SETUP_SYNC_FRAME = 0x0C, // Sync frame code. + SETUP_ANCHOR_LOAD = 0xA0 // Anchor load code. +}; + +// Standard status responses. +enum usb_setup_status_code { + STATUS_SELF_POWERED = 0x01, + STATUS_REMOTE_WAKEUP = 0x02 +}; + +// Standard feature selectors. +enum usb_setup_feature_selector { + FEATURE_STALL = 0x00, + FEATURE_REMOTE_WAKEUP = 0x01, + FEATURE_TEST_MODE = 0x02 +}; + +// Get descriptor codes. +enum usb_setup_get_descriptor_code { + DESC_DEVICE = 0x01, // Device descriptor. + DESC_CONF = 0x02, // Configuration descriptor. + DESC_STRING = 0x03, // String descriptor. + DESC_INTERFACE = 0x04, // Interface descriptor. + DESC_ENDPOINT = 0x05, // End point descriptor. + DESC_DEVICE_QUAL = 0x06, // Device qualifier descriptor. + DESC_OTHER_SPEED_CONF = 0x07, // Other configuration descriptor. + DESC_INTERFACE_POWER = 0x08, // Interface power descriptor. + DESC_OTG = 0x09, // OTG descriptor. + DESC_DEBUG = 0x0A, // Debug descriptor. + DESC_INTERFACE_ASSOC = 0x0B, // Interface association descriptor. + DESC_HID = 0x21, // Get HID descriptor. + DESC_REPORT = 0x22 // Get report descriptor. +}; + + +enum usb_ep_size { + EP0_MAX_PACKET_SIZE = 8, + EP_MAX_PACKET_SIZE = 64, + EP_MAX_FIFO_SIZE = 256, + EP_NO_MORE_DATA = 0xFFFF +}; + +void usb_init(void); +void usb_task(void); + +#ifdef __cplusplus +} +#endif + +#endif // MSP430_USB_H diff --git a/examples/baremetal/msp430f5529/nes-gamepads/wdt_a.c b/examples/baremetal/msp430f5529/nes-gamepads/wdt_a.c new file mode 100644 index 000000000..5adf3c361 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/wdt_a.c @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hwdefs.h" +#include "wdt_a.h" + +#define WDT_CONTROL_ADDRESS (WDT_A_BASE + OFS_WDTCTL) + +void wdt_a_stop(void) +{ + const uint8_t st = (HWREG16(WDT_CONTROL_ADDRESS) & 0x00FF) | WDTHOLD; + HWREG16(WDT_CONTROL_ADDRESS) = WDTPW + st; +} diff --git a/examples/baremetal/msp430f5529/nes-gamepads/wdt_a.h b/examples/baremetal/msp430f5529/nes-gamepads/wdt_a.h new file mode 100644 index 000000000..3a5e5b407 --- /dev/null +++ b/examples/baremetal/msp430f5529/nes-gamepads/wdt_a.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qbs. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MSP430_WDT_A_H +#define MSP430_WDT_A_H + +#ifdef __cplusplus +extern "C" { +#endif + +void wdt_a_stop(void); + +#ifdef __cplusplus +} +#endif + +#endif // MSP430_WDT_A_H |