aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/baremetal/msp430f5529/msp430f5529.qbs3
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/README.md36
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/gamepads.ld57
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/gpio.c167
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/gpio.h110
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/hid.h116
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/hiddesc.c303
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/hidep0.c554
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/hidep1.c214
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/hwdefs.h81
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/main.c92
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/nes-gamepads.qbs148
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/pmm.c237
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/pmm.h73
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/ucs.c264
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/ucs.h106
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/usb.c317
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/usb.h148
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/wdt_a.c60
-rw-r--r--examples/baremetal/msp430f5529/nes-gamepads/wdt_a.h64
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