nrf: Add tinyusb support for nrf52840.

Add nrf-port finyusb driver files. USB CDC can be activated
by board configuration files using the MICROPY_HW_USB_CDC.

Updating BLE driver, Makefile, nrfx-glue and main.c to plug
in the tinyusb stack.
This commit is contained in:
Glenn Ruben Bakke 2019-10-09 20:01:51 +02:00
parent 1571120dc2
commit 60b0b69f20
10 changed files with 485 additions and 1 deletions

View File

@ -66,6 +66,7 @@ INC += -I../../lib/nrfx/drivers
INC += -I../../lib/nrfx/drivers/include INC += -I../../lib/nrfx/drivers/include
INC += -I../../lib/nrfx/mdk INC += -I../../lib/nrfx/mdk
INC += -I../../lib/nrfx/hal INC += -I../../lib/nrfx/hal
INC += -I../../lib/nrfx/drivers/src/
MCU_VARIANT_UPPER = $(shell echo $(MCU_VARIANT) | tr '[:lower:]' '[:upper:]') MCU_VARIANT_UPPER = $(shell echo $(MCU_VARIANT) | tr '[:lower:]' '[:upper:]')
MCU_SUB_VARIANT_UPPER = $(shell echo $(MCU_SUB_VARIANT) | tr '[:lower:]' '[:upper:]') MCU_SUB_VARIANT_UPPER = $(shell echo $(MCU_SUB_VARIANT) | tr '[:lower:]' '[:upper:]')
@ -183,6 +184,8 @@ SRC_NRFX += $(addprefix lib/nrfx/drivers/src/,\
nrfx_pwm.c \ nrfx_pwm.c \
nrfx_gpiote.c \ nrfx_gpiote.c \
nrfx_nvmc.c \ nrfx_nvmc.c \
nrfx_power.c \
nrfx_clock.c \
) )
SRC_C += \ SRC_C += \
@ -198,6 +201,34 @@ SRC_C += \
drivers/bluetooth/ble_drv.c \ drivers/bluetooth/ble_drv.c \
drivers/bluetooth/ble_uart.c \ drivers/bluetooth/ble_uart.c \
ifeq ($(MCU_SUB_VARIANT), nrf52840)
INC += -I./drivers/usb
INC += -I../../lib/tinyusb/src
# If SoftDevice is selected.
ifneq ($(SD), )
# For external tinyusb drivers to enable SoftDevice mode.
CFLAGS += -DSOFTDEVICE_PRESENT
endif
SRC_C += $(addprefix drivers/usb/,\
usb_cdc.c \
usb_descriptors.c \
)
SRC_C += $(addprefix lib/tinyusb/src/,\
common/tusb_fifo.c \
device/usbd.c \
device/usbd_control.c \
class/cdc/cdc_device.c \
tusb.c \
portable/nordic/nrf5x/dcd_nrf5x.c \
portable/nordic/nrf5x/hal_nrf5x.c \
)
endif
DRIVERS_SRC_C += $(addprefix modules/,\ DRIVERS_SRC_C += $(addprefix modules/,\
machine/modmachine.c \ machine/modmachine.c \
machine/uart.c \ machine/uart.c \

View File

@ -40,6 +40,10 @@
#include "mphalport.h" #include "mphalport.h"
#if MICROPY_HW_USB_CDC
#include "usb_cdc.h"
#endif
#define BLE_DRIVER_VERBOSE 0 #define BLE_DRIVER_VERBOSE 0
#if BLE_DRIVER_VERBOSE #if BLE_DRIVER_VERBOSE
@ -952,6 +956,10 @@ static void sd_evt_handler(uint32_t evt_id) {
// unhandled event! // unhandled event!
break; break;
} }
#if MICROPY_HW_USB_CDC
// Farward SOC events to USB CDC driver.
usb_cdc_sd_event_handler(evt_id);
#endif
} }
static void ble_evt_handler(ble_evt_t * p_ble_evt) { static void ble_evt_handler(ble_evt_t * p_ble_evt) {

View File

@ -0,0 +1,44 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_NRF_TUSB_CONFIG_H
#define MICROPY_INCLUDED_NRF_TUSB_CONFIG_H
// Common configuration
#define CFG_TUSB_MCU OPT_MCU_NRF5X
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
#define CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
// Device configuration
#define CFG_TUD_ENDOINT0_SIZE (64)
#define CFG_TUD_CDC (1)
#define CFG_TUD_CDC_RX_BUFSIZE (64)
#define CFG_TUD_CDC_TX_BUFSIZE (64)
#endif // MICROPY_INCLUDED_NRF_TUSB_CONFIG_H

View File

@ -0,0 +1,226 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
* Copyright (c) 2019 Glenn Ruben Bakke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#include "py/mphal.h"
#if MICROPY_HW_USB_CDC
#include "tusb.h"
#include "nrfx.h"
#include "nrfx_power.h"
#include "nrfx_uart.h"
#include "py/ringbuf.h"
#ifdef BLUETOOTH_SD
#include "nrf_sdm.h"
#include "nrf_soc.h"
#include "ble_drv.h"
#endif
extern void tusb_hal_nrf_power_event(uint32_t event);
static void cdc_task(void);
static uint8_t rx_ringbuf_array[1024];
static uint8_t tx_ringbuf_array[1024];
static volatile ringbuf_t rx_ringbuf;
static volatile ringbuf_t tx_ringbuf;
static void board_init(void) {
// Config clock source.
#ifndef BLUETOOTH_SD
NRF_CLOCK->LFCLKSRC = (uint32_t)((CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos) & CLOCK_LFCLKSRC_SRC_Msk);
NRF_CLOCK->TASKS_LFCLKSTART = 1UL;
#endif
// Priorities 0, 1, 4 (nRF52) are reserved for SoftDevice
// 2 is highest for application
NRFX_IRQ_PRIORITY_SET(USBD_IRQn, 2);
// USB power may already be ready at this time -> no event generated
// We need to invoke the handler based on the status initially
uint32_t usb_reg;
#ifdef BLUETOOTH_SD
uint8_t sd_en = false;
sd_softdevice_is_enabled(&sd_en);
if (sd_en) {
sd_power_usbdetected_enable(true);
sd_power_usbpwrrdy_enable(true);
sd_power_usbremoved_enable(true);
sd_power_usbregstatus_get(&usb_reg);
} else
#endif
{
// Power module init
const nrfx_power_config_t pwr_cfg = { 0 };
nrfx_power_init(&pwr_cfg);
// Register tusb function as USB power handler
const nrfx_power_usbevt_config_t config = { .handler = (nrfx_power_usb_event_handler_t) tusb_hal_nrf_power_event };
nrfx_power_usbevt_init(&config);
nrfx_power_usbevt_enable();
usb_reg = NRF_POWER->USBREGSTATUS;
}
if (usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk) {
tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_DETECTED);
}
#ifndef BLUETOOTH_SD
if (usb_reg & POWER_USBREGSTATUS_OUTPUTRDY_Msk) {
tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_READY);
}
#endif
}
static bool cdc_rx_any(void) {
return rx_ringbuf.iput != rx_ringbuf.iget;
}
static int cdc_rx_char(void) {
return ringbuf_get((ringbuf_t*)&rx_ringbuf);
}
static bool cdc_tx_any(void) {
return tx_ringbuf.iput != tx_ringbuf.iget;
}
static int cdc_tx_char(void) {
return ringbuf_get((ringbuf_t*)&tx_ringbuf);
}
static void cdc_task(void)
{
if ( tud_cdc_connected() ) {
// connected and there are data available
while (tud_cdc_available()) {
int c;
uint32_t count = tud_cdc_read(&c, 1);
(void)count;
ringbuf_put((ringbuf_t*)&rx_ringbuf, c);
}
int chars = 0;
while (cdc_tx_any()) {
if (chars < 64) {
tud_cdc_write_char(cdc_tx_char());
chars++;
} else {
chars = 0;
tud_cdc_write_flush();
}
}
tud_cdc_write_flush();
}
}
static void usb_cdc_loop(void) {
tud_task();
cdc_task();
}
int usb_cdc_init(void)
{
static bool initialized = false;
if (!initialized) {
#if BLUETOOTH_SD
// Initialize the clock and BLE stack.
ble_drv_stack_enable();
#endif
board_init();
initialized = true;
}
rx_ringbuf.buf = rx_ringbuf_array;
rx_ringbuf.size = sizeof(rx_ringbuf_array);
rx_ringbuf.iget = 0;
rx_ringbuf.iput = 0;
tx_ringbuf.buf = tx_ringbuf_array;
tx_ringbuf.size = sizeof(tx_ringbuf_array);
tx_ringbuf.iget = 0;
tx_ringbuf.iput = 0;
tusb_init();
return 0;
}
#ifdef BLUETOOTH_SD
// process SOC event from SD
void usb_cdc_sd_event_handler(uint32_t soc_evt) {
/*------------- usb power event handler -------------*/
int32_t usbevt = (soc_evt == NRF_EVT_POWER_USB_DETECTED ) ? NRFX_POWER_USB_EVT_DETECTED:
(soc_evt == NRF_EVT_POWER_USB_POWER_READY) ? NRFX_POWER_USB_EVT_READY :
(soc_evt == NRF_EVT_POWER_USB_REMOVED ) ? NRFX_POWER_USB_EVT_REMOVED : -1;
if (usbevt >= 0) {
tusb_hal_nrf_power_event(usbevt);
}
}
#endif
int mp_hal_stdin_rx_chr(void) {
for (;;) {
usb_cdc_loop();
if (cdc_rx_any()) {
return cdc_rx_char();
}
}
return 0;
}
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
for (const char *top = str + len; str < top; str++) {
ringbuf_put((ringbuf_t*)&tx_ringbuf, *str);
usb_cdc_loop();
}
}
void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) {
for (const char *top = str + len; str < top; str++) {
if (*str == '\n') {
ringbuf_put((ringbuf_t*)&tx_ringbuf, '\r');
usb_cdc_loop();
}
ringbuf_put((ringbuf_t*)&tx_ringbuf, *str);
usb_cdc_loop();
}
}
#endif // MICROPY_HW_USB_CDC

View File

@ -0,0 +1,40 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Glenn Ruben Bakke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef NRF_DRIVERS_USB_CDC_H__
#define NRF_DRIVERS_USB_CDC_H__
#include "tusb.h"
void usb_cdc_init(void);
void usb_cdc_loop(void);
int usb_cdc_read_char(void);
void usb_cdc_write_char(char c);
void usb_cdc_sd_event_handler(uint32_t soc_evt);
#endif // NRF_DRIVERS_USB_CDC_H__

View File

@ -0,0 +1,114 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "tusb.h"
#define USBD_VID (0xf055)
#define USBD_PID (0x9802)
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
#define USBD_MAX_POWER_MA (250)
#define USBD_ITF_CDC (0) // needs 2 interfaces
#define USBD_ITF_MAX (2)
#define USBD_CDC_EP_CMD (0x81)
#define USBD_CDC_EP_OUT (0x02)
#define USBD_CDC_EP_IN (0x82)
#define USBD_CDC_CMD_MAX_SIZE (8)
#define USBD_STR_0 (0x00)
#define USBD_STR_MANUF (0x01)
#define USBD_STR_PRODUCT (0x02)
#define USBD_STR_SERIAL (0x03)
#define USBD_STR_CDC (0x04)
// Note: descriptors returned from callbacks must exist long enough for transfer to complete
static const tusb_desc_device_t usbd_desc_device = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE,
.idVendor = USBD_VID,
.idProduct = USBD_PID,
.bcdDevice = 0x0100,
.iManufacturer = USBD_STR_MANUF,
.iProduct = USBD_STR_PRODUCT,
.iSerialNumber = USBD_STR_SERIAL,
.bNumConfigurations = 1,
};
static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
TUD_CONFIG_DESCRIPTOR(USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN,
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA),
TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD,
USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, CFG_TUD_CDC_RX_BUFSIZE),
};
static const char *const usbd_desc_str[] = {
[USBD_STR_MANUF] = "MicroPython",
[USBD_STR_PRODUCT] = "Board in FS mode",
[USBD_STR_SERIAL] = "000000000000", // TODO
[USBD_STR_CDC] = "Board CDC",
};
const uint8_t *tud_descriptor_device_cb(void) {
return (const uint8_t*)&usbd_desc_device;
}
const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
(void)index;
return usbd_desc_cfg;
}
const uint16_t *tud_descriptor_string_cb(uint8_t index) {
#define DESC_STR_MAX (20)
static uint16_t desc_str[DESC_STR_MAX];
uint8_t len;
if (index == 0) {
desc_str[1] = 0x0409; // supported language is English
len = 1;
} else {
if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
return NULL;
}
const char* str = usbd_desc_str[index];
for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
desc_str[1 + len] = str[len];
}
}
// first byte is len, second byte is string type
desc_str[0] = TUD_DESC_STR_HEADER(len);
return desc_str;
}

View File

@ -70,6 +70,10 @@
#include "softpwm.h" #include "softpwm.h"
#endif #endif
#if MICROPY_HW_USB_CDC
#include "usb_cdc.h"
#endif
void do_str(const char *src, mp_parse_input_kind_t input_kind) { void do_str(const char *src, mp_parse_input_kind_t input_kind) {
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
if (lex == NULL) { if (lex == NULL) {
@ -121,6 +125,7 @@ soft_reset:
readline_init0(); readline_init0();
#if MICROPY_PY_MACHINE_HW_SPI #if MICROPY_PY_MACHINE_HW_SPI
spi_init0(); spi_init0();
#endif #endif
@ -149,7 +154,7 @@ soft_reset:
uart_init0(); uart_init0();
#endif #endif
#if (MICROPY_PY_BLE_NUS == 0) #if (MICROPY_PY_BLE_NUS == 0) && (MICROPY_HW_USB_CDC == 0)
{ {
mp_obj_t args[2] = { mp_obj_t args[2] = {
MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_NEW_SMALL_INT(0),
@ -231,6 +236,10 @@ led_state(1, 0);
pyexec_file_if_exists("main.py"); pyexec_file_if_exists("main.py");
#endif #endif
#if MICROPY_HW_USB_CDC
usb_cdc_init();
#endif
for (;;) { for (;;) {
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
if (pyexec_raw_repl() != 0) { if (pyexec_raw_repl() != 0) {

View File

@ -62,7 +62,9 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
} }
return ret; return ret;
} }
#endif
#if !MICROPY_PY_BLE_NUS && !MICROPY_HW_USB_CDC
int mp_hal_stdin_rx_chr(void) { int mp_hal_stdin_rx_chr(void) {
for (;;) { for (;;) {
if (MP_STATE_PORT(board_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(board_stdio_uart))) { if (MP_STATE_PORT(board_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(board_stdio_uart))) {

View File

@ -47,6 +47,14 @@
#define GPIO_COUNT 2 #define GPIO_COUNT 2
#endif #endif
#if defined(NRF52840)
// for tinyusb
//#define NRFX_IRQ_IS_ENABLED 1
#define NRFX_POWER_ENABLED 1
#define NRFX_POWER_CONFIG_IRQ_PRIORITY 2
#define NRFX_SYSTICK_ENABLED 1
#endif
#define NRFX_GPIOTE_ENABLED 1 #define NRFX_GPIOTE_ENABLED 1
#define NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 1 #define NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 1
#if NRF51 #if NRF51

View File

@ -138,4 +138,6 @@
#endif // !BLUETOOTH_SD #endif // !BLUETOOTH_SD
#define NRFX_IRQ_IS_ENABLED(irq_number) (0 != (NVIC->ISER[irq_number / 32] & (1UL << (irq_number % 32))))
#endif // NRFX_GLUE_H #endif // NRFX_GLUE_H