Error in makefile

main
Adam Procházka 2 years ago
parent 9d50a83a78
commit 276d443bb1

File diff suppressed because one or more lines are too long

@ -0,0 +1,9 @@
{
"files.associations": {
"cdc_device.h": "c",
"tusb_option.h": "c",
"tusb.h": "c",
"stdbool.h": "c"
},
"C_Cpp.errorSquiggles": "disabled"
}

@ -29,28 +29,37 @@ extern "C"
/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_hal.h"
#include "Cam.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "stdbool.h"
#include "tusb.h"
/* USER CODE END ET */
// #include "portable/st/synopsys/dcd_synopsys.c"
// #include "portable/st/synopsys/synopsys_common.h"
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END Includes */
/* USER CODE END EC */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END ET */
/* USER CODE END EM */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
@ -74,9 +83,9 @@ extern "C"
#define LD3_Pin GPIO_PIN_3
#define LD3_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}

@ -63,7 +63,7 @@
/*#define HAL_OPAMP_MODULE_ENABLED */
/*#define HAL_OSPI_MODULE_ENABLED */
/*#define HAL_OSPI_MODULE_ENABLED */
/*#define HAL_PCD_MODULE_ENABLED */
#define HAL_PCD_MODULE_ENABLED
/*#define HAL_PKA_MODULE_ENABLED */
/*#define HAL_QSPI_MODULE_ENABLED */
/*#define HAL_QSPI_MODULE_ENABLED */

@ -58,6 +58,7 @@ void SysTick_Handler(void);
void DMA1_Channel2_IRQHandler(void);
void DMA1_Channel3_IRQHandler(void);
void USART2_IRQHandler(void);
void USB_IRQHandler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */

@ -0,0 +1,121 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C"
{
#endif
//--------------------------------------------------------------------+
// Board Specific Configuration
//--------------------------------------------------------------------+
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_TUD_RHPORT
#define BOARD_TUD_RHPORT 0
#endif
// RHPort max operational speed can defined by board.mk
#ifndef BOARD_TUD_MAX_SPEED
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
//--------------------------------------------------------------------
// Common Configuration
//--------------------------------------------------------------------
#define CFG_TUSB_MCU OPT_MCU_STM32L4
#define CFG_TUSB_OS OPT_OS_NONE
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#define BOARD_DEVICE_RHPORT_NUM 0
#define CFG_TUSB_RHPORT_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED)
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif
// Enable Device stack
#define CFG_TUD_ENABLED 1
// Default is max speed that hardware controller could support with on-chip PHY
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4)))
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
#define CFG_TUD_CDC 1
#define CFG_TUD_MSC 0
#define CFG_TUD_HID 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
// CDC Endpoint transfer buffer size, more is faster
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
// MSC Buffer size of Device Mass storage
#define CFG_TUD_MSC_EP_BUFSIZE 512
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

@ -21,6 +21,7 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@ -46,6 +47,8 @@ DMA_HandleTypeDef hdma_spi1_tx;
UART_HandleTypeDef huart2;
PCD_HandleTypeDef hpcd_USB_FS;
/* USER CODE BEGIN PV */
int SPI_Rx_Done_Flag = 0;
/* USER CODE END PV */
@ -57,6 +60,7 @@ static void MX_DMA_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_SPI1_Init(void);
static void MX_I2C1_Init(void);
static void MX_USB_PCD_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
@ -82,6 +86,7 @@ int main(void)
HAL_Init();
/* USER CODE BEGIN Init */
tusb_init();
/* USER CODE END Init */
@ -98,21 +103,24 @@ int main(void)
MX_USART2_UART_Init();
MX_SPI1_Init();
MX_I2C1_Init();
MX_USB_PCD_Init();
/* USER CODE BEGIN 2 */
HAL_Delay(10);
SPI_Init(&hspi1);
// HAL_Delay(10);
// SPI_Init(&hspi1);
// Wait for power stabilization
HAL_Delay(1000);
// HAL_Delay(1000);
Cam_Init(&hi2c1, &hspi1);
// Cam_Init(&hi2c1, &hspi1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
tud_task();
/*
Cam_Capture(&hspi1);
uint16_t image_size = Cam_FIFO_length(&hspi1);
@ -137,6 +145,7 @@ int main(void)
HAL_UART_Transmit(&huart2, image_data, image_size, HAL_MAX_DELAY);
Debug_LED_Off();
free(image_data);
*/
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
@ -163,8 +172,9 @@ void SystemClock_Config(void)
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48 | RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
@ -312,6 +322,38 @@ static void MX_USART2_UART_Init(void)
/* USER CODE END USART2_Init 2 */
}
/**
* @brief USB Initialization Function
* @param None
* @retval None
*/
static void MX_USB_PCD_Init(void)
{
/* USER CODE BEGIN USB_Init 0 */
/* USER CODE END USB_Init 0 */
/* USER CODE BEGIN USB_Init 1 */
/* USER CODE END USB_Init 1 */
hpcd_USB_FS.Instance = USB;
hpcd_USB_FS.Init.dev_endpoints = 8;
hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
hpcd_USB_FS.Init.Sof_enable = DISABLE;
hpcd_USB_FS.Init.low_power_enable = DISABLE;
hpcd_USB_FS.Init.lpm_enable = DISABLE;
hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USB_Init 2 */
/* USER CODE END USB_Init 2 */
}
/**
* Enable DMA controller clock
*/

@ -0,0 +1,277 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
#if CFG_TUD_MSC
// whether host does safe-eject
static bool ejected = false;
// Some MCU doesn't have enough 8KB SRAM to store the whole disk
// We will use Flash as read-only disk with board that has
// CFG_EXAMPLE_MSC_READONLY defined
#define README_CONTENTS \
"This is tinyusb's MassStorage Class demo.\r\n\r\n\
If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb"
enum
{
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
DISK_BLOCK_SIZE = 512
};
#ifdef CFG_EXAMPLE_MSC_READONLY
const
#endif
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
{
//------------- Block0: Boot Sector -------------//
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
// sector_per_cluster = 1; reserved_sectors = 1;
// fat_num = 1; fat12_root_entry_num = 16;
// sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
// drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
// filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
// FAT magic code at offset 510-511
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U',
'S', 'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
// Zero up to 2 last bytes of FAT magic code
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA},
//------------- Block1: FAT12 Table -------------//
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
},
//------------- Block2: Root Directory -------------//
{
// first entry is volume label
'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// second entry is readme file
'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(README_CONTENTS) - 1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
},
//------------- Block3: Readme Content -------------//
README_CONTENTS};
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{
(void)lun;
const char vid[] = "TinyUSB";
const char pid[] = "Mass Storage";
const char rev[] = "1.0";
memcpy(vendor_id, vid, strlen(vid));
memcpy(product_id, pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun)
{
(void)lun;
// RAM disk is ready until ejected
if (ejected)
{
// Additional Sense 3A-00 is NOT_FOUND
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
return false;
}
return true;
}
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size)
{
(void)lun;
*block_count = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
}
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
(void)lun;
(void)power_condition;
if (load_eject)
{
if (start)
{
// load disk storage
}
else
{
// unload disk storage
ejected = true;
}
}
return true;
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize)
{
(void)lun;
// out of ramdisk
if (lba >= DISK_BLOCK_NUM)
return -1;
uint8_t const *addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
return (int32_t)bufsize;
}
bool tud_msc_is_writable_cb(uint8_t lun)
{
(void)lun;
#ifdef CFG_EXAMPLE_MSC_READONLY
return false;
#else
return true;
#endif
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize)
{
(void)lun;
// out of ramdisk
if (lba >= DISK_BLOCK_NUM)
return -1;
#ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t *addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
#else
(void)lba;
(void)offset;
(void)buffer;
#endif
return (int32_t)bufsize;
}
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize)
{
// read10 & write10 has their own callback and MUST not be handled here
void const *response = NULL;
int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
switch (scsi_cmd[0])
{
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
}
// return resplen must not larger than bufsize
if (resplen > bufsize)
resplen = bufsize;
if (response && (resplen > 0))
{
if (in_xfer)
{
memcpy(buffer, response, (size_t)resplen);
}
else
{
// SCSI output
}
}
return (int32_t)resplen;
}
#endif

@ -349,6 +349,67 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
}
/**
* @brief PCD MSP Initialization
* This function configures the hardware resources used in this example
* @param hpcd: PCD handle pointer
* @retval None
*/
void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
if(hpcd->Instance==USB)
{
/* USER CODE BEGIN USB_MspInit 0 */
/* USER CODE END USB_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
__HAL_RCC_USB_CLK_ENABLE();
/* USB interrupt Init */
HAL_NVIC_SetPriority(USB_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USB_IRQn);
/* USER CODE BEGIN USB_MspInit 1 */
/* USER CODE END USB_MspInit 1 */
}
}
/**
* @brief PCD MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hpcd: PCD handle pointer
* @retval None
*/
void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)
{
if(hpcd->Instance==USB)
{
/* USER CODE BEGIN USB_MspDeInit 0 */
/* USER CODE END USB_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USB_CLK_DISABLE();
/* USB interrupt DeInit */
HAL_NVIC_DisableIRQ(USB_IRQn);
/* USER CODE BEGIN USB_MspDeInit 1 */
/* USER CODE END USB_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */

@ -1,20 +1,20 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32l4xx_it.c
* @brief Interrupt Service Routines.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
******************************************************************************
* @file stm32l4xx_it.c
* @brief Interrupt Service Routines.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
@ -58,6 +58,7 @@
extern DMA_HandleTypeDef hdma_spi1_rx;
extern DMA_HandleTypeDef hdma_spi1_tx;
extern UART_HandleTypeDef huart2;
extern PCD_HandleTypeDef hpcd_USB_FS;
/* USER CODE BEGIN EV */
/* USER CODE END EV */
@ -242,6 +243,22 @@ void USART2_IRQHandler(void)
/* USER CODE END USART2_IRQn 1 */
}
/**
* @brief This function handles USB event interrupt through EXTI line 17.
*/
void USB_IRQHandler(void)
{
/* USER CODE BEGIN USB_IRQn 0 */
tud_int_handler(0);
return;
/* USER CODE END USB_IRQn 0 */
HAL_PCD_IRQHandler(&hpcd_USB_FS);
/* USER CODE BEGIN USB_IRQn 1 */
/* USER CODE END USB_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */

@ -0,0 +1,288 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
#define USB_VID 0xCafe
#define USB_BCD 0x0200
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_MSC,
ITF_NUM_TOTAL
};
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ...
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_MSC_OUT 0x05
#define EPNUM_MSC_IN 0x85
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x83
#define EPNUM_MSC_OUT 0x04
#define EPNUM_MSC_IN 0x85
#elif CFG_TUSB_MCU == OPT_MCU_CXD56
// CXD56 doesn't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
// CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number
// 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN)
#define EPNUM_CDC_NOTIF 0x83
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x81
#define EPNUM_MSC_OUT 0x05
#define EPNUM_MSC_IN 0x84
#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X
// FT9XX doesn't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x83
#define EPNUM_MSC_OUT 0x04
#define EPNUM_MSC_IN 0x85
#else
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_MSC_OUT 0x03
#define EPNUM_MSC_IN 0x83
#endif
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
// full speed configuration
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
};
#if TUD_OPT_HIGH_SPEED
// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
// high speed configuration
uint8_t const desc_hs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
};
// other speed configuration
uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
tusb_desc_device_qualifier_t const desc_device_qualifier =
{
.bLength = sizeof(tusb_desc_device_qualifier_t),
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
.bcdUSB = USB_BCD,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.bNumConfigurations = 0x01,
.bReserved = 0x00
};
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
uint8_t const* tud_descriptor_device_qualifier_cb(void)
{
return (uint8_t const*) &desc_device_qualifier;
}
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
// Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
CONFIG_TOTAL_LEN);
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
return desc_other_speed_config;
}
#endif // highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
"123456789012", // 3: Serials, should use chip ID
"TinyUSB CDC", // 4: CDC Interface
"TinyUSB MSC", // 5: MSC Interface
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
uint8_t chr_count;
if ( index == 0)
{
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}else
{
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > 31 ) chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}

@ -0,0 +1 @@
return USB0.INTSTS1.BIT.ATTCH ? true : false;

@ -0,0 +1,8 @@
synopsys
sie
tre
hsi
fro
dout
mot
te

@ -0,0 +1,10 @@
# See: https://github.com/codespell-project/codespell#using-a-config-file
[codespell]
# In the event of a false positive, add the problematic word, in all lowercase, to 'ignore-words.txt' (one word per line).
# Or copy & paste the whole problematic line to 'exclude-file.txt'
ignore-words = .codespell/ignore-words.txt
exclude-file = .codespell/exclude-file.txt
check-filenames =
check-hidden =
count =
skip = .cproject,./.git,./hw/mcu,./lib,./examples/*/*/_build,./examples/*/*/ses,./examples/*/*/ozone,./hw/mcu,./test/unit-test/vendor,./tests_obsolete,./tools/uf2

@ -0,0 +1,25 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
*.c text
*.cpp text
*.h text
*.icf text
*.js text
*.json text
*.ld text
*.md text
*.mk text
*.py text
*.rst text
*.s text
*.txt text
*.xml text
*.yml text
Makefile text
# Windows-only Visual Studio things
*.sln text eol=crlf
*.csproj text eol=crlf

@ -0,0 +1,86 @@
name: Bug Report
description: Report a problem with TinyUSB
labels: 'Bug 🐞'
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
It's okay to leave some blank if it doesn't apply to your problem.
- type: dropdown
attributes:
label: Operating System
options:
- Linux
- MacOS
- RaspberryPi OS
- Windows 7
- Windows 10
- Windows 11
- Others
validations:
required: true
- type: input
attributes:
label: Board
placeholder: e.g Feather nRF52840 Express
validations:
required: true
- type: textarea
attributes:
label: Firmware
placeholder: |
e.g examples/device/cdc_msc. If it is custom firmware, it is preferably compiled like one in example folder and reviewable for people to comment on. The easiest way is
- Fork this repo, checkout a new branch
- Add your-own-example based on stock one
- Push and post it here.
validations:
required: true
- type: textarea
attributes:
label: What happened ?
placeholder: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: How to reproduce ?
placeholder: |
Exact steps in chronological order, details should be specific e.g if you use a command/script to test with, please post it as well.
1. Go to '...'
2. Click on '....'
3. See error
validations:
required: true
- type: textarea
attributes:
label: Debug Log as txt file
placeholder: |
Attach your debug log txt file here, where the issue occurred, best with comments to explain the actual events.
Note1: Please DO NOT paste your lengthy log contents here since it hurts the readability.
Note2: To enable logging, add `LOG=3` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=3` in your tusb_config.h.
More information can be found at [example's readme](https://github.com/hathach/tinyusb/blob/master/docs/getting_started.md)
validations:
required: false
- type: textarea
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
validations:
required: false
- type: checkboxes
attributes:
label: I have checked existing issues, dicussion and documentation
description: You agree to check all the resources above before opening a new issue.
options:
- label: I confirm I have checked existing issues, dicussion and documentation.
required: true

@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: TinyUSB Discussion
url: https://github.com/hathach/tinyusb/discussions
about: If you have other questions or need help, post it here.
- name: TinyUSB Docs
url: https://docs.tinyusb.org/
about: Online documentation

@ -0,0 +1,49 @@
name: Feature Request
description: Suggest an idea for this project
labels: 'Feature 💡'
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this request!
It's okay to leave some blank if it doesn't apply to your request.
- type: input
attributes:
label: Related area
description: Please briefly explain the area of your Feature Request.
placeholder: eg. new port support, device stack, class driver ...
validations:
required: true
- type: input
attributes:
label: Hardware specification
description: Please provide if your proposal depends on specific Hardware.
placeholder: eg. rp2040, samd51 ...
validations:
required: true
- type: textarea
attributes:
label: Is your feature request related to a problem?
description: Please provide a clear and concise description of what the problem is. Add relevant issue link.
placeholder: ex. I'm facing the issue/missing function...
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like
description: Please provide a clear and concise description of what you want to happen.
placeholder: ex. When using this function...
validations:
required: true
- type: checkboxes
attributes:
label: I have checked existing issues, dicussion and documentation
description: You agree to check all the resources above before opening a new issue.
options:
- label: I confirm I have checked existing issues, dicussion and documentation.
required: true

@ -0,0 +1,5 @@
**Describe the PR**
A clear and concise description of what this PR solve.
**Additional context**
If applicable, add any other context about the PR and/or screenshots here.

@ -0,0 +1,86 @@
name: Build AArch64
on:
push:
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_aarch64.yml'
pull_request:
branches: [ master ]
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_aarch64.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
# ---------------------------------------
# Build AARCH64 family
# ---------------------------------------
build-arm:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
family:
# Alphabetical order
- 'broadcom_64bit'
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Checkout TinyUSB
uses: actions/checkout@v3
- name: Checkout common submodules in lib
run: git submodule update --init lib/FreeRTOS-Kernel lib/lwip lib/sct_neopixel
- name: Checkout hathach/linkermap
uses: actions/checkout@v3
with:
repository: hathach/linkermap
path: linkermap
- name: Set Toolchain URL
run: echo >> $GITHUB_ENV TOOLCHAIN_URL=https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz
- name: Cache Toolchain
uses: actions/cache@v3
id: cache-toolchain
with:
path: ~/cache/
key: ${{ runner.os }}-21-11-02-${{ env.TOOLCHAIN_URL }}
- name: Install Toolchain
if: steps.cache-toolchain.outputs.cache-hit != 'true'
run: |
mkdir -p ~/cache/toolchain
wget --progress=dot:mega $TOOLCHAIN_URL -O toolchain.tar.gz
tar -C ~/cache/toolchain -xaf toolchain.tar.gz
- name: Set Toolchain Path
run: echo >> $GITHUB_PATH `echo ~/cache/toolchain/*/bin`
- name: Get Dependencies
run: python3 tools/get_dependencies.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }}
- name: Linker Map
run: |
pip install linkermap/
for ex in `ls -d examples/device/*/`; do \
find ${ex} -name *.map -print -quit | \
xargs -I % sh -c 'echo "::group::%"; linkermap -v %; echo "::endgroup::"'; \
done

@ -0,0 +1,291 @@
name: Build ARM
on:
push:
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_arm.yml'
pull_request:
branches: [ master ]
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_arm.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
# ---------------------------------------
# Build ARM family
# ---------------------------------------
build-arm:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
family:
# Alphabetical order
- 'broadcom_32bit'
- 'imxrt'
- 'lpc15'
- 'lpc18'
- 'lpc54'
- 'lpc55'
- 'mm32'
- 'msp432e4'
- 'nrf'
- 'rp2040'
- 'samd11'
- 'samd21'
- 'samd51'
- 'saml2x'
- 'stm32f0'
- 'stm32f1'
- 'stm32f4'
- 'stm32f7'
- 'stm32g4'
- 'stm32h7'
- 'stm32l4'
- 'stm32wb'
- 'tm4c123'
- 'xmc4000'
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install ARM GCC
uses: carlosperate/arm-none-eabi-gcc-action@v1
with:
release: '11.2-2022.02'
- name: Checkout TinyUSB
uses: actions/checkout@v3
- name: Checkout common submodules in lib
run: git submodule update --init lib/FreeRTOS-Kernel lib/lwip lib/sct_neopixel
- name: Checkout hathach/linkermap
uses: actions/checkout@v3
with:
repository: hathach/linkermap
path: linkermap
- name: Checkout pico-sdk for rp2040
if: matrix.family == 'rp2040'
run: |
git clone --depth 1 -b develop https://github.com/raspberrypi/pico-sdk ~/pico-sdk
echo >> $GITHUB_ENV PICO_SDK_PATH=~/pico-sdk
- name: Get Dependencies
run: python3 tools/get_dependencies.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }}
- name: Linker Map
run: |
pip install linkermap/
# find -quit to only print linkermap of 1 board per example
for ex in `ls -d examples/*/*/`
do
find ${ex} -name *.map -print -quit | xargs -I % sh -c 'echo "::group::%"; linkermap -v %; echo "::endgroup::"'
done
# Upload binaries for rp2040 hardware test with self-hosted
- name: Prepare rp2040 Artifacts
if: matrix.family == 'rp2040' && github.repository_owner == 'hathach'
run: find examples/ -name "*.elf" -exec mv {} . \;
- name: Upload rp2040 Artifacts
if: matrix.family == 'rp2040' && github.repository_owner == 'hathach'
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.family }}
path: |
*.elf
# Upload binaries for stm32l412nucleo hardware test with self-hosted
- name: Prepare stm32l412nucleo Artifacts
if: matrix.family == 'stm32l4'
run: find examples/ -path "*stm32l412nucleo/*.elf" -exec mv {} . \;
- name: Upload stm32l412nucleo Artifacts
if: matrix.family == 'stm32l4'
uses: actions/upload-artifact@v3
with:
name: stm32l412nucleo
path: |
*.elf
# ---------------------------------------
# Build all no-family (orphaned) boards
# disable this workflow since it is often failed randomly
# ---------------------------------------
build-board:
runs-on: ubuntu-latest
if: false
strategy:
fail-fast: false
matrix:
example:
# Alphabetical order, a group of 4
- 'device/audio_test device/board_test device/cdc_dual_ports device/cdc_msc'
- 'device/cdc_msc_freertos device/dfu_runtime device/hid_composite device/hid_composite_freertos'
- 'device/hid_generic_inout device/hid_multiple_interface device/midi_test device/msc_dual_lun'
- 'device/net_lwip_webserver'
- 'device/uac2_headset device/usbtmc device/webusb_serial host/cdc_msc_hid'
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install ARM GCC
uses: carlosperate/arm-none-eabi-gcc-action@v1
with:
release: '11.2-2022.02'
- name: Checkout TinyUSB
uses: actions/checkout@v3
- name: Checkout common submodules in lib
run: git submodule update --init lib/FreeRTOS-Kernel lib/lwip
- name: Build
run: python3 tools/build_board.py ${{ matrix.example }}
# ---------------------------------------
# Hardware in the loop (HIL)
# Current self-hosted instance is running on an RPI4 with
# - pico + pico-probe connected via USB
# - pico-probe is /dev/ttyACM0
# ---------------------------------------
hw-rp2040-test:
# run only with hathach's commit due to limited resource on RPI4
if: github.repository_owner == 'hathach'
needs: build-arm
runs-on: [self-hosted, Linux, ARM64, rp2040]
steps:
- name: Clean workspace
run: |
echo "Cleaning up previous run"
rm -rf "${{ github.workspace }}"
mkdir -p "${{ github.workspace }}"
- name: Download rp2040 Artifacts
uses: actions/download-artifact@v3
with:
name: rp2040
- name: Create flash.sh
run: |
#echo > flash.sh 'cmdout=$(openocd -f "interface/picoprobe.cfg" -f "target/rp2040.cfg" -c "program $1 reset exit")'
echo > flash.sh 'pyocd flash -t rp2040 $1'
echo >> flash.sh 'if (( $? )) ; then echo $cmdout ; fi'
chmod +x flash.sh
- name: Test cdc_dual_ports
run: |
./flash.sh cdc_dual_ports.elf
while (! ([ -e /dev/ttyACM1 ] && [ -e /dev/ttyACM2 ])) && [ $SECONDS -le 10 ]; do :; done
test -e /dev/ttyACM1 && echo "ttyACM1 exists"
test -e /dev/ttyACM2 && echo "ttyACM2 exists"
- name: Test cdc_msc
run: |
./flash.sh cdc_msc.elf
readme='/media/pi/TinyUSB MSC/README.TXT'
while (! ([ -e /dev/ttyACM1 ] && [ -f "$readme" ])) && [ $SECONDS -le 10 ]; do :; done
test -e /dev/ttyACM1 && echo "ttyACM1 exists"
test -f "$readme" && echo "$readme exists"
cat "$readme"
- name: Test dfu
run: |
./flash.sh dfu.elf
while (! (dfu-util -l | grep "Found DFU")) && [ $SECONDS -le 10 ]; do :; done
dfu-util -d cafe -a 0 -U dfu0
dfu-util -d cafe -a 1 -U dfu1
grep "TinyUSB DFU! - Partition 0" dfu0
grep "TinyUSB DFU! - Partition 1" dfu1
- name: Test dfu_runtime
run: |
./flash.sh dfu_runtime.elf
while (! (dfu-util -l | grep "Found Runtime")) && [ $SECONDS -le 10 ]; do :; done
# ---------------------------------------
# Hardware in the loop (HIL)
# Current self-hosted instance is running on an EPYC 7232 server hosted by HiFiPhile user
# - STM32L412 Nucleo with on-board jlink as ttyACM0
# ---------------------------------------
hw-stm32l412nucleo-test:
needs: build-arm
runs-on: [self-hosted, Linux, X64, hifiphile]
steps:
- name: Clean workspace
run: |
echo "Cleaning up previous run"
rm -rf "${{ github.workspace }}"
mkdir -p "${{ github.workspace }}"
- name: Download stm32l4 Artifacts
uses: actions/download-artifact@v3
with:
name: stm32l412nucleo
- name: Create flash.sh
run: |
echo > flash.sh 'echo halt > flash.jlink'
echo >> flash.sh 'echo r >> flash.jlink'
echo >> flash.sh 'echo loadfile $1 >> flash.jlink'
echo >> flash.sh 'echo r >> flash.jlink'
echo >> flash.sh 'echo go >> flash.jlink'
echo >> flash.sh 'echo exit >> flash.jlink'
echo >> flash.sh 'cmdout=$(JLinkExe -device stm32l412kb -if swd -JTAGConf -1,-1 -speed auto -NoGui 1 -ExitOnError 1 -CommandFile flash.jlink)'
echo >> flash.sh 'if (( $? )) ; then echo $cmdout ; fi'
chmod +x flash.sh
- name: Test cdc_dual_ports
run: |
./flash.sh cdc_dual_ports.elf
while (! ([ -e /dev/ttyACM1 ] && [ -e /dev/ttyACM2 ])) && [ $SECONDS -le 10 ]; do :; done
test -e /dev/ttyACM1 && echo "ttyACM1 exists"
test -e /dev/ttyACM2 && echo "ttyACM2 exists"
# Debian does not auto mount usb drive. skip this test for now
- name: Test cdc_msc
if: false
run: |
./flash.sh cdc_msc.elf
readme='/media/pi/TinyUSB MSC/README.TXT'
while (! ([ -e /dev/ttyACM1 ] && [ -f "$readme" ])) && [ $SECONDS -le 10 ]; do :; done
test -e /dev/ttyACM1 && echo "ttyACM1 exists"
test -f "$readme" && echo "$readme exists"
cat "$readme"
- name: Test dfu
run: |
./flash.sh dfu.elf
while (! (dfu-util -l | grep "Found DFU")) && [ $SECONDS -le 10 ]; do :; done
dfu-util -d cafe -a 0 -U dfu0
dfu-util -d cafe -a 1 -U dfu1
grep "TinyUSB DFU! - Partition 0" dfu0
grep "TinyUSB DFU! - Partition 1" dfu1
- name: Test dfu_runtime
run: |
./flash.sh dfu_runtime.elf
while (! (dfu-util -l | grep "Found Runtime")) && [ $SECONDS -le 10 ]; do :; done

@ -0,0 +1,66 @@
name: Build ESP
on:
push:
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_esp.yml'
pull_request:
branches: [ master ]
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_esp.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
build-esp:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
board:
# Alphabetical order
# ESP32-S2
- 'espressif_saola_1'
# ESP32-S3
#- 'espressif_s3_devkitm'
# S3 compile error with "dangerous relocation: call8: call target out of range: memcpy"
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Pull ESP-IDF docker
run: docker pull espressif/idf:latest
- name: Checkout TinyUSB
uses: actions/checkout@v3
- name: Checkout hathach/linkermap
uses: actions/checkout@v3
with:
repository: hathach/linkermap
path: linkermap
- name: Build
run: docker run --rm -v $PWD:/project -w /project espressif/idf:latest python3 tools/build_esp32sx.py ${{ matrix.board }}
- name: Linker Map
run: |
pip install linkermap/
# find -quit to only print linkermap of 1 board per example
for ex in `ls -d examples/device/*/`
do
find ${ex} -maxdepth 3 -name *.map -print -quit | xargs -I % sh -c 'echo "::group::%"; linkermap -v %; echo "::endgroup::"'
done

@ -0,0 +1,57 @@
name: Build IAR
on:
push:
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_iar.yml'
pull_request:
branches: [ master ]
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_iar.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
build-arm:
runs-on: [self-hosted, Linux, X64, hifiphile]
strategy:
fail-fast: false
matrix:
family:
# Alphabetical order
# Note: bundle multiple families into a matrix since there is only one self-hosted instance can
# run IAR build. Too many matrix can hurt due to setup/teardown overhead.
- 'stm32f0 stm32f1 stm32f4 stm32f7 stm32g4 stm32h7 stm32l4'
steps:
- name: Clean workspace
run: |
echo "Cleaning up previous run"
rm -rf "${{ github.workspace }}"
mkdir -p "${{ github.workspace }}"
- name: Checkout TinyUSB
uses: actions/checkout@v3
- name: Checkout submodules and dependencies
run: |
git submodule update --init lib/FreeRTOS-Kernel lib/lwip lib/sct_neopixel
python3 tools/get_dependencies.py ${{ matrix.family }}
#- name: Checkout pico-sdk for rp2040
# if: matrix.family == 'rp2040'
# run: |
# git clone --depth 1 -b develop https://github.com/raspberrypi/pico-sdk ~/pico-sdk
# echo >> $GITHUB_ENV PICO_SDK_PATH=~/pico-sdk
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }} CC=iccarm

@ -0,0 +1,85 @@
name: Build MSP430
on:
push:
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_msp430.yml'
pull_request:
branches: [ master ]
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_msp430.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
build-msp430:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
family:
# Alphabetical order
- 'msp430'
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Checkout TinyUSB
uses: actions/checkout@v3
- name: Checkout common submodules in lib
run: git submodule update --init lib/FreeRTOS-Kernel lib/lwip
- name: Checkout hathach/linkermap
uses: actions/checkout@v3
with:
repository: hathach/linkermap
path: linkermap
- name: Set Toolchain URL
run: echo >> $GITHUB_ENV TOOLCHAIN_URL=http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2
- name: Cache Toolchain
uses: actions/cache@v3
id: cache-toolchain
with:
path: ~/cache/
key: ${{ runner.os }}-21-03-04-${{ env.TOOLCHAIN_URL }}
- name: Install Toolchain
if: steps.cache-toolchain.outputs.cache-hit != 'true'
run: |
mkdir -p ~/cache/toolchain
wget --progress=dot:mega $TOOLCHAIN_URL -O toolchain.tar.bz2
tar -C ~/cache/toolchain -xaf toolchain.tar.bz2
- name: Set Toolchain Path
run: echo >> $GITHUB_PATH `echo ~/cache/toolchain/*/bin`
- name: Get Dependencies
run: python3 tools/get_dependencies.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }}
- name: Linker Map
run: |
pip install linkermap/
# find -quit to only print linkermap of 1 board per example
for ex in `ls -d examples/device/*/`
do
find ${ex} -name *.map -print -quit | xargs -I % sh -c 'echo "::group::%"; linkermap -v %; echo "::endgroup::"'
done

@ -0,0 +1,85 @@
name: Build Renesas
on:
push:
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_renesas.yml'
pull_request:
branches: [ master ]
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_renesas.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
build-rx:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
family:
# Alphabetical order
- 'rx'
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Checkout TinyUSB
uses: actions/checkout@v3
- name: Checkout common submodules in lib
run: git submodule update --init lib/FreeRTOS-Kernel lib/lwip
- name: Checkout hathach/linkermap
uses: actions/checkout@v3
with:
repository: hathach/linkermap
path: linkermap
- name: Set Toolchain URL
run: echo >> $GITHUB_ENV TOOLCHAIN_URL=http://gcc-renesas.com/downloads/get.php?f=rx/8.3.0.202004-gnurx/gcc-8.3.0.202004-GNURX-ELF.run
- name: Cache Toolchain
uses: actions/cache@v3
id: cache-toolchain
with:
path: ~/cache/
key: ${{ runner.os }}-21-03-30-${{ env.TOOLCHAIN_URL }}
- name: Install Toolchain
if: steps.cache-toolchain.outputs.cache-hit != 'true'
run: |
mkdir -p ~/cache/toolchain/gnurx
wget --progress=dot:mega $TOOLCHAIN_URL -O toolchain.run
chmod +x toolchain.run
./toolchain.run -p ~/cache/toolchain/gnurx -y
- name: Set Toolchain Path
run: echo >> $GITHUB_PATH `echo ~/cache/toolchain/*/bin`
- name: Get Dependencies
run: python3 tools/get_dependencies.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }}
- name: Linker Map
run: |
pip install linkermap/
# find -quit to only print linkermap of 1 board per example
for ex in `ls -d examples/device/*/`
do
find ${ex} -name *.map -print -quit | xargs -I % sh -c 'echo "::group::%"; linkermap -v %; echo "::endgroup::"'
done

@ -0,0 +1,86 @@
name: Build RISC-V
on:
push:
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_riscv.yml'
pull_request:
branches: [ master ]
paths:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- '.github/workflows/build_riscv.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
build-riscv:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
family:
# Alphabetical order
- 'ch32v307'
- 'fomu'
- 'gd32vf103'
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Checkout TinyUSB
uses: actions/checkout@v3
- name: Checkout common submodules in lib
run: git submodule update --init lib/FreeRTOS-Kernel lib/lwip
- name: Checkout hathach/linkermap
uses: actions/checkout@v3
with:
repository: hathach/linkermap
path: linkermap
- name: Set Toolchain URL
run: echo >> $GITHUB_ENV TOOLCHAIN_URL=https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/download/v10.1.0-1.1/xpack-riscv-none-embed-gcc-10.1.0-1.1-linux-x64.tar.gz
- name: Cache Toolchain
uses: actions/cache@v3
id: cache-toolchain
with:
path: ~/cache/
key: ${{ runner.os }}-21-03-04-${{ env.TOOLCHAIN_URL }}
- name: Install Toolchain
if: steps.cache-toolchain.outputs.cache-hit != 'true'
run: |
mkdir -p ~/cache/toolchain
wget --progress=dot:mega $TOOLCHAIN_URL -O toolchain.tar.gz
tar -C ~/cache/toolchain -xaf toolchain.tar.gz
- name: Set Toolchain Path
run: echo >> $GITHUB_PATH `echo ~/cache/toolchain/*/bin`
- name: Get Dependencies
run: python3 tools/get_dependencies.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }}
- name: Linker Map
run: |
pip install linkermap/
# find -quit to only print linkermap of 1 board per example
for ex in `ls -d examples/device/*/`
do
find ${ex} -name *.map -print -quit | xargs -I % sh -c 'echo "::group::%"; linkermap -v %; echo "::endgroup::"'
done

@ -0,0 +1,33 @@
name: CIFuzz
on:
pull_request:
branches:
- master
paths:
- '**.c'
- '**.cc'
- '**.cpp'
- '**.cxx'
- '**.h'
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'tinyusb'
language: c++
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'tinyusb'
language: c++
fuzz-seconds: 600
- name: Upload Crash
uses: actions/upload-artifact@v3
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

@ -0,0 +1,48 @@
name: pre-commit
on:
push:
pull_request:
branches: [ master ]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.0'
- name: Checkout TinyUSB
uses: actions/checkout@v3
- name: Run codespell
uses: codespell-project/actions-codespell@master
- name: Run Unit Tests
run: |
# Install Ceedling
gem install ceedling
cd test/unit-test
ceedling test:all
- name: Build Fuzzer
run: |
export CC=clang
export CXX=clang++
fuzz_harness=$(ls -d test/fuzz/device/*/)
for h in $fuzz_harness
do
make -C $h get-deps
make -C $h all
done

@ -0,0 +1,59 @@
name: Trigger Repos
on:
push:
branches: master
release:
types:
- created
jobs:
trigger-mynewt:
if: github.repository == 'hathach/tinyusb'
runs-on: ubuntu-latest
steps:
- name: Trigger mynewt-tinyusb-example
shell: bash
run: |
curl -X POST -H "Authorization: token ${{ secrets.API_TOKEN_GITHUB }}" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" --data '{"event_type": "rebuild"}' https://api.github.com/repos/hathach/mynewt-tinyusb-example/dispatches
mirror-tinyusb-src:
if: github.repository == 'hathach/tinyusb'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Push to tinyusb_src
run: |
# clone tinyusb_src with PAT
git config --global user.email "thach@tinyusb.org"
git config --global user.name "hathach"
git clone --depth 1 --single-branch --branch main "https://${{ secrets.API_TOKEN_GITHUB }}@github.com/hathach/tinyusb_src.git" tinyusb_src
# Remove all files
rm -rf tinyusb_src/*
# Copy src and other files
cp -r src tinyusb_src/
cp LICENSE tinyusb_src/
cd tinyusb_src
# Commit if there is changes
if [ -n "$(git status --porcelain)" ]; then
git add .
git commit --message "Update from https://github.com/$GITHUB_REPOSITORY/commit/$GITHUB_SHA"
git push
fi
- name: Create tinyusb_src Release
if: ${{ github.event_name == 'release' }}
run: |
# Push tag
cd tinyusb_src
git tag ${{ github.event.release.tag_name }}
git push origin ${{ github.event.release.tag_name }}
# Send POST reqwuest to release https://docs.github.com/en/rest/reference/repos#create-a-release
bb="For release note, please checkout https://github.com/hathach/tinyusb/releases/tag/${{ github.event.release.tag_name }}"
curl -X POST -H "Authorization: token ${{ secrets.API_TOKEN_GITHUB }}" -H "Accept: application/vnd.github.v3+json" --data '{"tag_name": "${{ github.event.release.tag_name }}", "name": "${{ github.event.release.name }}", "body": "$bb", "draft": ${{ github.event.release.draft }}, "prerelease": ${{ github.event.release.prerelease }}}' https://api.github.com/repos/hathach/tinyusb_src/releases

@ -0,0 +1,30 @@
html
latex
*.d
*.o
*.P
*.map
*.axf
*.bin
*.jlink
*.emSession
*.elf
*.ind
.env
.settings/
.idea/
.gdb_history
/examples/*/*/build*
test_old/
tests_obsolete/
_build
/examples/*/*/ses
/examples/*/*/ozone
/examples/obsolete
# coverity intermediate files
cov-int
# cppcheck build directories
*-build-dir
/_bin/
__pycache__

@ -0,0 +1,160 @@
[submodule "hw/mcu/nordic/nrfx"]
path = hw/mcu/nordic/nrfx
url = https://github.com/NordicSemiconductor/nrfx.git
[submodule "tools/uf2"]
path = tools/uf2
url = https://github.com/microsoft/uf2.git
[submodule "hw/mcu/sony/cxd56/spresense-exported-sdk"]
path = hw/mcu/sony/cxd56/spresense-exported-sdk
url = https://github.com/sonydevworld/spresense-exported-sdk.git
[submodule "hw/mcu/ti"]
path = hw/mcu/ti
url = https://github.com/hathach/ti_driver.git
[submodule "hw/mcu/microchip"]
path = hw/mcu/microchip
url = https://github.com/hathach/microchip_driver.git
[submodule "hw/mcu/nuvoton"]
path = hw/mcu/nuvoton
url = https://github.com/majbthrd/nuc_driver.git
[submodule "lib/lwip"]
path = lib/lwip
url = https://github.com/lwip-tcpip/lwip.git
[submodule "hw/mcu/st/cmsis_device_f4"]
path = hw/mcu/st/cmsis_device_f4
url = https://github.com/STMicroelectronics/cmsis_device_f4.git
[submodule "hw/mcu/st/stm32f4xx_hal_driver"]
path = hw/mcu/st/stm32f4xx_hal_driver
url = https://github.com/STMicroelectronics/stm32f4xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_f0"]
path = hw/mcu/st/cmsis_device_f0
url = https://github.com/STMicroelectronics/cmsis_device_f0.git
[submodule "hw/mcu/st/stm32f0xx_hal_driver"]
path = hw/mcu/st/stm32f0xx_hal_driver
url = https://github.com/STMicroelectronics/stm32f0xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_f1"]
path = hw/mcu/st/cmsis_device_f1
url = https://github.com/STMicroelectronics/cmsis_device_f1.git
[submodule "hw/mcu/st/stm32f1xx_hal_driver"]
path = hw/mcu/st/stm32f1xx_hal_driver
url = https://github.com/STMicroelectronics/stm32f1xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_f2"]
path = hw/mcu/st/cmsis_device_f2
url = https://github.com/STMicroelectronics/cmsis_device_f2.git
[submodule "hw/mcu/st/stm32f2xx_hal_driver"]
path = hw/mcu/st/stm32f2xx_hal_driver
url = https://github.com/STMicroelectronics/stm32f2xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_f3"]
path = hw/mcu/st/cmsis_device_f3
url = https://github.com/STMicroelectronics/cmsis_device_f3.git
[submodule "hw/mcu/st/stm32f3xx_hal_driver"]
path = hw/mcu/st/stm32f3xx_hal_driver
url = https://github.com/STMicroelectronics/stm32f3xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_f7"]
path = hw/mcu/st/cmsis_device_f7
url = https://github.com/STMicroelectronics/cmsis_device_f7.git
[submodule "hw/mcu/st/stm32f7xx_hal_driver"]
path = hw/mcu/st/stm32f7xx_hal_driver
url = https://github.com/STMicroelectronics/stm32f7xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_h7"]
path = hw/mcu/st/cmsis_device_h7
url = https://github.com/STMicroelectronics/cmsis_device_h7.git
[submodule "hw/mcu/st/stm32h7xx_hal_driver"]
path = hw/mcu/st/stm32h7xx_hal_driver
url = https://github.com/STMicroelectronics/stm32h7xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_l0"]
path = hw/mcu/st/cmsis_device_l0
url = https://github.com/STMicroelectronics/cmsis_device_l0.git
[submodule "hw/mcu/st/stm32l0xx_hal_driver"]
path = hw/mcu/st/stm32l0xx_hal_driver
url = https://github.com/STMicroelectronics/stm32l0xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_l1"]
path = hw/mcu/st/cmsis_device_l1
url = https://github.com/STMicroelectronics/cmsis_device_l1.git
[submodule "hw/mcu/st/stm32l1xx_hal_driver"]
path = hw/mcu/st/stm32l1xx_hal_driver
url = https://github.com/STMicroelectronics/stm32l1xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_l4"]
path = hw/mcu/st/cmsis_device_l4
url = https://github.com/STMicroelectronics/cmsis_device_l4.git
[submodule "hw/mcu/st/stm32l4xx_hal_driver"]
path = hw/mcu/st/stm32l4xx_hal_driver
url = https://github.com/STMicroelectronics/stm32l4xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_g0"]
path = hw/mcu/st/cmsis_device_g0
url = https://github.com/STMicroelectronics/cmsis_device_g0.git
[submodule "hw/mcu/st/stm32g0xx_hal_driver"]
path = hw/mcu/st/stm32g0xx_hal_driver
url = https://github.com/STMicroelectronics/stm32g0xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_g4"]
path = hw/mcu/st/cmsis_device_g4
url = https://github.com/STMicroelectronics/cmsis_device_g4.git
[submodule "hw/mcu/st/stm32g4xx_hal_driver"]
path = hw/mcu/st/stm32g4xx_hal_driver
url = https://github.com/STMicroelectronics/stm32g4xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_l5"]
path = hw/mcu/st/cmsis_device_l5
url = https://github.com/STMicroelectronics/cmsis_device_l5.git
[submodule "hw/mcu/st/stm32l5xx_hal_driver"]
path = hw/mcu/st/stm32l5xx_hal_driver
url = https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_wb"]
path = hw/mcu/st/cmsis_device_wb
url = https://github.com/STMicroelectronics/cmsis_device_wb.git
[submodule "hw/mcu/st/stm32wbxx_hal_driver"]
path = hw/mcu/st/stm32wbxx_hal_driver
url = https://github.com/STMicroelectronics/stm32wbxx_hal_driver.git
[submodule "lib/sct_neopixel"]
path = lib/sct_neopixel
url = https://github.com/gsteiert/sct_neopixel
[submodule "lib/FreeRTOS-Kernel"]
path = lib/FreeRTOS-Kernel
url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git
[submodule "lib/CMSIS_5"]
path = lib/CMSIS_5
url = https://github.com/ARM-software/CMSIS_5.git
[submodule "hw/mcu/silabs/cmsis-dfp-efm32gg12b"]
path = hw/mcu/silabs/cmsis-dfp-efm32gg12b
url = https://github.com/cmsis-packs/cmsis-dfp-efm32gg12b
[submodule "hw/mcu/renesas/rx"]
path = hw/mcu/renesas/rx
url = https://github.com/kkitayam/rx_device.git
[submodule "hw/mcu/nxp/lpcopen"]
path = hw/mcu/nxp/lpcopen
url = https://github.com/hathach/nxp_lpcopen.git
[submodule "hw/mcu/nxp/mcux-sdk"]
path = hw/mcu/nxp/mcux-sdk
url = https://github.com/NXPmicro/mcux-sdk.git
[submodule "hw/mcu/nxp/nxp_sdk"]
path = hw/mcu/nxp/nxp_sdk
url = https://github.com/hathach/nxp_sdk.git
[submodule "hw/mcu/gd/nuclei-sdk"]
path = hw/mcu/gd/nuclei-sdk
url = https://github.com/Nuclei-Software/nuclei-sdk.git
[submodule "hw/mcu/bridgetek/ft9xx/ft90x-sdk"]
path = hw/mcu/bridgetek/ft9xx/ft90x-sdk
url = https://github.com/BRTSG-FOSS/ft90x-sdk
[submodule "hw/mcu/mindmotion/mm32sdk"]
path = hw/mcu/mindmotion/mm32sdk
url = https://github.com/hathach/mm32sdk.git
[submodule "hw/mcu/broadcom"]
path = hw/mcu/broadcom
url = https://github.com/adafruit/broadcom-peripherals.git
branch = main-build
[submodule "hw/mcu/infineon/mtb-xmclib-cat3"]
path = hw/mcu/infineon/mtb-xmclib-cat3
url = https://github.com/Infineon/mtb-xmclib-cat3.git
[submodule "hw/mcu/allwinner"]
path = hw/mcu/allwinner
url = https://github.com/hathach/allwinner_driver.git
[submodule "hw/mcu/wch/ch32v307"]
path = hw/mcu/wch/ch32v307
url = https://github.com/openwch/ch32v307.git
[submodule "hw/mcu/raspberry_pi/Pico-PIO-USB"]
path = hw/mcu/raspberry_pi/Pico-PIO-USB
url = https://github.com/sekigon-gonnoc/Pico-PIO-USB.git
[submodule "hw/mcu/st/cmsis_device_u5"]
path = hw/mcu/st/cmsis_device_u5
url = https://github.com/STMicroelectronics/cmsis_device_u5
[submodule "hw/mcu/st/stm32u5xx_hal_driver"]
path = hw/mcu/st/stm32u5xx_hal_driver
url = https://github.com/STMicroelectronics/stm32u5xx_hal_driver

@ -0,0 +1,18 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
version: 2
sphinx:
configuration: docs/conf.py
python:
version: 3.8
install:
- requirements: docs/requirements.txt
submodules:
include: []
recursive: false

@ -0,0 +1,88 @@
***************
Code of Conduct
***************
Our Pledge
----------
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our
project and our community a harassment-free experience for everyone,
regardless of age, body size, disability, ethnicity, sex
characteristics, gender identity and expression, level of experience,
education, socio-economic status, nationality, personal appearance,
race, religion, or sexual identity and orientation.
Our Standards
-------------
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual
attention or advances
- Trolling, insulting/derogatory comments, and personal or political
attacks
- Public or private harassment
- Publishing others' private information, such as a physical or
electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
Our Responsibilities
--------------------
Project maintainers are responsible for clarifying the standards of
acceptable behavior and are expected to take appropriate and fair
corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit,
or reject comments, commits, code, wiki edits, issues, and other
contributions that are not aligned to this Code of Conduct, or to ban
temporarily or permanently any contributor for other behaviors that they
deem inappropriate, threatening, offensive, or harmful.
Scope
-----
This Code of Conduct applies both within project spaces and in public
spaces when an individual is representing the project or its community.
Examples of representing a project or community include using an
official project e-mail address, posting via an official social media
account, or acting as an appointed representative at an online or
offline event. Representation of a project may be further defined and
clarified by project maintainers.
Enforcement
-----------
Instances of abusive, harassing, or otherwise unacceptable behavior may
be reported by contacting the project team at thach@tinyusb.org. All
complaints will be reviewed and investigated and will result in a
response that is deemed necessary and appropriate to the circumstances.
The project team is obligated to maintain confidentiality with regard to
the reporter of an incident. Further details of specific enforcement
policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in
good faith may face temporary or permanent repercussions as determined
by other members of the project's leadership.
Attribution
-----------
This Code of Conduct is adapted from the `Contributor
Covenant <https://www.contributor-covenant.org>`__, version 1.4,
available at
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

@ -0,0 +1,205 @@
************
Contributors
************
Special thanks to all the people who spent their precious time and effort to help this project so far.
list contributors and their awesome work for the stack:
Notable contributors
====================
(sorted alphabetically)
`Adafruit Team <https://github.com/adafruit>`__
-----------------------------------------------
- Main supporter and sponsor for hardware boards and kits
- Discussion and suggestion for feature and improvement
- Design the project logo
`Gordon McNab <https://github.com/ftdigdm>`__
---------------------------------------------
- Add new DCD port for Bridgetek FT90x and FT93x
`Ha Thach <https://github.com/hathach>`__
-----------------------------------------
- *Author and maintainer*
- Most features development
`Hristo Gochkov <https://github.com/me-no-dev>`__
-------------------------------------------------
- Improve ESP32s2 DCD
`Jacob Berg Potter <https://github.com/j4cbo>`__
------------------------------------------------
- Add new class driver for network CDC-NCM
`Jan Dümpelmann <https://github.com/duempel>`__
-----------------------------------------------
- Improve transfer performance for Synopsys DCD for STM32 MCUs
`Jeff Epler <https://github.com/jepler>`__
------------------------------------------
- Improve MIDI class driver
`Jerzy Kasenberg <https://github.com/kasjer>`__
-----------------------------------------------
- Add new DCD port for Dialog DA1469x
- Add new DCD port for PIC32MZ
- Add new class driver for Bluetooth HCI
- Add ISO transfer for STM32 Synopsys, Nordic nRF, Dialog DA1469x
- Improve Audio driver and add uac2\_headset example
- Improve STM32 Synopsys DCD with various PRs
`J McCarthy <https://github.com/xmos-jmccarthy>`__
--------------------------------------------------
- Add new DFU 1.1 class driver
- Add new example for dfu
`Kamil Tomaszewski <https://github.com/kamtom480>`__
----------------------------------------------------
- Add new DCD port for Sony CXD56 (spresnese board)
`Kay Sievers <https://github.com/kaysievers>`__
-----------------------------------------------
- Improve MIDI driver with packet API
`Koji KITAYAMA <https://github.com/kkitayam>`__
-----------------------------------------------
- Add new DCD and HCD port for NXP Kinetis KL25
- Add new DCD and HCD port for Renesas RX family (RX600, RX700 ..) with GR-CITRUS, RX65n target board
- Add new DCD and HCD port for Mentor musb with MSP432E4
- Add new class driver for USB Video Class (UVC 1.5)
`Nathan Conrad <https://github.com/pigrew>`__
---------------------------------------------
- Add new DCD port for STM32 fsdev Fullspeed device for STM32 L0,
F0, F1, F3 etc ...
- Add new class driver for USB Test and Measurement Class (USBTMC)
- Various improvement e.g Zero-length packet, Lint setup
- Board support for STM32F070RB Nucleo, STM32F303 Discovery
`Peter Lawrence <https://github.com/majbthrd>`__
------------------------------------------------
- Add new DCD port for Nuvoton NUC 120, 121, 125, 126, 505
- Add new class driver for network RNDIS, CDC-ECM
- Enhance CDC-NCM network driver to compatible with RNDIS/ECM
- Add *net\_lwip\_webserver* example for demonstration of usbnet with lwip
- Board support for NuTiny NUC120, NUC121s, NUC125s, NUC126V, NUC505
- Improve multiple cdc interfaces API & add cdc\_dual\_ports example
`Rafael Silva <https://github.com/perigoso>`__
----------------------------------------------
- Port DCD Synopsys to support Silabs EFM32GG12 with SLTB009A board
- Rewrite documentation in rst and setup for readthedocs
`Raspberry Pi Team <https://github.com/raspberrypi>`__
------------------------------------------------------
- Add new DCD port for Raspberry Pi RP2040
- Add new HCD port for Raspberry Pi RP2040
`Reinhard Panhuber <https://github.com/PanRe>`__
------------------------------------------------
- Add new class driver for USB Audio Class 2.0 (UAC2)
- Rework tu\_fifo with unmasked pointer, add DMA support, and constant address support
- Add new DCD/USBD edpt\_xfer\_fifo() API for optimizing endpoint transfer
- Add and greatly improve Isochronous transfer
- Add new audio examples: audio\_test and audio\_4\_channel\_mic
`Scott Shawcroft <https://github.com/tannewt>`__
------------------------------------------------
- Add new DCD port for SAMD21 and SAMD51
- Add new class driver for Musical Instrument Digital Interface (MIDI)
- Improve USBD control transfer, MSC, CDC class driver
- Board support for Metro M0 & M4 express
- Write the excellent porting.md documentation
- Add initial Makefile
`Sean Cross <https://github.com/xobs>`__
----------------------------------------
- Add new DCD port for ValentyUSB eptri (fomu board)
`Sylvain "tnt" Munaut <https://github.com/smunaut>`__
-----------------------------------------------------
- Add new class driver for DFU Runtime
`Tian Yunhao <https://github.com/t123yh>`__
-------------------------------------------
- Add new DCD port for Allwinner F1C100S/F1C200S
- Add support for osal_rtx4
`Timon Skerutsch <https://github.com/PTS93>`__
----------------------------------------------
- Add hid\_test.js script and extensive test for bi-directional raw HID
`Tod E. Kurt <https://github.com/todbot>`__
-------------------------------------------
- Add hid\_test.js script and extensive test for bi-directional raw HID
`Uwe Bonnes <https://github.com/UweBonnes>`__
---------------------------------------------
- Improve STM32 Synopsys highspeed DCD
`William D. Jones <https://github.com/cr1901>`__
------------------------------------------------
- Add new DCD port for Synopsys DesignWare for STM32 L4, F2, F4,
F7, H7 etc ...
- Add new DCD port for TI MSP430
- Board support for STM32F407 Discovery, STM32H743 Nucleo, pyboard v1.1, msp\_exp430f5529lp etc ...
`Zixun Li <https://github.com/HiFiPhile>`__
-------------------------------------------
- Add new DCD port for Microchip SAMx7x
- Add IAR compiler support
- Improve UAC2, CDC, DFU class driver
`Full contributors list <https://github.com/hathach/tinyusb/contributors>`__
============================================================================

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2018, hathach (tinyusb.org)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -0,0 +1,149 @@
.. figure:: docs/assets/logo.svg
:alt: TinyUSB
|Build Status| |Documentation Status| |Fuzzing Status| |License|
TinyUSB is an open-source cross-platform USB Host/Device stack for
embedded system, designed to be memory-safe with no dynamic allocation
and thread-safe with all interrupt events are deferred then handled in
the non-ISR task function.
Please take a look at the online `documentation <https://docs.tinyusb.org/>`__.
.. figure:: docs/assets/stack.svg
:width: 500px
:alt: stackup
::
.
├── docs # Documentation
├── examples # Sample with Makefile build support
├── hw
│   ├── bsp # Supported boards source files
│   └── mcu # Low level mcu core & peripheral drivers
├── lib # Sources from 3rd party such as freeRTOS, fatfs ...
├── src # All sources files for TinyUSB stack itself.
├── test # Unit tests for the stack
└── tools # Files used internally
Supported MCUs
==============
The stack supports the following MCUs:
- **Allwinner:** F1C100s/F1C200s
- **Broadcom:** BCM2837, BCM2711
- **Dialog:** DA1469x
- **Espressif:** ESP32-S2, ESP32-S3
- **GigaDevice:** GD32VF103
- **Infineon:** XMC4500
- **MicroChip:** SAMD11, SAMD21, SAMD51, SAME5x, SAMG55, SAML21, SAML22, SAME7x
- **NordicSemi:** nRF52833, nRF52840, nRF5340
- **Nuvoton:** NUC120, NUC121/NUC125, NUC126, NUC505
- **NXP:**
- iMX RT Series: RT10xx, RT11xx
- Kinetis: KL25, K32L2
- LPC Series: 11u, 13, 15, 17, 18, 40, 43, 51u, 54, 55
- **Raspberry Pi:** RP2040
- **Renesas:** RX63N, RX65N, RX72N
- **Silabs:** EFM32GG
- **Sony:** CXD56
- **ST:** STM32 series: F0, F1, F2, F3, F4, F7, H7, G4, L0, L1, L4, L4+, WB
- **TI:** MSP430, MSP432E4, TM4C123
- **ValentyUSB:** eptri
- **WCH:** CH32V307
Here is the list of `Supported Devices`_ that can be used with provided examples.
Device Stack
============
Supports multiple device configurations by dynamically changing USB descriptors, low power functions such like suspend, resume, and remote wakeup. The following device classes are supported:
- Audio Class 2.0 (UAC2)
- Bluetooth Host Controller Interface (BTH HCI)
- Communication Device Class (CDC)
- Device Firmware Update (DFU): DFU mode (WIP) and Runtime
- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ...
- Mass Storage Class (MSC): with multiple LUNs
- Musical Instrument Digital Interface (MIDI)
- Network with RNDIS, Ethernet Control Model (ECM), Network Control Model (NCM)
- Test and Measurement Class (USBTMC)
- Video class 1.5 (UVC): work in progress
- Vendor-specific class support with generic In & Out endpoints. Can be used with MS OS 2.0 compatible descriptor to load winUSB driver without INF file.
- `WebUSB <https://github.com/WICG/webusb>`__ with vendor-specific class
If you have a special requirement, `usbd_app_driver_get_cb()` can be used to write your own class driver without modifying the stack. Here is how the RPi team added their reset interface `raspberrypi/pico-sdk#197 <https://github.com/raspberrypi/pico-sdk/pull/197>`_
Host Stack
==========
- Human Interface Device (HID): Keyboard, Mouse, Generic
- Mass Storage Class (MSC)
- Hub with multiple-level support
OS Abstraction layer
====================
TinyUSB is completely thread-safe by pushing all Interrupt Service Request (ISR) events into a central queue, then processing them later in the non-ISR context task function. It also uses semaphore/mutex to access shared resources such as Communication Device Class (CDC) FIFO. Therefore the stack needs to use some of the OS's basic APIs. Following OSes are already supported out of the box.
- **No OS**
- **FreeRTOS**
- `RT-Thread <https://github.com/RT-Thread/rt-thread>`_: `repo <https://github.com/RT-Thread-packages/tinyusb>`_
- **Mynewt** Due to the newt package build system, Mynewt examples are better to be on its `own repo <https://github.com/hathach/mynewt-tinyusb-example>`_
Docs
====
- Info
- `Uses`_
- `Changelog`_
- `Contributors`_
- `Reference`_
- `Supported Devices`_
- `Getting Started`_
- `Concurrency`_
- `Contributing`_
- `Code of Conduct`_
- `Structure`_
- `Porting`_
License
=======
All TinyUSB sources in the ``src`` folder are licensed under MIT
license, the `Full license is here <LICENSE>`__. However, each file can be
individually licensed especially those in ``lib`` and ``hw/mcu`` folder.
Please make sure you understand all the license term for files you use
in your project.
.. |Build Status| image:: https://github.com/hathach/tinyusb/workflows/Build/badge.svg
:target: https://github.com/hathach/tinyusb/actions
.. |Documentation Status| image:: https://readthedocs.org/projects/tinyusb/badge/?version=latest
:target: https://docs.tinyusb.org/en/latest/?badge=latest
.. |Fuzzing Status| image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/tinyusb.svg
:target: https://oss-fuzz-build-logs.storage.googleapis.com/index.html#tinyusb
.. |License| image:: https://img.shields.io/badge/license-MIT-brightgreen.svg
:target: https://opensource.org/licenses/MIT
.. _Uses: docs/info/uses.rst
.. _Changelog: docs/info/changelog.rst
.. _Contributors: CONTRIBUTORS.rst
.. _Reference: docs/reference/index.rst
.. _Supported Devices: docs/reference/supported.rst
.. _Getting Started: docs/reference/getting_started.rst
.. _Concurrency: docs/reference/concurrency.rst
.. _Contributing: docs/contributing/index.rst
.. _Code of Conduct: CODE_OF_CONDUCT.rst
.. _Structure: docs/contributing/structure.rst
.. _Porting: docs/contributing/porting.rst

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="280" height="140" version="1.1" viewBox="0 0 74.083 37.042" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(-60.931 -79.245)">
<g transform="matrix(1.0442 0 0 1.1531 -27.105 33.588)" fill="#fff">
<path d="m86.972 39.594c-1.4683 3.2e-5 -2.6588 1.181-2.66 2.6384v26.844c3.3e-5 1.4583 1.1909 2.6404 2.66 2.6404h65.63c1.469-3.2e-5 2.66-1.1822 2.66-2.6404v-26.844c-1e-3 -1.4575-1.1917-2.6384-2.66-2.6384z" color="#000000" fill="#fff" style="-inkscape-stroke:none"/>
</g>
<g transform="matrix(.35278 0 0 -.35278 -160.36 421.93)" fill="#231f20">
<path transform="translate(672.09 955.48)" d="m0 0h-21.484v-12.601h-5.349v-6.436h5.349v-25.383c0-11.331 7.252-13.87 17.223-13.87 4.352 0 8.613 0.272 12.873 0.907v6.073c-0.816-0.09-2.266-0.362-3.535-0.362-3.807 0-5.077 0.816-5.077 4.896v27.739h8.612v6.436h-8.612z"/>
<path transform="translate(693.61 925.33)" d="m0 0h-0.049c-1.518 0-2.165-0.896-2.165-2.24v-0.05h4.504v0.05c0 1.344-0.771 2.24-2.29 2.24"/>
<path transform="translate(700.92 925.5)" d="m0 0h-0.124c-1.443 0-2.265-0.995-2.265-2.389v-0.074h4.654v0.074c0 1.394-0.822 2.389-2.265 2.389"/>
<path transform="translate(750.09 943.78)" d="m0 0c-6.165 0-11.876-2.267-14.505-5.893v4.986h-20.578v-45.326h21.484v36.533c1.27 0.272 2.449 0.453 3.717 0.453 4.715 0 5.44-2.538 5.44-6.436v-30.55h21.484v30.278c0 11.694-7.523 15.955-17.042 15.955"/>
<path transform="translate(811.83 942.88)" d="m0 0-10.516-23.57-11.784 23.57h-23.388l24.204-48.046-6.799-15.411h8.249l28.193 63.457z"/>
<path transform="translate(706 920)" d="m0 0h-17.421v2.637c0 2.938 1.194 5.675 4.43 5.675h0.124c2.24 0 3.335-1.269 3.932-2.514 0.647 1.469 1.667 2.738 3.883 2.738h0.224c3.086 0 4.828-2.39 4.828-5.774zm-0.598-9.412h-3.16c0.622 1.07 0.971 1.917 0.971 2.737 0 0.871-0.424 1.618-1.493 1.618h-0.05c-0.797 0-1.394-0.249-3.037-1.692-2.339-2.065-3.459-2.912-5.574-2.912h-0.05c-2.787 0-4.555 1.816-4.555 4.231 0 1.219 0.175 1.941 0.548 2.687h3.161c-0.548-0.945-0.797-1.518-0.797-2.314 0-0.845 0.548-1.568 1.493-1.568h0.05c0.821 0 1.12 0.25 2.788 1.692 2.762 2.39 3.832 2.912 5.824 2.912h0.048c2.739 0 4.555-1.917 4.555-4.305 0-1.195-0.298-2.215-0.722-3.086m-4.479-10.93h-12.344v3.011h12.643c1.567 0 2.189 0.548 2.189 1.319 0 0.772-0.622 1.32-2.189 1.32h-12.643v3.01h12.344c3.658 0 5.301-1.841 5.301-4.33 0-2.488-1.643-4.33-5.301-4.33m-9.641 53.817h12.114v-10.601h-12.114zm14.114 2h-16.114v-12.601h-2.685v-45.326h21.484v45.326h-2.685z"/>
<path d="m692.79 947.02h2.827v2.319h-2.827z"/>
<path d="m699.06 947.02h2.826v2.319h-2.826z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 84 KiB

@ -0,0 +1,41 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# -- Project information -----------------------------------------------------
project = 'TinyUSB'
copyright = '2021, Ha Thach'
author = 'Ha Thach'
# -- General configuration ---------------------------------------------------
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx_autodoc_typehints',
]
templates_path = ['_templates']
exclude_patterns = ['_build']
# -- Options for HTML output -------------------------------------------------
html_theme = 'furo'
html_title = 'TinyUSB'
html_logo = 'assets/logo.svg'
html_favicon = 'assets/logo.svg'
html_theme_options = {
'sidebar_hide_name': True,
}
todo_include_todos = True

@ -0,0 +1,23 @@
************
Contributing
************
Contributing can be highly rewarding, but it can also be frustrating at times.
It takes time to review patches, and as this is an open source project, that
sometimes can take a while. The reviewing process depends on the availability
of the maintainers, who may not be always available. Please try to be
understanding through the process.
There a few guidelines you need to keep in mind when contributing. Please have
a look at them as that will make the contribution process easier for all
parties.
Index
=====
.. toctree::
:maxdepth: 2
code_of_conduct
structure
porting

@ -0,0 +1,241 @@
*******
Porting
*******
TinyUSB is designed to be a universal USB protocol stack for microcontrollers. It
handles most of the high level USB protocol and relies on the microcontroller's USB peripheral for
data transactions on different endpoints. Porting is the process of adding low-level support for
the rest of the common stack. Once the low-level is implemented, it is very easy to add USB support
for the microcontroller to other projects, especially those already using TinyUSB such as CircuitPython.
Below are instructions on how to get the cdc_msc device example running on a new microcontroller. Doing so includes adding the common code necessary for other uses while minimizing other extra code. Whenever you see a phrase or word in <> it should be replaced.
Register defs
-------------
The first step to adding support is including the register definitions and startup code for the
microcontroller in TinyUSB. We write the TinyUSB implementation against these structs instead of higher level functions to keep the code small and to prevent function name collisions in linking of larger projects. For ARM microcontrollers this is the CMSIS definitions. They should be
placed in the ``hw/mcu/<vendor>/<chip_family>`` directory.
Once this is done, create a directory in ``hw/bsp/<your board name>`` for the specific board you are using to test the code. (Duplicating an existing board's directory is the best way to get started.) The board should be a readily available development board so that others can also test.
Build
-----
Now that those directories are in place, we can start our iteration process to get the example building successfully. To build, run from the root of TinyUSB:
``make -C examples/device/cdc_msc BOARD=<board>``
Unless, you've read ahead, this will fail miserably. Now, lets get it to fail less by updating the files in the board directory. The code in the board's directory is responsible for setting up the microcontroller's clocks and pins so that USB works. TinyUSB itself only operates on the USB peripheral. The board directory also includes information what files are needed to build the example.
One of the first things to change is the ``-DCFG_TUSB_MCU`` cflag in the ``board.mk`` file. This is used to tell TinyUSB what platform is being built. So, add an entry to ``src/tusb_option.h`` and update the CFLAG to match.
Update ``board.mk``\ 's VENDOR and CHIP_FAMILY values when creating the directory for the struct files. Duplicate one of the other sources from ``src/portable`` into ``src/portable/<vendor>/<chip_family>`` and delete all of the implementation internals. We'll cover what everything there does later. For now, get it compiling.
Implementation
--------------
At this point you should get an error due to an implementation issue and hopefully the build is setup for the new MCU. You will still need to modify the ``board.mk`` to include specific CFLAGS, the linker script, linker flags, source files, include directories. All file paths are relative to the top of the TinyUSB repo.
Board Support (BSP)
^^^^^^^^^^^^^^^^^^^
The board support code is only used for self-contained examples and testing. It is not used when TinyUSB is part of a larger project. Its responsible for getting the MCU started and the USB peripheral clocked. It also optionally provides LED definitions that are used to blink an LED to show that the code is running.
It is located in ``hw/bsp/<board name>/board_<board name>.c``.
board_init
~~~~~~~~~~
``board_init`` is responsible for starting the MCU, setting up the USB clock and USB pins. It is also responsible for initializing LED pins.
One useful clock debugging technique is to set up a PWM output at a known value such as 500hz based on the USB clock so that you can verify it is correct with a logic probe or oscilloscope.
Setup your USB in a crystal-less mode when available. That makes the code easier to port across boards.
board_led_write
~~~~~~~~~~~~~~~
Feel free to skip this until you want to verify your demo code is running. To implement, set the pin corresponding to the led to output a value that lights the LED when ``state`` is true.
OS Abstraction Layer (OSAL)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
The OS Abstraction Layer is responsible for providing basic data structures for TinyUSB that may allow for concurrency when used with an RTOS. Without an RTOS it simply handles concurrency issues between the main code and interrupts.
The code is almost entirely agnostic of MCU and lives in ``src/osal``.
Device API
^^^^^^^^^^
After the USB device is setup, the USB device code works by processing events on the main thread (by calling ``tud_task``\ ). These events are queued by the USB interrupt handler. So, there are three parts to the device low-level API: device setup, endpoint setup and interrupt processing.
All of the code for the low-level device API is in ``src/portable/<vendor>/<chip family>/dcd_<chip family>.c``.
Device Setup
~~~~~~~~~~~~
dcd_init
""""""""
Initializes the USB peripheral for device mode and enables it.
This function should enable internal D+/D- pull-up for enumeration.
dcd_int_enable / dcd_int_disable
""""""""""""""""""""""""""""""""
Enables or disables the USB device interrupt(s). May be used to prevent concurrency issues when mutating data structures shared between main code and the interrupt handler.
dcd_int_handler
"""""""""""""""
Processes all the hardware generated events e.g Bus reset, new data packet from host etc ... It will be called by application in the MCU USB interrupt handler.
dcd_set_address
"""""""""""""""
Called when the device is given a new bus address.
If your peripheral automatically changes address during enumeration (like the nrf52) you may leave this empty and also no queue an event for the corresponding SETUP packet.
dcd_remote_wakeup
"""""""""""""""""
Called to remote wake up host when suspended (e.g hid keyboard)
dcd_connect / dcd_disconnect
""""""""""""""""""""""""""""
Connect or disconnect the data-line pull-up resistor. Define only if MCU has an internal pull-up. (BSP may define for MCU without internal pull-up.)
Special events
~~~~~~~~~~~~~~
You must let TinyUSB know when certain events occur so that it can continue its work. There are a few methods you can call to queue events for TinyUSB to process.
dcd_event_bus_signal
""""""""""""""""""""
There are a number of events that your peripheral may communicate about the state of the bus. Here is an overview of what they are. Events in **BOLD** must be provided for TinyUSB to work.
* **DCD_EVENT_RESET** - Triggered when the host resets the bus causing the peripheral to reset. Do any other internal reset you need from the interrupt handler such as resetting the control endpoint.
* DCD_EVENT_SOF - Signals the start of a new USB frame.
Calls to this look like:
.. code-block::
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
The first ``0`` is the USB peripheral number. Statically saying 0 is common for single USB device MCUs.
The ``true`` indicates the call is from an interrupt handler and will always be the case when porting in this way.
dcd_setup_received
""""""""""""""""""
SETUP packets are a special type of transaction that can occur at any time on the control endpoint, numbered ``0``. Since they are unique, most peripherals have special handling for them. Their data is always 8 bytes in length as well.
Calls to this look like:
.. code-block::
dcd_event_setup_received(0, setup, true);
As before with ``dcd_event_bus_signal`` the first argument is the USB peripheral number and the third is true to signal its being called from an interrupt handler. The middle argument is byte array of length 8 with the contents of the SETUP packet. It can be stack allocated because it is copied into the queue.
Endpoints
~~~~~~~~~
Endpoints are the core of the USB data transfer process. They come in a few forms such as control, isochronous, bulk, and interrupt. We won't cover the details here except with some caveats in open below. In general, data is transferred by setting up a buffer of a given length to be transferred on a given endpoint address and then waiting for an interrupt to signal that the transfer is finished. Further details below.
Endpoints within USB have an address which encodes both the number and direction of an endpoint. TinyUSB provides ``tu_edpt_number`` and ``tu_edpt_dir`` to unpack this data from the address. Here is a snippet that does it.
.. code-block::
uint8_t epnum = tu_edpt_number(ep_addr);
uint8_t dir = tu_edpt_dir(ep_addr);
dcd_edpt_open
"""""""""""""
Opening an endpoint is done for all non-control endpoints once the host picks a configuration that the device should use. At this point, the endpoint should be enabled in the peripheral and configured to match the endpoint descriptor. Pay special attention to the direction of the endpoint you can get from the helper methods above. It will likely change what registers you are setting.
Also make sure to enable endpoint specific interrupts.
dcd_edpt_close
""""""""""""""
Close an endpoint. his function is used for implementing alternate settings.
After calling this, the device should not respond to any packets directed towards this endpoint. When called, this function must abort any transfers in progress through this endpoint, before returning.
Implementation is optional. Must be called from the USB task. Interrupts could be disabled or enabled during the call.
dcd_edpt_xfer
"""""""""""""
``dcd_edpt_xfer`` is responsible for configuring the peripheral to send or receive data from the host. "xfer" is short for "transfer". **This is one of the core methods you must implement for TinyUSB to work (one other is the interrupt handler).** Data from the host is the OUT direction and data to the host is IN. It is used for all endpoints including the control endpoint 0. Make sure to handle the zero-length packet STATUS packet on endpoint 0 correctly. It may be a special transaction to the peripheral.
Besides that, all other transactions are relatively straight-forward. The endpoint address provides the endpoint
number and direction which usually determines where to write the buffer info. The buffer and its length are usually
written to a specific location in memory and the peripheral is told the data is valid. (Maybe by writing a 1 to a
register or setting a counter register to 0 for OUT or length for IN.)
The transmit buffer alignment is determined by ``CFG_TUSB_MEM_ALIGN``.
One potential pitfall is that the buffer may be longer than the maximum endpoint size of one USB
packet. Some peripherals can handle transmitting multiple USB packets for a provided buffer (like the SAMD21).
Others (like the nRF52) may need each USB packet queued individually. To make this work you'll need to track
some state for yourself and queue up an intermediate USB packet from the interrupt handler.
Once the transaction is going, the interrupt handler will notify TinyUSB of transfer completion.
During transmission, the IN data buffer is guaranteed to remain unchanged in memory until the ``dcd_xfer_complete`` function is called.
The dcd_edpt_xfer function must never add zero-length-packets (ZLP) on its own to a transfer. If a ZLP is required,
then it must be explicitly sent by the stack calling dcd_edpt_xfer(), by calling dcd_edpt_xfer() a second time with len=0.
For control transfers, this is automatically done in ``usbd_control.c``.
At the moment, only a single buffer can be transmitted at once. There is no provision for double-buffering. new dcd_edpt_xfer() will not
be called again on the same endpoint address until the driver calls dcd_xfer_complete() (except in cases of USB resets).
dcd_xfer_complete
"""""""""""""""""
Once a transfer completes you must call dcd_xfer_complete from the USB interrupt handler to let TinyUSB know that a transaction has completed. Here is a sample call:
.. code-block::
dcd_event_xfer_complete(0, ep_addr, xfer->actual_len, XFER_RESULT_SUCCESS, true);
The arguments are:
* the USB peripheral number
* the endpoint address
* the actual length of the transfer. (OUT transfers may be smaller than the buffer given in ``dcd_edpt_xfer``\ )
* the result of the transfer. Failure isn't handled yet.
* ``true`` to note the call is from an interrupt handler.
dcd_edpt_stall / dcd_edpt_clear_stall
"""""""""""""""""""""""""""""""""""""
Stalling is one way an endpoint can indicate failure such as when an unsupported command is transmitted. The pair of ``dcd_edpt_stall``\ , ``dcd_edpt_clear_stall`` help manage the stall state of all endpoints.
Woohoo!
-------
At this point you should have everything working! ;-) Of course, you may not write perfect code. Here are some tips and tricks for debugging.
Use `WireShark <https://www.wireshark.org/>`_ or `a Beagle <https://www.totalphase.com/protocols/usb/>`_ to sniff the USB traffic. When things aren't working its likely very early in the USB enumeration process. Figuring out where can help clue in where the issue is. For example:
* If the host sends a SETUP packet and its not ACKed then your USB peripheral probably isn't started correctly.
* If the peripheral is started correctly but it still didn't work, then verify your usb clock is correct. (You did output a PWM based on it right? ;-) )
* If the SETUP packet is ACKed but nothing is sent back then you interrupt handler isn't queueing the setup packet correctly. (Also, if you are using your own code instead of an example ``tud_task`` may not be called.) If that's OK, the ``dcd_xfer_complete`` may not be setting up the next transaction correctly.

@ -0,0 +1,59 @@
*********
Structure
*********
Tree
====
::
.
├── docs
├── examples
├── hw
│   ├── bsp
│   └── mcu
├── lib
├── src
├── test
└── tools
docs
----
Documentation
examples
--------
Sample with Makefile build support
hw/bsp
------
Supported boards source files
hw/mcu
------
Low level mcu core & peripheral drivers
lib
---
Sources from 3rd party such as freeRTOS, fatfs ...
src
---
All sources files for TinyUSB stack itself.
test
----
Unit tests for the stack
tools
-----
Files used internally

@ -0,0 +1,25 @@
:hide-toc:
*********
TinyUSB
*********
TinyUSB is an open-source cross-platform USB Host/Device stack for embedded systems,
designed to be memory-safe with no dynamic allocation and thread-safe with all interrupt events being deferred and then handled in the non-ISR task function.
.. toctree::
:caption: Index
:hidden:
Info <info/index>
Reference <reference/index>
Contributing <contributing/index>
.. toctree::
:caption: External Links
:hidden:
Source Code <https://github.com/hathach/tinyusb>
Issue Tracker <https://github.com/hathach/tinyusb/issues>
Discussions <https://github.com/hathach/tinyusb/discussions>

@ -0,0 +1,798 @@
*********
Changelog
*********
0.15.0
======
- Add codespell to detect typo
- Add support for fuzzing and bagde for oss-fuzz
- [osal]
- Allow the use of non-static allocation for FreeRTOS
- Fix FreeRTOS wrong task switch in some cases
- Fix tu_fifo memory overflown when repeatedly write to overwritable fifo (accumulated more than 2 depths)
- Better support for IAR (ARM) with ci build check for stm32 mcus.
- Fix Windows build for some mingw gnu make situations
Controller Driver (DCD & HCD)
-----------------------------
- Add new port support (WIP) for WCH CH32V307 USB Highspeed
- Add new port support (WIP) for PIC32MM/MX & PIC24
- [nRF]
- Fix endpoint internal state when closed
- Fix reception of large ISO packets
- [rp2040]
- [dcd] Implement workaround for Errata 15. This enable SOF when bulk-in endpoint is in use and reduce its bandwidth to only 80%
- [hcd] Fix shared irq slots filling up when hcd_init() is called multiple times
- [hcd] Support host bulk endpoint using hw "interrupt" endpoint. Note speed limit is 64KB/s
- [samd][dcd] Add support for ISO endpoint
- [dwc2][dcd] Add support for stm32u5xx
- [esp32sx] Fix Isochronous transfers only transmitted on even frame
- [lpc_ip3511][dcd] Add isochronous support and fix endpoint accidental write
- [ft90x] Improve and enhance support for FT9xx MCU, tested with more examples
Device Stack
------------
- [Video]
- Add support for MJPEG
- Fix probe on macOS
- [MIDI]
- Support port name strings
- fix MS Header wTotalLength computation
- [HID]
- Add FIDO descriptor template
- change length in tud_hid_report_complete_cb() from uint8 to uint16
- [CDC]
- Fix autoflush for FIFO < MPS
- Fix tx fifo memory overflown when DTR is not set and tud_cdc_write() is called repeatedly with large enough data
- [USBTMC] Fix packet size with highspeed
Host Stack
----------
- Retry a few times with transfers in enumeration since device can be unstable when starting up
- [MSC] Rework host masstorage API. Add new **host/msc_file_explorer** example
- [CDC]
- Add support for host cdc
- Fix host cdc with device without IAD e.g Arduino Due
0.14.0
======
- Improve compiler support for CCRX and IAR
- Add timeout to osal_queue_receive()
- Add tud_task_ext(timeout, in_isr) as generic version of tud_task(). Same as tuh_task_ext(), tuh_task()
- Enable more warnings -Wnull-dereference -Wuninitialized -Wunused -Wredundant-decls -Wconversion
- Add new examples
- host/bare_api to demonstrate generic (app-level) enumeration and endpoint transfer
- dual/host_hid_to_device_cdc to run both device and host stack concurrently, get HID report from host and print out to device CDC. This example only work with multiple-controller MCUs and rp2040 with the help of pio-usb as added controller.
Controller Driver (DCD & HCD)
-----------------------------
- Enhance rhports management to better support dual roles
- CFG_TUD_ENABLED/CFG_TUH_ENABLED, CFG_TUD_MAX_SPEED/CFG_TUH_MAX_SPEED can be used to replace CFG_TUSB_RHPORT0_MODE/CFG_TUSB_RHPORT1_MODE
- tud_init(rphort), tuh_init(rhport) can be used to init stack on specified roothub port (controller) instead of tusb_init(void)
- Add dcd/hcd port specific defines TUP_ (stand for tinyusb port-specific)
- [dwc2]
- Update to support stm32 h72x, h73x with only 1 otg controller
- Fix overwrite with grstctl when disable endpoint
- [EHCI] Fix an issue with EHCI driver
- [msp430] Fix for possible bug in msp430-elf-gcc 9.3.0
- [nrf5x] Fix DMA access race condition using atomic function
- [pic32] Fix PIC32 santiy
- [rp2040]
- Add PICO-PIO-USB as controller (device/host) support for rp2040
- Use shared IRQ handlers, so user can also hook the USB IRQ
- Fix resumed signal not reported to device stack
- [stm32fsdev] Add support for stm32wb55
Device Stack
------------
- [Audio] Add support for feedback endpoint computation
- New API tud_audio_feedback_params_cb(), tud_audio_feedback_interval_isr().
- Supported computation method are: frequency with fixed/float or power of 2. Feedback with fifo count is not yet supported.
- Fix nitfs (should be 3) in TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR
- Fix typo in audiod_rx_done_cb()
- [DFU] Fix coexistence with other interfaces BTH, RNDIS
- [MSC] Fix inquiry response additional length field
- [Venndor] Improve write performance
Host Stack
----------
- Add new API tuh_configure(rhport, cfg_id, cfg_param) for dynamnic port specific behavior configuration
- [HID] Open OUT endpoint if available
- [Hub] hub clear port and device interrupts
- [USBH] Major improvement
- Rework usbh control transfer with complete callback. New API tuh_control_xfer() though still only carry 1 usbh (no queueing) at a time.
- Add generic endpoint transfer with tuh_edpt_open(), tuh_edpt_xfer(). Require `CFG_TUH_API_EDPT_XFER=1`
- Support app-level enumeration with new APIs
- tuh_descriptor_get(), tuh_descriptor_get_device(), tuh_descriptor_get_configuration(), tuh_descriptor_get_hid_report()
- tuh_descriptor_get_string(), tuh_descriptor_get_manufacturer_string(), tuh_descriptor_get_product_string(), tuh_descriptor_get_serial_string()
- Also add _sync() as sync/blocking version for above APIs
0.13.0
======
- [tu_fifo] Fix locked mutex when full, and return type in peek_n()
Controller Driver (DCD & HCD)
-----------------------------
- [DWC2] Generalize synopsys dwc2 with synopsys/dwc2 which support both FS and HS phy (UTMI and ULPI) for various MCUs.
- Broadcom 28/27xx on raspberrypi SBC
- Silicon Labs EFM32
- Espressif ESP32 Sx
- GigaDevice GD32
- ST STM32
- Infineon XMC
- [KL25] Add new HCD for NXP KL25
- [MUSB] Add new DCD and HCD for Mentor musb with TI MSP432E4
- [F1C100s] Add new DCD for Allwinner F1C100s family
- [PIC32MZ] Add new DCD for PIC32MZ
- [nRF] Fix/Enhance various race condition with: EASY DMA, request HFXO, EPOUT
- [ChipIdea] rename Transdimension to more popular ChipIdea Highspeed,
- [RP2040] various update/fix for hcd/dcd
- [FT9XX] new DCD port for Bridgetek FT90x and FT93x devices
- [DA1469X] Fix resume
- [OHCI] Fix device array out of bound
Note: legacy drivers such as st/synopsys, nxp/transdimension are still present in this release but won't receive more update and could be removed in the future.
Device Stack
------------
- [Audio] Support disabling feedback format correction (16.16 <-> 10.14 format)
- [MSC] Add tud_msc_request_sense_cb() callback, change most default sense error to medium not present (0x02, 0x3A, 0x00)
- [Video] Fix video_capture example fails enumeration when 8FPS
Host Stack
----------
No notable changes
0.12.0
======
- add CFG_TUSB_OS_INC_PATH for os include path
Device Controller Driver (DCD)
------------------------------
- Getting device stack to pass USB Compliance Verification test (chapter9, HID, MSC). Ports are tested:
nRF, SAMD 21/51, rp2040, stm32f4, Renesas RX, iMXRT, ESP32-S2/3, Kinetic KL25/32, DA146xx
- Added dcd_edpt_close_all() for switching configuration
- [Transdimension] Support dcd_edpt_xfer_fifo() with auto wrap over if fifo buffer is 4K aligned and size is multiple of 4K.
- [DA146xx] Improve vbus, reset, suspend, resume detection, and remote wakeup.
Device Stack
------------
- Add new network driver Network Control Model (CDC-NCM), update net_lwip_webserver to work with NCM (need re-configure example)
- Add new USB Video Class UVC 1.5 driver and video_capture example ((work in progress)
- Fix potential buffer overflow for HID, bluetooth drivers
Host Controller Driver (HCD)
----------------------------
No notable changes
Host Stack
----------
No notable changes
0.11.0 (2021-08-29)
===================
- Add host/hid_controller example: only worked/tested with Sony PS4 DualShock controller
- Add device/hid_boot_interface example
- Add support for Renesas CCRX toolchain for RX mcu
Device Controller Driver (DCD)
------------------------------
- Add new DCD port for SAMx7x (E70, S70, V70, V71)
- Add new mcu K32L2Bxx
- Add new mcu GD32VF103
- Add new mcu STM32l151
- Add new mcu SAML21
- Add new mcu RX65n RX72n
- Fix NUC120/121/126 USBRAM can only be accessed in byte manner. Also improve set_address & disable sof
- Add Suspend/Resume handling for Renesas RX family.
- Fix DA1469x no VBUS startup
Synopsys
^^^^^^^^
- Fix Synopsys set address bug which could cause re-enumeration failed
- Fix dcd_synopsys driver integer overflow in HS mode (issue #968)
nRF5x
^^^^^
- Add nRF5x suspend, resume and remote wakeup
- Fix nRF5x race condition with TASKS_EP0RCVOUT
RP2040
^^^^^^
- Add RP2040 suspend & resume support
- Implement double buffer for both host and device (#891). However device EPOUT is still single buffered due to techinical issue with short packet
Device Stack
------------
USBD
^^^^
- Better support big endian mcu
- Add tuh_inited() and tud_inited(), will separate tusb_init/inited() to tud/tuh init/inited
- Add dcd_attr.h for defining common controller attribute such as max endpoints
Bluetooth
^^^^^^^^^
- Fix stridx error in descriptor template
DFU
^^^
- Enhance DFU implementation to support multiple alternate interface and better support bwPollTimeout
- Rename CFG_TUD_DFU_MODE to simply CFG_TUD_DFU
HID
^^^
- Fix newline usage keyboard (ENTER 0x28)
- Better support Hid Get/Set report
- Change max gamepad support from 16 to 32 buttons
MIDI
^^^^
- Fix midi available
- Fix midi data
- Fix an issue when calling midi API when not enumerated yet
UAC2
^^^^
- Fix bug and enhance of UAC2
Vendor
^^^^^^
- Fix vendor fifo deadlock in certain case
- Add tud_vendor_n_read_flush
Host Controller Driver (HCD)
----------------------------
RP2040
^^^^^^
- Implement double buffered to fix E4 errata and boost performance
- Lots of rp2040 update and enhancement
Host Stack
----------
- Major update and rework most of host stack, still needs more improvement
- Lots of improvement and update in parsing configuration and control
- Rework and major update to HID driver. Will default to enable boot interface if available
- Separate CFG_TUH_DEVICE_MAX and CFG_TUH_HUB for better management and reduce SRAM usage
0.10.1 (2021-06-03)
===================
- rework rp2040 examples and CMake build, allow better integration with pico-sdk
Host Controller Driver (HCD)
----------------------------
- Fix rp2040 host driver: incorrect PID with low speed device with max packet size of 8 bytes
- Improve hub driver
- Remove obsolete hcd_pipe_queue_xfer()/hcd_pipe_xfer()
- Use hcd_frame_number() instead of micro frame
- Fix OHCI endpoint address and xferred_bytes in xfer complete event
0.10.0 (2021-05-28)
===================
- Rework tu_fifo_t with separated mutex for read and write, better support DMA with read/write buffer info. And constant address mode
- Improve audio_test example and add audio_4_channel_mic example
- Add new dfu example
- Remove pico-sdk from submodule
Device Controller Driver (DCD)
------------------------------
- Add new DCD port for Silabs EFM32GG12 with board Thunderboard Kit (SLTB009A)
- Add new DCD port Renesas RX63N, board GR-CITRUS
- Add new (optional) endpoint API dcd_edpt_xfer_fifo
- Fix build with nRF5340
- Fix build with lpc15 and lpc54
- Fix build with lpc177x_8x
- STM32 Synopsys: greatly improve Isochronous transfer with edpt_xfer_fifo API
- Support LPC55 port1 highspeed
- Add support for Espressif esp32s3
- nRF: fix race condition that could cause drop packet of Bulk OUT transfer
USB Device Driver (USBD)
------------------------
- Add new (optional) endpoint ADPI usbd_edpt_xfer_fifo
Device Class Driver
-------------------
CDC
- [Breaking] tud_cdc_peek(), tud_vendor_peek() no longer support random offset and dropped position parameter.
DFU
- Add new DFU 1.1 class driver (WIP)
HID
- Fix keyboard report descriptor template
- Add more hid keys constant from 0x6B to 0xA4
- [Breaking] rename API
- HID_PROTOCOL_NONE/KEYBOARD/MOUST to HID_ITF_PROTOCOL_NONE/KEYBOARD/MOUSE
- tud_hid_boot_mode() to tud_hid_get_protocol()
- tud_hid_boot_mode_cb() to tud_hid_set_protocol_cb()
MIDI
- Fix MIDI buffer overflow issue
- [Breaking] rename API
- Rename tud_midi_read() to tud_midi_stream_read()
- Rename tud_midi_write() to tud_midi_stream_write()
- Rename tud_midi_receive() to tud_midi_packet_read()
- Rename tud_midi_send() to tud_midi_packet_write()
Host Controller Driver (HCD)
----------------------------
- No noticeable changes
USB Host Driver (USBH)
----------------------
- No noticeable changes
Host Class Driver
-----------------
- HID: Rework host hid driver, basically everything changes
0.9.0 (2021-03-12)
==================
Device Stack
------------
Device Controller Driver (DCD)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RP2040
- Fix endpoint buffer reallocation overrun problem
- Fix osal_pico queue overflow in initialization
- Fix Isochronous endpoint buffer size in transfer
- Optimize hardware endpoint struct to reduce RAM usage
- Fix enum walkaround forever check for SE0 when pull up is disabled
Sony CXD56
- Pass the correct speed on Spresense
- Fix setup processed flag
NXP Transdimention
- Update dcd_init() to reset controller to device mode
USB Device Driver (USBD)
^^^^^^^^^^^^^^^^^^^^^^^^
- Fix issue with status zlp (tud_control_status) is returned by class driver with SET/CLEAR_FEATURE for endpoint.
- Correct endpoint size check for fullspeed bulk, can be 8, 16, 32, 64
- Ack SET_INTERFACE even if it is not implemented by class driver.
Device Class Driver
^^^^^^^^^^^^^^^^^^^
DFU Runtime
- rename dfu_rt to dfu_runtime for easy reading
CDC
- Add tud_cdc_send_break_cb() to support break request
- Improve CDC receive, minor behavior changes: when tud_cdc_rx_wanted_cb() is invoked wanted_char may not be the last byte in the fifo
HID
- [Breaking] Add itf argument to hid API to support multiple instances, follow API has signature changes
- tud_hid_descriptor_report_cb()
- tud_hid_get_report_cb()
- tud_hid_set_report_cb()
- tud_hid_boot_mode_cb()
- tud_hid_set_idle_cb()
- Add report complete callback tud_hid_report_complete_cb() API
- Add DPad/Hat support for HID Gamepad
- `TUD_HID_REPORT_DESC_GAMEPAD()` now support 16 buttons, 2 joysticks, 1 hat/dpad
- Add hid_gamepad_report_t along with `GAMEPAD_BUTTON_` and `GAMEPAD_HAT_` enum
- Add Gamepad to hid_composite / hid_composite_freertos example
MIDI
- Fix dropping MIDI sysex message when fifo is full
- Fix typo in tud_midi_write24(), make example less ambiguous for cable and channel
- Fix incorrect endpoint descriptor length, MIDI v1 use Audio v1 which has 9-byte endpoint descriptor (instead of 7)
Host Stack
----------
Host Controller Driver (HCD)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Add rhport to hcd_init()
- Improve EHCI/OHCI driver abstraction
- Move echi/ohci files to portable/
- Rename hcd_lpc18_43 to hcd_transdimension
- Sub hcd API with hcd_ehci_init(), hcd_ehci_register_addr()
- Update NXP transdimention hcd_init() to reset controller to host mode
- Ported hcd to rt10xx
USB Host Driver (USBH)
^^^^^^^^^^^^^^^^^^^^^^
- No noticeable changes to usbh
Host Class Driver
^^^^^^^^^^^^^^^^^
MSC
- Rename tuh_msc_scsi_inquiry() to tuh_msc_inquiry()
- Rename tuh_msc_mounted_cb/tuh_msc_unmounted_cb to tuh_msc_mount_cb/tuh_msc_unmount_cb to match device stack naming
- Change tuh_msc_is_busy() to tuh_msc_ready()
- Add read10 and write10 function: tuh_msc_read10(), tuh_msc_write10()
- Read_Capacity is invoked as part of enumeration process
- Add tuh_msc_get_block_count(), tuh_msc_get_block_size()
- Add CFG_TUH_MSC_MAXLUN (default to 4) to hold lun capacities
Others
------
- Add basic support for rt-thread OS
- Change zero bitfield length to more explicit padding
- Build example now fetch required submodules on the fly while running `make` without prio submodule init for mcu drivers
- Update pico-sdk to v1.1.0
**New Boards**
- Microchip SAM E54 Xplained Pro
- LPCXpresso 55s28
- LPCXpresso 18s37
0.8.0 (2021-02-05)
==================
Device Controller Driver
------------------------
- Added new device support for Raspberry Pi RP2040
- Added new device support for NXP Kinetis KL25ZXX
- Use dcd_event_bus_reset() with link speed to replace bus_signal
- ESP32-S2:
- Add bus suspend and wakeup support
- SAMD21:
- Fix (walkaround) samd21 setup_packet overflow by USB DMA
- STM32 Synopsys:
- Rework USB FIFO allocation scheme and allow RX FIFO size reduction
- Sony CXD56
- Update Update Spresense SDK to 2.0.2
- Fix dcd issues with setup packets
- Correct EP number for cdc_msc example
USB Device
----------
**USBD**
- Rework usbd control transfer to have additional stage parameter for setup, data, status
- Fix tusb_init() return true instead of TUSB_ERROR_NONE
- Added new API tud_connected() that return true after device got out of bus reset and received the very first setup packet
**Class Driver**
- CDC
- Allow to transmit data, even if the host does not support control line states i.e set DTR
- HID
- change default CFG_TUD_HID_EP_BUFSIZE from 16 to 64
- MIDI
- Fix midi sysex sending bug
- MSC
- Invoke only scsi complete callback after status transaction is complete.
- Fix scsi_mode_sense6_t padding, which cause IAR compiler internal error.
- USBTMC
- Change interrupt endpoint example size to 8 instead of 2 for better compatibility with mcu
**Example**
- Support make from windows cmd.exe
- Add HID Consumer Control (media keys) to hid_composite & hid_composite_freertos examples
USB Host
--------
No noticeable changes to host stack
New Boards
----------
- NXP/Freescale Freedom FRDM-KL25Z
- Feather Double M33 express
- Raspberry Pi Pico
- Adafruit Feather RP2040
- Adafruit Itsy Bitsy RP2040
- Adafruit QT RP2040
- Adfruit Feather ESP32-S2
- Adafruit Magtag 29" Eink
- Adafruit Metro ESP32-S2
- Adafruit PyBadge
- Adafruit PyPortal
- Great Scott Gadgets' LUNA D11 & D21
0.7.0 (2020-11-08)
==================
Device Controller Driver
------------------------
- Added new support for Espressif ESP32-S2
- Added new support for Dialog DA1469x
- Enhance STM32 Synopsys
- Support bus events disconnection/suspend/resume/wakeup
- Improve transfer performance with optimizing xfer and fifo size
- Support Highspeed port (OTG_HS) with both internal and external PHY
- Support multiple usb ports with rhport=1 is highspeed on selected MCUs e.g H743, F23. It is possible to have OTG_HS to run on Fullspeed PHY (e.g lacking external PHY)
- Add ISO transfer, fix odd/even frame
- Fix FIFO flush during stall
- Implement dcd_edpt_close() API
- Support F105, F107
- Enhance STM32 fsdev
- Improve dcd fifo allocation
- Fix ISTR race condition
- Support remap USB IRQ on supported MCUs
- Implement dcd_edpt_close() API
- Enhance NUC 505: enhance set configure behavior
- Enhance SAMD
- Fix race condition with setup packet
- Add SAMD11 option `OPT_MCU_SAMD11`
- Add SAME5x option `OPT_MCU_SAME5X`
- Fix SAMG control data toggle and stall race condition
- Enhance nRF
- Fix hanged when tud_task() is called within critical section (disabled interrupt)
- Fix disconnect bus event not submitted
- Implement ISO transfer and dcd_edpt_close()
USB Device
----------
**USBD**
- Add new class driver for **Bluetooth HCI** class driver with example can be found in [mynewt-tinyusb-example](https://github.com/hathach/mynewt-tinyusb-example) since it needs mynewt OS to run with.
- Fix USBD endpoint usage racing condition with `usbd_edpt_claim()/usbd_edpt_release()`
- Added `tud_task_event_ready()` and `osal_queue_empty()`. This API is needed to check before enter low power mode with WFI/WFE
- Rename USB IRQ Handler to `dcd_int_handler()`. Application must define IRQ handler in which it calls this API.
- Add `dcd_connect()` and `dcd_disconnect()` to enable/disable internal pullup on D+/D- on supported MCUs.
- Add `usbd_edpt_open()`
- Remove `dcd_set_config()`
- Add *OPT_OS_CUMSTOM* as hook for application to overwrite and/or add their own OS implementation
- Support SET_INTERFACE, GET_INTERFACE request
- Add Logging for debug with optional uart/rtt/swo printf retarget or `CFG_TUSB_DEBUG_PRINTF` hook
- Add IAR compiler support
- Support multiple configuration descriptors. `TUD_CONFIG_DESCRIPTOR()` template has extra config_num as 1st argument
- Improve USB Highspeed support with actual link speed detection with `dcd_event_bus_reset()`
- Enhance class driver management
- `usbd_driver_open()` add max length argument, and return length of interface (0 for not supported). Return value is used for finding appropriate driver
- Add application implemented class driver via `usbd_app_driver_get_cb()`
- IAD is handled to assign driver id
- Added `tud_descriptor_device_qualifier_cb()` callback
- Optimize `tu_fifo` bulk write/read transfer
- Forward non-std control request to class driver
- Let application handle Microsoft OS 1.0 Descriptors (the 0xEE index string)
- Fix OSAL FreeRTOS yield from ISR
**Class Drivers**
- USBNET: remove ACM-EEM due to lack of support from host
- USBTMC: fix descriptors when INT EP is disabled
- CDC:
- Send zero length packet for end of data when needed
- Add `tud_cdc_tx_complete_cb()` callback
- Change tud_cdc_n_write_flush() return number of bytes forced to transfer, and flush when writing enough data to fifo
- MIDI:
- Add packet interface
- Add multiple jack descriptors
- Fix MIDI driver for sysex
- DFU Runtime: fix response to SET_INTERFACE and DFU_GETSTATUS request
- Rename some configure macro to make it clear that those are used directly for endpoint transfer
- CFG_TUD_HID_BUFSIZE to CFG_TUD_HID_EP_BUFSIZE
- CFG_TUD_CDC_EPSIZE to CFG_TUD_CDC_EP_BUFSIZE
- CFG_TUD_MSC_BUFSIZE to CFG_TUD_MSC_EP_BUFSIZE
- CFG_TUD_MIDI_EPSIZE to CFG_TUD_MIDI_EP_BUFSIZE
- HID:
- Fix gamepad template descriptor
- Add multiple HID interface API
- Add extra comma to HID_REPORT_ID
USB Host
--------
- Rework USB host stack (still work in progress)
- Fix compile error with pipehandle
- Rework usbh control and enumeration as non-blocking
- Improve Hub, MSC, HID host driver
Examples
--------
- Add new hid_composite_freertos
- Add new dynamic_configuration to demonstrate how to switch configuration descriptors
- Add new hid_multiple_interface
- Enhance `net_lwip_webserver` example
- Add multiple configuration: RNDIS for Windows, CDC-ECM for macOS (Linux will work with both)
- Update lwip to STABLE-2_1_2_RELEASE for net_lwip_webserver
- Added new Audio example: audio_test uac2_headsest
New Boards
----------
- Espressif ESP32-S2: saola_1, kaluga_1
- STM32: F746 Nucleo, H743 Eval, H743 Nucleo, F723 discovery, stlink v3 mini, STM32L4r5 Nucleo
- Dialog DA1469x dk pro and dk usb
- Microchip: Great Scoot Gadgets' LUNA, samd11_xplained, D5035-01, atsamd21 xplained pro
- nRF: ItsyBitsy nRF52840
0.6.0 (2020-03-30)
==================
Added **CONTRIBUTORS.md** to give proper credit for contributors to the stack. Special thanks to `Nathan Conrad <https://github.com/pigrew>`__ , `Peter Lawrence <https://github.com/majbthrd>`__ , `William D. Jones <https://github.com/cr1901>`__ and `Sean Cross <https://github.com/xobs>`__ and others for spending their precious time to add lots of features and ports for this release.
Added
-----
**MCU**
- Added support for Microchip SAMG55
- Added support for Nordic nRF52833
- Added support for Nuvoton: NUC120, NUC121/NUC125, NUC126, NUC505
- Added support for NXP LPC: 51Uxx, 54xxx, 55xx
- Added support for NXP iMXRT: RT1011, RT1015, RT1021, RT1052, RT1062, RT1064
- Added support for Sony CXD56 (Spresense)
- Added support for STM32: L0, F0, F1, F2, F3, F4, F7, H7
- Added support for TI MSP430
- Added support for ValentyUSB's eptri
**Class Driver**
- Added DFU Runtime class driver
- Added Network class driver with RNDIS, CDC-ECM, CDC-EEM (work in progress)
- Added USBTMC class driver
- Added WebUSB class driver using vendor-specific class
- Added multiple instances support for CDC and MIDI
- Added a handful of unit test with Ceedling.
- Added LOG support for debugging with CFG_TUSB_DEBUG
- Added `tud_descriptor_bos_cb()` for BOS descriptor (required for USB 2.1)
- Added `dcd_edpt0_status_complete()` as optional API for DCD
**Examples**
Following examples are added:
- board_test
- cdc_dual_ports
- dfu_rt
- hid_composite
- net_lwip_webserver
- usbtmc
- webusb_serial
Changed
-------
- Changed `tud_descriptor_string_cb()` to have additional Language ID argument
- Merged hal_nrf5x.c into dcd_nrf5x.c
- Merged dcd_samd21.c and dcd_samd51.c into dcd_samd.c
- Generalized dcd_stm32f4.c to dcd_synopsys.c
- Changed cdc_msc_hid to cdc_msc (drop hid) due to limited endpoints number of some MCUs
- Improved DCD SAMD stability, fix missing setup packet occasionally
- Improved usbd/usbd_control with proper handling of zero-length packet (ZLP)
- Improved STM32 DCD FSDev
- Improved STM32 DCD Synopsys
- Migrated CI from Travis to Github Action
- Updated nrfx submodule to 2.1.0
- Fixed mynewt osal queue definition
- Fixed cdc_msc_freertos example build for all MCUs
0.5.0 (2019-06)
===============
First release, device stack works great, host stack works but still need improvement.
- Special thanks to @adafruit team, especially @tannewt to help out immensely to rework device stack: simplify osal & control transfer, adding SAMD21/SAMD51 ports, writing porting docs, adding MIDI class support etc...
- Thanks to @cr1901 for adding STM32F4 port.
- Thanks to @PTS93 and @todbot for HID raw API

@ -0,0 +1,13 @@
****
Info
****
Index
=====
.. toctree::
:maxdepth: 2
uses
changelog
contributors

@ -0,0 +1,17 @@
****
Uses
****
TinyUSB is currently used by these other projects:
- `Adafruit nRF52 Arduino <https://github.com/adafruit/Adafruit_nRF52_Arduino>`__
- `Adafruit nRF52 Bootloader <https://github.com/adafruit/Adafruit_nRF52_Bootloader>`__
- `Adafruit SAMD Arduino <https://github.com/adafruit/ArduinoCore-samd>`__
- `CircuitPython <https://github.com/adafruit/circuitpython>`__
- `Espressif IDF <https://github.com/espressif/esp-idf>`__
- `MicroPython <https://github.com/micropython/micropython>`__
- `mynewt <https://mynewt.apache.org>`__
- `openinput <https://github.com/openinput-fw/openinput>`__
- `Raspberry Pi Pico SDK <https://github.com/raspberrypi/pico-sdk>`__
- `TinyUF2 Bootloader <https://github.com/adafruit/tinyuf2>`__
- `TinyUSB Arduino Library <https://github.com/adafruit/Adafruit_TinyUSB_Arduino>`__

@ -0,0 +1,42 @@
***********
Concurrency
***********
The TinyUSB library is designed to operate on single-core MCUs with multi-threaded applications in mind. Interaction with interrupts is especially important to pay attention to.
It is compatible with optionally using a RTOS.
General
-------
When writing code, keep in mind that the OS (if using a RTOS) may swap out your code at any time. Also, your code can be preempted by an interrupt at any time.
Application Code
----------------
The USB core does not execute application callbacks while in an interrupt context. Calls to application code are from within the USB core task context. Note that the application core will call class drivers from within their own task.
Class Drivers
-------------
Class driver code should never be called from an interrupt context by the USB core, though the application is allowed to call class driver functions from interrupts. USB core functions may be called simultaneously by multiple tasks. Use care that proper locking is used to guard the USBD core functions from this case.
Class drivers are allowed to call ``usbd_*`` functions, but not ``dcd_*`` functions.
USB Core
--------
All functions that may be called from an (USB core) interrupt context have a ``bool in_isr`` parameter to remind the implementer that special care must be taken.
Interrupt handlers must not directly call class driver code, they must pass a message to the USB core's task.
``usbd_*`` functions may be called from interrupts without any notice. They may also be called simultaneously by multiple tasks.
Device Drivers
--------------
Much of the processing of the USB stack is done in an interrupt context, and care must be taken in order to ensure variables are handled in the appropriate ways by the compiler and optimizer.
In particular:
* Ensure that all memory-mapped registers (including packet memory) are marked as volatile. GCC's optimizer will even combine memory access (like two 16-bit to be a 32-bit) if you don't mark the pointers as volatile. On some architectures, this can use macros like _I , _O , or _IO.
* All defined global variables are marked as ``static``.

@ -0,0 +1,206 @@
***************
Getting Started
***************
Add TinyUSB to your project
---------------------------
It is relatively simple to incorporate tinyusb to your (existing) project
* Copy or ``git submodule`` this repo into your project in a subfolder. Let's say it is *your_project/tinyusb*
* Add all the .c in the ``tinyusb/src`` folder to your project
* Add *your_project/tinyusb/src* to your include path. Also make sure your current include path also contains the configuration file tusb_config.h.
* Make sure all required macros are all defined properly in tusb_config.h (configure file in demo application is sufficient, but you need to add a few more such as CFG_TUSB_MCU, CFG_TUSB_OS since they are passed by IDE/compiler to maintain a unique configure for all boards).
* If you use the device stack, make sure you have created/modified usb descriptors for your own need. Ultimately you need to implement all **tud descriptor** callbacks for the stack to work.
* Add tusb_init() call to your reset initialization code.
* Call ``tud_int_handler()`` (device) and/or ``tuh_int_handler()`` (host) in your USB IRQ Handler
* Implement all enabled classes's callbacks.
* If you don't use any RTOSes at all, you need to continuously and/or periodically call tud_task()/tuh_task() function. All of the callbacks and functionality are handled and invoked within the call of that task runner.
.. code-block::
int main(void)
{
your_init_code();
tusb_init(); // initialize tinyusb stack
while(1) // the mainloop
{
your_application_code();
tud_task(); // device task
tuh_task(); // host task
}
}
Examples
--------
For your convenience, TinyUSB contains a handful of examples for both host and device with/without RTOS to quickly test the functionality as well as demonstrate how API() should be used. Most examples will work on most of `the supported boards <supported.rst>`_. Firstly we need to ``git clone`` if not already
.. code-block::
$ git clone https://github.com/hathach/tinyusb tinyusb
$ cd tinyusb
Some TinyUSB examples also requires external submodule libraries in ``/lib`` such as FreeRTOS, Lightweight IP to build. Run following command to fetch them
.. code-block::
$ git submodule update --init lib
Some ports will also require a port-specific SDK (e.g. RP2040) or binary (e.g. Sony Spresense) to build examples. They are out of scope for tinyusb, you should download/install it first according to its manufacturer guide.
Build
^^^^^
To build example, first change directory to an example folder.
.. code-block::
$ cd examples/device/cdc_msc
Before building, we need to download MCU driver submodule to provide low-level MCU peripheral's driver first. Run the ``get-deps`` target in one of the example folder as follow. You only need to do this once per mcu
.. code-block::
$ make BOARD=feather_nrf52840_express get-deps
Some modules (e.g. RP2040 and ESP32s2) require the project makefiles to be customized using CMake. If necessary apply any setup steps for the platform's SDK.
Then compile with ``make BOARD=[board_name] all``\ , for example
.. code-block::
$ make BOARD=feather_nrf52840_express all
Note: ``BOARD`` can be found as directory name in ``hw/bsp``\ , either in its family/boards or directly under bsp (no family).
Note: some examples especially those that uses Vendor class (e.g webUSB) may requires udev permission on Linux (and/or macOS) to access usb device. It depends on your OS distro, typically copy ``/examples/device/99-tinyusb.rules`` file to /etc/udev/rules.d/ then run ``sudo udevadm control --reload-rules && sudo udevadm trigger`` is good enough.
Port Selection
~~~~~~~~~~~~~~
If a board has several ports, one port is chosen by default in the individual board.mk file. Use option ``PORT=x`` To choose another port. For example to select the HS port of a STM32F746Disco board, use:
.. code-block::
$ make BOARD=stm32f746disco PORT=1 all
Port Speed
~~~~~~~~~~
A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option ``SPEED=full/high`` e.g To force F723 operate at full instead of default high speed
.. code-block::
$ make BOARD=stm32f746disco SPEED=full all
Size Analysis
~~~~~~~~~~~~~
First install `linkermap tool <https://github.com/hathach/linkermap>`_ then ``linkermap`` target can be used to analyze code size. You may want to compile with ``NO_LTO=1`` since -flto merges code across .o files and make it difficult to analyze.
.. code-block::
$ make BOARD=feather_nrf52840_express NO_LTO=1 all linkermap
Debug
^^^^^
To compile for debugging add ``DEBUG=1``\ , for example
.. code-block::
$ make BOARD=feather_nrf52840_express DEBUG=1 all
Log
~~~
Should you have an issue running example and/or submitting an bug report. You could enable TinyUSB built-in debug logging with optional ``LOG=``. LOG=1 will only print out error message, LOG=2 print more information with on-going events. LOG=3 or higher is not used yet.
.. code-block::
$ make BOARD=feather_nrf52840_express LOG=2 all
Logger
~~~~~~
By default log message is printed via on-board UART which is slow and take lots of CPU time comparing to USB speed. If your board support on-board/external debugger, it would be more efficient to use it for logging. There are 2 protocols:
* `LOGGER=rtt`: use `Segger RTT protocol <https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/>`_
* Cons: requires jlink as the debugger.
* Pros: work with most if not all MCUs
* Software viewer is JLink RTT Viewer/Client/Logger which is bundled with JLink driver package.
* ``LOGGER=swo``\ : Use dedicated SWO pin of ARM Cortex SWD debug header.
* Cons: only work with ARM Cortex MCUs minus M0
* Pros: should be compatible with more debugger that support SWO.
* Software viewer should be provided along with your debugger driver.
.. code-block::
$ make BOARD=feather_nrf52840_express LOG=2 LOGGER=rtt all
$ make BOARD=feather_nrf52840_express LOG=2 LOGGER=swo all
Flash
^^^^^
``flash`` target will use the default on-board debugger (jlink/cmsisdap/stlink/dfu) to flash the binary, please install those support software in advance. Some board use bootloader/DFU via serial which is required to pass to make command
.. code-block::
$ make BOARD=feather_nrf52840_express flash
$ make SERIAL=/dev/ttyACM0 BOARD=feather_nrf52840_express flash
Since jlink can be used with most of the boards, there is also ``flash-jlink`` target for your convenience.
.. code-block::
$ make BOARD=feather_nrf52840_express flash-jlink
Some board use uf2 bootloader for drag & drop in to mass storage device, uf2 can be generated with ``uf2`` target
.. code-block::
$ make BOARD=feather_nrf52840_express all uf2
IAR Support
^^^^^^^^^^^
IAR Project Connection files are provided to import TinyUSB stack into your project.
* A buldable project of your MCU need to be created in advance.
* Take example of STM32F0:
- You need `stm32l0xx.h`, `startup_stm32f0xx.s`, `system_stm32f0xx.c`.
- `STM32L0xx_HAL_Driver` is only needed to run examples, TinyUSB stack itself doesn't rely on MCU's SDKs.
* Open `Tools -> Configure Custom Argument Variables` (Switch to `Global` tab if you want to do it for all your projects)
Click `New Group ...`, name it to `TUSB`, Click `Add Variable ...`, name it to `TUSB_DIR`, change it's value to the path of your TinyUSB stack,
for example `C:\\tinyusb`
Import stack only
~~~~~~~~~~~~~~~~~
1. Open `Project -> Add project Connection ...`, click `OK`, choose `tinyusb\\tools\\iar_template.ipcf`.
Run examples
~~~~~~~~~~~~
1. (Python3 is needed) Run `iar_gen.py` to generate .ipcf files of examples:
.. code-block::
cd C:\tinyusb\tools
python iar_gen.py
2. Open `Project -> Add project Connection ...`, click `OK`, choose `tinyusb\\examples\\(.ipcf of example)`.
For example `C:\\tinyusb\\examples\\device\\cdc_msc\\iar_cdc_msc.ipcf`

@ -0,0 +1,59 @@
*********
Reference
*********
.. figure:: ../assets/stack.svg
:width: 1600px
:alt: stackup
representation of the TinyUSB stack.
Device Stack
============
Supports multiple device configurations by dynamically changing usb descriptors. Low power functions such like suspend, resume, and remote wakeup. Following device classes are supported:
- Audio Class 2.0 (UAC2)
- Bluetooth Host Controller Interface (BTH HCI)
- Communication Class (CDC)
- Device Firmware Update (DFU): DFU mode (WIP) and Runtinme
- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ...
- Mass Storage Class (MSC): with multiple LUNs
- Musical Instrument Digital Interface (MIDI)
- Network with RNDIS, CDC-ECM (work in progress)
- USB Test and Measurement Class (USBTMC)
- Vendor-specific class support with generic In & Out endpoints. Can be used with MS OS 2.0 compatible descriptor to load winUSB driver without INF file.
- `WebUSB <https://github.com/WICG/webusb>`__ with vendor-specific class
If you have special need, `usbd_app_driver_get_cb()` can be used to write your own class driver without modifying the stack. Here is how RPi team add their reset interface `raspberrypi/pico-sdk#197 <https://github.com/raspberrypi/pico-sdk/pull/197>`__
Host Stack
==========
- Human Interface Device (HID): Keyboard, Mouse, Generic
- Mass Storage Class (MSC)
- Hub currently only supports 1 level of hub (due to my laziness)
OS Abstraction layer
====================
TinyUSB is completely thread-safe by pushing all ISR events into a central queue, then process it later in the non-ISR context task function. It also uses semaphore/mutex to access shared resources such as CDC FIFO. Therefore the stack needs to use some of OS's basic APIs. Following OSes are already supported out of the box.
- **No OS**
- **FreeRTOS**
- **Mynewt** Due to the newt package build system, Mynewt examples are better to be on its `own repo <https://github.com/hathach/mynewt-tinyusb-example>`__
License
=======
All TinyUSB sources in the `src` folder are licensed under MIT license. However, each file can be individually licensed especially those in `lib` and `hw/mcu` folder. Please make sure you understand all the license term for files you use in your project.
Index
=====
.. toctree::
:maxdepth: 2
supported
getting_started
concurrency

@ -0,0 +1,406 @@
*****************
Supported Devices
*****************
Supported MCUs
==============
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| Manufacturer | Family | Device | Host | Highspeed | Driver | Note |
+==============+=======================+========+======+===========+===================+==============+
| Broadcom | BCM2711, BCM2837 | ✔ | | ✔ | dwc2 | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| Dialog | DA1469x | ✔ | ✖ | ✖ | da146xx | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| Espressif | ESP32 S2, S3 | ✔ | | ✖ | dwc2 or esp32sx | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| GigaDevice | GD32VF103 | ✔ | | ✖ | dwc2 | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| Infineon | XMC4500 | ✔ | | ✖ | dwc2 | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| MicroChip | SAM D11, D21 | ✔ | | ✖ | samd | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | SAM D51, E5x | ✔ | | ✖ | samd | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | SAM G55 | ✔ | | ✖ | samg | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | SAM L21, L22 | ✔ | | ✖ | samd | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | SAM E70,S70,V70,V71 | ✔ | | ✔ | samx7x | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| NordicSemi | nRF52833, nRF52840 | ✔ | ✖ | ✖ | nrf5x | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | nRF5340 | ✔ | ✖ | ✖ | nrf5x | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| Nuvoton | NUC120 | ✔ | ✖ | ✖ | | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | NUC121/NUC125 | ✔ | ✖ | ✖ | | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | NUC126 | ✔ | ✖ | ✖ | | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | NUC505 | ✔ | | ✔ | | |
+--------------+---------+-------------+--------+------+-----------+-------------------+--------------+
| NXP | iMXRT | RT10xx | ✔ | ✔ | ✔ | ci_hs | |
| | +-------------+--------+------+-----------+-------------------+--------------+
| | | RT11xx | ✔ | ✔ | ✔ | ci_hs | |
| +---------+-------------+--------+------+-----------+-------------------+--------------+
| | Kinetis | KL25 | ✔ | ⚠ | ✖ | | |
| | +-------------+--------+------+-----------+-------------------+--------------+
| | | K32L2 | ✔ | | ✖ | | |
| +---------+-------------+--------+------+-----------+-------------------+--------------+
| | LPC | 11u, 13, 15 | ✔ | ✖ | ✖ | lpc_ip3511 | |
| | +-------------+--------+------+-----------+-------------------+--------------+
| | | 17, 40 | ✔ | ⚠ | ✖ | lpc17_40 | |
| | +-------------+--------+------+-----------+-------------------+--------------+
| | | 18, 43 | ✔ | ✔ | ✔ | ci_hs | |
| | +-------------+--------+------+-----------+-------------------+--------------+
| | | 51u | ✔ | ✖ | ✖ | lpc_ip3511 | |
| | +-------------+--------+------+-----------+-------------------+--------------+
| | | 54 | ✔ | | ✔ | lpc_ip3511 | |
| | +-------------+--------+------+-----------+-------------------+--------------+
| | | 55 | ✔ | | ✔ | lpc_ip3511 | |
+--------------+---------+-------------+--------+------+-----------+-------------------+--------------+
| Raspberry Pi | RP2040 | ✔ | ✔ | ✖ | rp2040, pio_usb | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| Renesas | RX 63N, 65N, 72N | ✔ | ✔ | ✖ | usba | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| Silabs | EFM32GG12 | ✔ | | ✖ | dwc2 | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| Sony | CXD56 | ✔ | ✖ | ✔ | cxd56 | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| ST STM32 | F0 | ✔ | ✖ | ✖ | stm32_fsdev | |
| +----+------------------+--------+------+-----------+-------------------+--------------+
| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | |
| | +------------------+--------+------+-----------+-------------------+--------------+
| | | 105, 107 | ✔ | | ✖ | dwc2 | |
| +----+------------------+--------+------+-----------+-------------------+--------------+
| | F2 | ✔ | | ✔ | dwc2 | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | F3 | ✔ | ✖ | ✖ | stm32_fsdev | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | F4 | ✔ | | ✔ | dwc2 | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | F7 | ✔ | | ✔ | dwc2 | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | H7 | ✔ | | ✔ | dwc2 | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | L0, L1 | ✔ | ✖ | ✖ | stm32_fsdev | |
| +----+------------------+--------+------+-----------+-------------------+--------------+
| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | |
| | +------------------+--------+------+-----------+-------------------+--------------+
| | | 4x5, 4x6 | ✔ | | | dwc2 | |
| +----+------------------+--------+------+-----------+-------------------+--------------+
| | L4+ | ✔ | | | dwc2 | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | U5 | ⚠ | | | dwc2 | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | WBx5 | ✔ | | | stm32_fsdev | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| TI | MSP430 | ✔ | ✖ | ✖ | msp430x5xx | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | MSP432E4 | ✔ | | ✖ | musb | |
| +-----------------------+--------+------+-----------+-------------------+--------------+
| | TM4C123 | ✔ | | ✖ | musb | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| ValentyUSB | eptri | ✔ | ✖ | ✖ | eptri | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
| WCH | CH32V307 | ✔ | | ✔ | ch32v307 | |
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
Table Legend
------------
= ===================
✔ Supported
⚠ WIP/partial support
✖ Not supported
= ===================
Supported Boards
================
The board support code is only used for self-contained examples and testing. It is not used when TinyUSB is part of a larger project. It is responsible for getting the MCU started and the USB peripheral clocked with minimal of on-board devices
- One LED : for status
- One Button : to get input from user
- One UART : optional for device, but required for host examples
The following boards are supported (sorted alphabetically):
Broadcom
--------
- `Raspberry Pi CM4 <https://www.raspberrypi.com/products/compute-module-4>`__
Dialog DA146xx
--------------
- `DA14695 Development Kit USB <https://www.dialog-semiconductor.com/products/da14695-development-kit-usb>`__
- `DA1469x Development Kit Pro <https://www.dialog-semiconductor.com/products/da14695-development-kit-pro>`__
Espressif ESP32-S2
------------------
- `Adafruit Feather ESP32-S2 <https://www.adafruit.com/product/5000>`__
- `Adafruit Magtag 2.9" E-Ink WiFi Display <https://www.adafruit.com/product/4800>`__
- `Adafruit Metro ESP32-S2 <https://www.adafruit.com/product/4775>`__
- `ESP32-S2-Kaluga-1 <https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-esp32-s2-kaluga-1-kit.html>`__
- `ESP32-S2-Saola-1 <https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-saola-1-v1.2.html>`__
GigaDevice
----------
- `Sipeed Longan Nano <https://longan.sipeed.com/en/>`__
Infineon
---------
XMC4000
^^^^^^^
- `XMC4500 Relax (Lite) Kit <https://www.infineon.com/cms/en/product/evaluation-boards/kit_xmc45_relax_lite_v1/>`__
MicroChip
---------
SAMD11 & SAMD21
^^^^^^^^^^^^^^^
- `Adafruit Circuit Playground Express <https://www.adafruit.com/product/3333>`__
- `Adafruit Feather M0 Express <https://www.adafruit.com/product/3403>`__
- `Adafruit ItsyBitsy M0 Express <https://www.adafruit.com/product/3727>`__
- `Adafruit Metro M0 Express <https://www.adafruit.com/product/3505>`__
- `Great Scott Gadgets LUNA <https://greatscottgadgets.com/luna/>`__
- `Microchip SAMD11 Xplained Pro <https://www.microchip.com/developmenttools/ProductDetails/atsamd11-xpro>`__
- `Microchip SAMD21 Xplained Pro <https://www.microchip.com/DevelopmentTools/ProductDetails/ATSAMD21-XPRO>`__
- `Seeeduino Xiao <https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html>`__
SAMD51 & SAME54
^^^^^^^^^^^^^^^
- `Adafruit Feather M4 Express <https://www.adafruit.com/product/3857>`__
- `Adafruit ItsyBitsy M4 Express <https://www.adafruit.com/product/3800>`__
- `Adafruit PyBadge <https://www.adafruit.com/product/4200>`__
- `Adafruit PyPortal <https://www.adafruit.com/product/4116>`__
- `Adafruit Metro M4 Express <https://www.adafruit.com/product/3382>`__
- `D5035-01 <https://github.com/RudolphRiedel/USB_CAN-FD>`__
- `Microchip SAME54 Xplained Pro <https://www.microchip.com/developmenttools/productdetails/atsame54-xpro>`__
SAME7x
^^^^^^
- `Microchip SAME70 Xplained <https://www.microchip.com/en-us/development-tool/ATSAME70-XPLD>`_
- `QMTECH ATSAME70N19 <https://www.aliexpress.com/item/1005003173783268.html>`_
SAMG
^^^^
- `Microchip SAMG55 Xplained Pro <https://www.microchip.com/DevelopmentTools/ProductDetails/PartNO/ATSAMG55-XPRO>`__
SAML2x
^^^^^^
- `SAML21 Xplaind Pro <https://www.microchip.com/DevelopmentTools/ProductDetails/ATSAML21-XPRO-B>`__
- `SAML22 Feather <https://github.com/joeycastillo/Feather-Projects/tree/main/SAML22%20Feather>`__
- `Sensor Watch <https://github.com/joeycastillo/Sensor-Watch>`__
Nordic nRF5x
------------
- `Adafruit Circuit Playground Bluefruit <https://www.adafruit.com/product/4333>`__
- `Adafruit CLUE <https://www.adafruit.com/product/4500>`__
- `Adafruit Feather nRF52840 Express <https://www.adafruit.com/product/4062>`__
- `Adafruit Feather nRF52840 Sense <https://www.adafruit.com/product/4516>`__
- `Adafruit ItsyBitsy nRF52840 Express <https://www.adafruit.com/product/4481>`__
- `Arduino Nano 33 BLE <https://store.arduino.cc/usa/nano-33-ble>`__
- `Arduino Nano 33 BLE Sense <https://store.arduino.cc/usa/nano-33-ble-sense>`__
- `Maker Diary nRF52840 MDK Dongle <https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle>`__
- `Nordic nRF52840 Development Kit (aka pca10056) <https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK>`__
- `Nordic nRF52840 Dongle (aka pca10059) <https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle>`__
- `Nordic nRF52833 Development Kit (aka pca10100) <https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52833-DK>`__
- `Raytac MDBT50Q-RX Dongle <https://www.raytac.com/product/ins.php?index_id=89>`__
Nuvoton
-------
- NuTiny SDK NUC120
- `NuTiny NUC121S <https://direct.nuvoton.com/en/nutiny-nuc121s>`__
- `NuTiny NUC125S <https://direct.nuvoton.com/en/nutiny-nuc125s>`__
- `NuTiny NUC126V <https://direct.nuvoton.com/en/nutiny-nuc126v>`__
- `NuTiny SDK NUC505Y <https://direct.nuvoton.com/en/nutiny-nuc505y>`__
NXP
---
iMX RT
^^^^^^
- `MIMX RT1010 Evaluation Kit <https://www.nxp.com/design/development-boards/i.mx-evaluation-and-development-boards/i.mx-rt1010-evaluation-kit:MIMXRT1010-EVK>`__
- `MIMX RT1015 Evaluation Kit <https://www.nxp.com/design/development-boards/i.mx-evaluation-and-development-boards/i.mx-rt1015-evaluation-kit:MIMXRT1015-EVK>`__
- `MIMX RT1020 Evaluation Kit <https://www.nxp.com/design/development-boards/i.mx-evaluation-and-development-boards/i.mx-rt1020-evaluation-kit:MIMXRT1020-EVK>`__
- `MIMX RT1050 Evaluation Kit <https://www.nxp.com/design/development-boards/i.mx-evaluation-and-development-boards/i.mx-rt1050-evaluation-kit:MIMXRT1050-EVK>`__
- `MIMX RT1060 Evaluation Kit <https://www.nxp.com/design/development-boards/i.mx-evaluation-and-development-boards/mimxrt1060-evk-i.mx-rt1060-evaluation-kit:MIMXRT1060-EVK>`__
- `MIMX RT1064 Evaluation Kit <https://www.nxp.com/design/development-boards/i.mx-evaluation-and-development-boards/mimxrt1064-evk-i.mx-rt1064-evaluation-kit:MIMXRT1064-EVK>`__
- `Teensy 4.0 Development Board <https://www.pjrc.com/store/teensy40.html>`__
- `Teensy 4.1 Development Board <https://www.pjrc.com/store/teensy41.html>`__
Kinetis
^^^^^^^
- `Freedom FRDM-KL25Z <https://www.nxp.com/design/development-boards/freedom-development-boards/mcu-boards/freedom-development-platform-for-kinetis-kl14-kl15-kl24-kl25-mcus:FRDM-KL25Z>`__
- `Freedom FRDM-K32L2B3 <https://www.nxp.com/design/development-boards/freedom-development-boards/mcu-boards/nxp-freedom-development-platform-for-k32-l2b-mcus:FRDM-K32L2B3>`__
- `KUIIC <https://github.com/nxf58843/kuiic>`__
LPC 11-13-15
^^^^^^^^^^^^
- `LPCXpresso 11u37 <https://www.nxp.com/design/microcontrollers-developer-resources/lpcxpresso-boards/lpcxpresso-board-for-lpc11u37h:OM13074>`__
- `LPCXpresso 11u68 <https://www.nxp.com/support/developer-resources/evaluation-and-development-boards/lpcxpresso-boards/lpcxpresso-board-for-lpc11u68:OM13058>`__
- `LPCXpresso 1347 <https://www.nxp.com/support/developer-resources/evaluation-and-development-boards/lpcxpresso-boards/lpcxpresso-board-for-lpc1347:OM13045>`__
- `LPCXpresso 1549 <https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc1500-cortex-m3/lpcxpresso-board-for-lpc1549:OM13056>`__
LPC 17-40
^^^^^^^^^
- `ARM mbed LPC1768 <https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc1700-cortex-m3/arm-mbed-lpc1768-board:OM11043>`__
- `Embedded Artists LPC4088 Quick Start board <https://www.embeddedartists.com/products/lpc4088-quickstart-board>`__
- `LPCXpresso 1769 <https://www.nxp.com/support/developer-resources/evaluation-and-development-boards/lpcxpresso-boards/lpcxpresso-board-for-lpc1769:OM13000>`__
LPC 18-43
^^^^^^^^^
- `Embedded Artists LPC4357 Developer Kit <http://www.embeddedartists.com/products/kits/lpc4357_kit.php>`__
- `Keil MCB1800 Evaluation Board <http://www.keil.com/mcb1800>`__
- `LPCXpresso18S37 Development Board <https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc4000-cortex-m4/lpcxpresso18s37-development-board:OM13076>`__
- `NGX LPC4330-Xplorer <https://www.nxp.com/design/designs/lpc4330-xplorer-board:OM13027>`__
LPC 51
^^^^^^
- `LPCXpresso 51U68 <https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpcxpresso51u68-for-the-lpc51u68-mcus:OM40005>`__
LPC 54
^^^^^^
- `LPCXpresso 54114 <https://www.nxp.com/design/microcontrollers-developer-resources/lpcxpresso-boards/lpcxpresso54114-board:OM13089>`__
LPC55
^^^^^
- `Double M33 Express <https://www.crowdsupply.com/steiert-solutions/double-m33-express>`__
- `LPCXpresso 55s28 EVK <https://www.nxp.com/design/software/development-software/lpcxpresso55s28-development-board:LPC55S28-EVK>`__
- `LPCXpresso 55s69 EVK <https://www.nxp.com/design/development-boards/lpcxpresso-boards/lpcxpresso55s69-development-board:LPC55S69-EVK>`__
- `MCU-Link <https://www.nxp.com/design/development-boards/lpcxpresso-boards/mcu-link-debug-probe:MCU-LINK>`__
Renesas RX
----------
- `GR-CITRUS <https://www.renesas.com/us/en/products/gadget-renesas/boards/gr-citrus>`__
- `Renesas RX65N Target Board <https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rx-32-bit-performance-efficiency-mcus/rtk5rx65n0c00000br-target-board-rx65n>`__
Raspberry Pi RP2040
-------------------
- `Adafruit Feather RP2040 <https://www.adafruit.com/product/4884>`__
- `Adafruit ItsyBitsy RP2040 <https://www.adafruit.com/product/4888>`__
- `Adafruit QT Py RP2040 <https://www.adafruit.com/product/4900>`__
- `Raspberry Pi Pico <https://www.raspberrypi.org/products/raspberry-pi-pico/>`__
Silabs
------
- `EFM32GG12 Thunderboard Kit (SLTB009A) <https://www.silabs.com/development-tools/thunderboard/thunderboard-gg12-kit>`__
Sony
----
- `Sony Spresense CXD5602 <https://developer.sony.com/develop/spresense>`__
ST STM32
--------
F0
^^
- `STM32 F070rb Nucleo <https://www.st.com/en/evaluation-tools/nucleo-f070rb.html>`__
- `STM32 F072 Evaluation <https://www.st.com/en/evaluation-tools/stm32072b-eval.html>`__
- `STM32 F072rb Discovery <https://www.st.com/en/evaluation-tools/32f072bdiscovery.html>`__
F1
^^
- `STM32 F103c8 Blue Pill <https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill>`__
- `STM32 F103rc Mini v2.0 <https://stm32-base.org/boards/STM32F103RCT6-STM32-Mini-V2.0>`__
F2
^^
- `STM32 F207zg Nucleo <https://www.st.com/en/evaluation-tools/nucleo-f207zg.html>`__
F3
^^
- `STM32 F303vc Discovery <https://www.st.com/en/evaluation-tools/stm32f3discovery.html>`__
F4
^^
- `Adafruit Feather STM32F405 <https://www.adafruit.com/product/4382>`__
- `Micro Python PyBoard v1.1 <https://store.micropython.org/product/PYBv1.1>`__
- `STM32 F401cc Black Pill <https://stm32-base.org/boards/STM32F401CCU6-WeAct-Black-Pill-V1.2>`__
- `STM32 F407vg Discovery <https://www.st.com/en/evaluation-tools/stm32f4discovery.html>`__
- `STM32 F411ce Black Pill <https://www.adafruit.com/product/4877>`__
- `STM32 F411ve Discovery <https://www.st.com/en/evaluation-tools/32f411ediscovery.html>`__
- `STM32 F412zg Discovery <https://www.st.com/en/evaluation-tools/32f412gdiscovery.html>`__
- `STM32 F412zg Nucleo <https://www.st.com/en/evaluation-tools/nucleo-f412zg.html>`__
- `STM32 F439zi Nucleo <https://www.st.com/en/evaluation-tools/nucleo-f439zi.html>`__
F7
^^
- `STLink-V3 Mini <https://www.st.com/en/development-tools/stlink-v3mini.html>`__
- `STM32 F723e Discovery <https://www.st.com/en/evaluation-tools/32f723ediscovery.html>`__
- `STM32 F746zg Nucleo <https://www.st.com/en/evaluation-tools/nucleo-f746zg.html>`__
- `STM32 F746g Discovery <https://www.st.com/en/evaluation-tools/32f746gdiscovery.html>`__
- `STM32 F767zi Nucleo <https://www.st.com/en/evaluation-tools/nucleo-f767zi.html>`__
- `STM32 F769i Discovery <https://www.st.com/en/evaluation-tools/32f769idiscovery.html>`__
H7
^^
- `STM32 H743zi Nucleo <https://www.st.com/en/evaluation-tools/nucleo-h743zi.html>`__
- `STM32 H743i Evaluation <https://www.st.com/en/evaluation-tools/stm32h743i-eval.html>`__
- `STM32 H745i Discovery <https://www.st.com/en/evaluation-tools/stm32h745i-disco.html>`__
- `Waveshare OpenH743I-C <https://www.waveshare.com/openh743i-c-standard.htm>`__
G4
^^
- `STM32 G474RE Nucleo <https://www.st.com/en/evaluation-tools/nucleo-g474re.html>`__
L0
^^
- `STM32 L035c8 Discovery <https://www.st.com/en/evaluation-tools/32l0538discovery.html>`__
L4
^^
- `STM32 L476vg Discovery <https://www.st.com/en/evaluation-tools/32l476gdiscovery.html>`__
- `STM32 L4P5zg Nucleo <https://www.st.com/en/evaluation-tools/nucleo-l4p5zg.html>`__
- `STM32 L4R5zi Nucleo <https://www.st.com/en/evaluation-tools/nucleo-l4r5zi.html>`__
WB
^^
- `STM32 WB55 Nucleo <https://www.st.com/en/evaluation-tools/p-nucleo-wb55.html>`__
TI
--
- `MSP430F5529 USB LaunchPad Evaluation Kit <http://www.ti.com/tool/MSP-EXP430F5529LP>`__
- `MSP-EXP432E401Y LaunchPad Evaluation Kit <https://www.ti.com/tool/MSP-EXP432E401Y>`__
- `TM4C123GXL LaunchPad Evaluation Kit <https://www.ti.com/tool/EK-TM4C123GXL>`__
Tomu
----
- `Fomu <https://www.crowdsupply.com/sutajio-kosagi/fomu>`__
WCH
---
- `CH32V307V-R1-1v0 <https://lcsc.com/product-detail/Development-Boards-Kits_WCH-Jiangsu-Qin-Heng-CH32V307V-EVT-R1_C2943980.html>`

@ -0,0 +1,4 @@
sphinx~=3.0
furo>=2020.12.30.b24
sphinx-autodoc-typehints>=1.10
jinja2==3.0.3

@ -0,0 +1,21 @@
# Copy this file to the location of your distribution's udev rules, for example on Ubuntu:
# sudo cp 99-tinyusb.rules /etc/udev/rules.d/
# Then reload udev configuration by executing:
# sudo udevadm control --reload-rules
# sudo udevadm trigger
# Check SUBSYSTEM
SUBSYSTEMS=="hidraw", KERNEL=="hidraw*", MODE="0666", GROUP="dialout"
# Rule applies to all TinyUSB example
ATTRS{idVendor}=="cafe", MODE="0666", GROUP="dialout"
# Rule to blacklist TinyUSB example from being manipulated by ModemManager.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="cafe", ENV{ID_MM_DEVICE_IGNORE}="1"
# Xplained Pro SamG55 Device
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2111", MODE="0666", GROUP="users", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEMS=="tty", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2111", MODE="0666", GROUP="users", ENV{ID_MM_DEVICE_IGNORE}="1"
# TI Stellaris/Tiva-C Launchpad ICDI
SUBSYSTEM=="usb", ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="0666"

@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.5)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
project(tinyusb_device_examples)
family_initialize_project(tinyusb_device_examples ${CMAKE_CURRENT_LIST_DIR})
# family_add_subdirectory will filter what to actually add based on selected FAMILY
family_add_subdirectory(audio_4_channel_mic)
family_add_subdirectory(audio_test)
family_add_subdirectory(board_test)
family_add_subdirectory(cdc_dual_ports)
family_add_subdirectory(cdc_msc)
family_add_subdirectory(cdc_msc_freertos)
family_add_subdirectory(dfu)
family_add_subdirectory(dfu_runtime)
family_add_subdirectory(dynamic_configuration)
family_add_subdirectory(hid_composite)
family_add_subdirectory(hid_composite_freertos)
family_add_subdirectory(hid_generic_inout)
family_add_subdirectory(hid_multiple_interface)
family_add_subdirectory(midi_test)
family_add_subdirectory(msc_dual_lun)
family_add_subdirectory(net_lwip_webserver)
family_add_subdirectory(uac2_headset)
family_add_subdirectory(usbtmc)
family_add_subdirectory(video_capture)
family_add_subdirectory(webusb_serial)

@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.5)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
project(${PROJECT})
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
)
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
family_configure_device_example(${PROJECT})

@ -0,0 +1,12 @@
include ../../../tools/top.mk
include ../../make.mk
INC += \
src \
$(TOP)/hw \
# Example source
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
include ../../rules.mk

@ -0,0 +1,459 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Reinhard Panhuber
*
* 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.
*
*/
/* plot_audio_samples.py requires following modules:
* $ sudo apt install libportaudio
* $ pip3 install sounddevice matplotlib
*
* Then run
* $ python3 plot_audio_samples.py
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "bsp/board.h"
#include "tusb.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
#ifndef AUDIO_SAMPLE_RATE
#define AUDIO_SAMPLE_RATE 48000
#endif
/* Blink pattern
* - 250 ms : device not mounted
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
enum {
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
};
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
// Audio controls
// Current states
bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
uint32_t sampFreq;
uint8_t clkValid;
// Range states
audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Volume range state
audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state
// Audio test data
uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ/2]; // Ensure half word aligned
void led_blinking_task(void);
void audio_task(void);
/*------------- MAIN -------------*/
int main(void)
{
board_init();
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
// Init values
sampFreq = AUDIO_SAMPLE_RATE;
clkValid = 1;
sampleFreqRng.wNumSubRanges = 1;
sampleFreqRng.subrange[0].bMin = AUDIO_SAMPLE_RATE;
sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE;
sampleFreqRng.subrange[0].bRes = 0;
while (1)
{
tud_task(); // tinyusb device task
led_blinking_task();
audio_task();
}
return 0;
}
//--------------------------------------------------------------------+
// Device callbacks
//--------------------------------------------------------------------+
// Invoked when device is mounted
void tud_mount_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
}
// Invoked when device is unmounted
void tud_umount_cb(void)
{
blink_interval_ms = BLINK_NOT_MOUNTED;
}
// Invoked when usb bus is suspended
// remote_wakeup_en : if host allow us to perform remote wakeup
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en)
{
(void) remote_wakeup_en;
blink_interval_ms = BLINK_SUSPENDED;
}
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
}
//--------------------------------------------------------------------+
// AUDIO Task
//--------------------------------------------------------------------+
void audio_task(void)
{
// Yet to be filled - e.g. put meas data into TX FIFOs etc.
// asm("nop");
}
//--------------------------------------------------------------------+
// Application Callback API Implementations
//--------------------------------------------------------------------+
// Invoked when audio class specific set request received for an EP
bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
(void) rhport;
(void) pBuff;
// We do not support any set range requests here, only current value requests
TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t ep = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) ep;
return false; // Yet not implemented
}
// Invoked when audio class specific set request received for an interface
bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
(void) rhport;
(void) pBuff;
// We do not support any set range requests here, only current value requests
TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t itf = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) itf;
return false; // Yet not implemented
}
// Invoked when audio class specific set request received for an entity
bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
(void) rhport;
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t itf = TU_U16_LOW(p_request->wIndex);
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
(void) itf;
// We do not support any set range requests here, only current value requests
TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
// If request is for our feature unit
if ( entityID == 2 )
{
switch ( ctrlSel )
{
case AUDIO_FU_CTRL_MUTE:
// Request uses format layout 1
TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t));
mute[channelNum] = ((audio_control_cur_1_t*) pBuff)->bCur;
TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum);
return true;
case AUDIO_FU_CTRL_VOLUME:
// Request uses format layout 2
TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t));
volume[channelNum] = (uint16_t) ((audio_control_cur_2_t*) pBuff)->bCur;
TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum);
return true;
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
}
return false; // Yet not implemented
}
// Invoked when audio class specific get request received for an EP
bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
(void) rhport;
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t ep = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) ep;
// return tud_control_xfer(rhport, p_request, &tmp, 1);
return false; // Yet not implemented
}
// Invoked when audio class specific get request received for an interface
bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
(void) rhport;
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t itf = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) itf;
return false; // Yet not implemented
}
// Invoked when audio class specific get request received for an entity
bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
(void) rhport;
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
// uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since we have only one audio function implemented, we do not need the itf value
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
// Input terminal (Microphone input)
if (entityID == 1)
{
switch ( ctrlSel )
{
case AUDIO_TE_CTRL_CONNECTOR:
{
// The terminal connector control only has a get request with only the CUR attribute.
audio_desc_channel_cluster_t ret;
// Those are dummy values for now
ret.bNrChannels = 1;
ret.bmChannelConfig = 0;
ret.iChannelNames = 0;
TU_LOG2(" Get terminal connector\r\n");
return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret));
}
break;
// Unknown/Unsupported control selector
default:
TU_BREAKPOINT();
return false;
}
}
// Feature unit
if (entityID == 2)
{
switch ( ctrlSel )
{
case AUDIO_FU_CTRL_MUTE:
// Audio control mute cur parameter block consists of only one byte - we thus can send it right away
// There does not exist a range parameter block for mute
TU_LOG2(" Get Mute of channel: %u\r\n", channelNum);
return tud_control_xfer(rhport, p_request, &mute[channelNum], 1);
case AUDIO_FU_CTRL_VOLUME:
switch ( p_request->bRequest )
{
case AUDIO_CS_REQ_CUR:
TU_LOG2(" Get Volume of channel: %u\r\n", channelNum);
return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum]));
case AUDIO_CS_REQ_RANGE:
TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum);
// Copy values - only for testing - better is version below
audio_control_range_2_n_t(1)
ret;
ret.wNumSubRanges = 1;
ret.subrange[0].bMin = -90; // -90 dB
ret.subrange[0].bMax = 90; // +90 dB
ret.subrange[0].bRes = 1; // 1 dB steps
return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret));
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
break;
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
}
// Clock Source unit
if ( entityID == 4 )
{
switch ( ctrlSel )
{
case AUDIO_CS_CTRL_SAM_FREQ:
// channelNum is always zero in this case
switch ( p_request->bRequest )
{
case AUDIO_CS_REQ_CUR:
TU_LOG2(" Get Sample Freq.\r\n");
return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
case AUDIO_CS_REQ_RANGE:
TU_LOG2(" Get Sample Freq. range\r\n");
return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng));
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
break;
case AUDIO_CS_CTRL_CLK_VALID:
// Only cur attribute exists for this request
TU_LOG2(" Get Sample Freq. valid\r\n");
return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
}
TU_LOG2(" Unsupported entity: %d\r\n", entityID);
return false; // Yet not implemented
}
bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
{
(void) rhport;
(void) itf;
(void) ep_in;
(void) cur_alt_setting;
for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++)
{
tud_audio_write_support_ff(cnt, i2s_dummy_buffer[cnt], AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX);
}
return true;
}
bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
{
(void) rhport;
(void) n_bytes_copied;
(void) itf;
(void) ep_in;
(void) cur_alt_setting;
uint16_t dataVal;
// Generate dummy data
for (uint16_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++)
{
uint16_t * p_buff = i2s_dummy_buffer[cnt]; // 2 bytes per sample
dataVal = 1;
for (uint16_t cnt2 = 0; cnt2 < AUDIO_SAMPLE_RATE/1000; cnt2++)
{
for (uint8_t cnt3 = 0; cnt3 < CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; cnt3++)
{
*p_buff++ = dataVal;
}
dataVal++;
}
}
return true;
}
bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
(void) rhport;
(void) p_request;
return true;
}
//--------------------------------------------------------------------+
// BLINKING TASK
//--------------------------------------------------------------------+
void led_blinking_task(void)
{
static uint32_t start_ms = 0;
static bool led_state = false;
// Blink every interval ms
if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}

@ -0,0 +1,34 @@
import sounddevice as sd
import matplotlib.pyplot as plt
import numpy as np
import platform
if __name__ == '__main__':
# If you got "ValueError: No input device matching", that is because your PC name example device
# differently from tested list below. Uncomment the next line to see full list and try to pick correct one
# print(sd.query_devices())
fs = 48000 # Sample rate
duration = 100e-3 # Duration of recording
if platform.system() == 'Windows':
# WDM-KS is needed since there are more than one MicNode device APIs (at least in Windows)
device = 'Microphone (MicNode_4_Ch), Windows WDM-KS'
elif platform.system() == 'Darwin':
device = 'MicNode_4_Ch'
else:
device ='default'
myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=4, dtype='int16', device=device)
print('Waiting...')
sd.wait() # Wait until recording is finished
print('Done!')
time = np.arange(0, duration, 1 / fs) # time vector
plt.plot(time, myrecording)
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.title('MicNode 4 Channel')
plt.show()

@ -0,0 +1,129 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// Board Specific Configuration
//--------------------------------------------------------------------+
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_TUD_RHPORT
#define BOARD_TUD_RHPORT 0
#endif
// RHPort max operational speed can defined by board.mk
#ifndef BOARD_TUD_MAX_SPEED
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif
// Enable Device stack
#define CFG_TUD_ENABLED 1
// Default is max speed that hardware controller could support with on-chip PHY
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
#define CFG_TUD_AUDIO 1
#define CFG_TUD_CDC 0
#define CFG_TUD_MSC 0
#define CFG_TUD_HID 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
//--------------------------------------------------------------------
// AUDIO CLASS DRIVER CONFIGURATION
//--------------------------------------------------------------------
// Have a look into audio_device.h for all configurations
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_FOUR_CH_DESC_LEN
#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
#define CFG_TUD_AUDIO_EP_SZ_IN (48 + 1) * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x CFG_TUD_AUDIO_N_CHANNELS_TX Channels - the Windows driver always needs an extra sample per channel of space more, otherwise it complains... found by trial and error
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN
#define CFG_TUD_AUDIO_ENABLE_ENCODING 1
#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 1
#define CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX 2 // One I2S stream contains two channels, each stream is saved within one support FIFO - this value is currently fixed, the driver does not support a changing value
#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX)
#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO)
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

@ -0,0 +1,165 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] AUDIO | MIDI | HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) )
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
ITF_NUM_AUDIO_CONTROL = 0,
ITF_NUM_AUDIO_STREAMING,
ITF_NUM_TOTAL
};
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_FOUR_CH_DESC_LEN)
#if TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX)
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_AUDIO 0x03
#elif TU_CHECK_MCU(OPT_MCU_NRF5X)
// nRF5x ISO can only be endpoint 8
#define EPNUM_AUDIO 0x08
#else
#define EPNUM_AUDIO 0x01
#endif
uint8_t const desc_configuration[] =
{
// Interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP Out & EP In address, EP size
TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN)
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
return desc_configuration;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"PaniRCorp", // 1: Manufacturer
"MicNode_4_Ch", // 2: Product
"123458", // 3: Serials, should use chip ID
"UAC2", // 4: Audio Interface
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
uint8_t chr_count;
if ( index == 0)
{
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}else
{
// Convert ASCII string into UTF-16
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > 31 ) chr_count = 31;
for(uint8_t i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}

@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.5)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
project(${PROJECT})
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
)
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
family_configure_device_example(${PROJECT})

@ -0,0 +1,12 @@
include ../../../tools/top.mk
include ../../make.mk
INC += \
src \
$(TOP)/hw \
# Example source
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
include ../../rules.mk

@ -0,0 +1,447 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Reinhard Panhuber
*
* 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.
*
*/
/* plot_audio_samples.py requires following modules:
* $ sudo apt install libportaudio
* $ pip3 install sounddevice matplotlib
*
* Then run
* $ python3 plot_audio_samples.py
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "bsp/board.h"
#include "tusb.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
#ifndef AUDIO_SAMPLE_RATE
#define AUDIO_SAMPLE_RATE 48000
#endif
/* Blink pattern
* - 250 ms : device not mounted
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
enum {
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
};
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
// Audio controls
// Current states
bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
uint32_t sampFreq;
uint8_t clkValid;
// Range states
audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Volume range state
audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state
// Audio test data
uint16_t test_buffer_audio[(CFG_TUD_AUDIO_EP_SZ_IN - 2) / 2];
uint16_t startVal = 0;
void led_blinking_task(void);
void audio_task(void);
/*------------- MAIN -------------*/
int main(void)
{
board_init();
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
// Init values
sampFreq = AUDIO_SAMPLE_RATE;
clkValid = 1;
sampleFreqRng.wNumSubRanges = 1;
sampleFreqRng.subrange[0].bMin = AUDIO_SAMPLE_RATE;
sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE;
sampleFreqRng.subrange[0].bRes = 0;
while (1)
{
tud_task(); // tinyusb device task
led_blinking_task();
audio_task();
}
return 0;
}
//--------------------------------------------------------------------+
// Device callbacks
//--------------------------------------------------------------------+
// Invoked when device is mounted
void tud_mount_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
}
// Invoked when device is unmounted
void tud_umount_cb(void)
{
blink_interval_ms = BLINK_NOT_MOUNTED;
}
// Invoked when usb bus is suspended
// remote_wakeup_en : if host allow us to perform remote wakeup
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en)
{
(void) remote_wakeup_en;
blink_interval_ms = BLINK_SUSPENDED;
}
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
}
//--------------------------------------------------------------------+
// AUDIO Task
//--------------------------------------------------------------------+
void audio_task(void)
{
// Yet to be filled - e.g. put meas data into TX FIFOs etc.
// asm("nop");
}
//--------------------------------------------------------------------+
// Application Callback API Implementations
//--------------------------------------------------------------------+
// Invoked when audio class specific set request received for an EP
bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
(void) rhport;
(void) pBuff;
// We do not support any set range requests here, only current value requests
TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t ep = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) ep;
return false; // Yet not implemented
}
// Invoked when audio class specific set request received for an interface
bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
(void) rhport;
(void) pBuff;
// We do not support any set range requests here, only current value requests
TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t itf = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) itf;
return false; // Yet not implemented
}
// Invoked when audio class specific set request received for an entity
bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
(void) rhport;
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t itf = TU_U16_LOW(p_request->wIndex);
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
(void) itf;
// We do not support any set range requests here, only current value requests
TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
// If request is for our feature unit
if ( entityID == 2 )
{
switch ( ctrlSel )
{
case AUDIO_FU_CTRL_MUTE:
// Request uses format layout 1
TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t));
mute[channelNum] = ((audio_control_cur_1_t*) pBuff)->bCur;
TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum);
return true;
case AUDIO_FU_CTRL_VOLUME:
// Request uses format layout 2
TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t));
volume[channelNum] = (uint16_t) ((audio_control_cur_2_t*) pBuff)->bCur;
TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum);
return true;
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
}
return false; // Yet not implemented
}
// Invoked when audio class specific get request received for an EP
bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
(void) rhport;
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t ep = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) ep;
// return tud_control_xfer(rhport, p_request, &tmp, 1);
return false; // Yet not implemented
}
// Invoked when audio class specific get request received for an interface
bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
(void) rhport;
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t itf = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) itf;
return false; // Yet not implemented
}
// Invoked when audio class specific get request received for an entity
bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
(void) rhport;
// Page 91 in UAC2 specification
uint8_t channelNum = TU_U16_LOW(p_request->wValue);
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
// uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since we have only one audio function implemented, we do not need the itf value
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
// Input terminal (Microphone input)
if (entityID == 1)
{
switch ( ctrlSel )
{
case AUDIO_TE_CTRL_CONNECTOR:
{
// The terminal connector control only has a get request with only the CUR attribute.
audio_desc_channel_cluster_t ret;
// Those are dummy values for now
ret.bNrChannels = 1;
ret.bmChannelConfig = 0;
ret.iChannelNames = 0;
TU_LOG2(" Get terminal connector\r\n");
return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret));
}
break;
// Unknown/Unsupported control selector
default:
TU_BREAKPOINT();
return false;
}
}
// Feature unit
if (entityID == 2)
{
switch ( ctrlSel )
{
case AUDIO_FU_CTRL_MUTE:
// Audio control mute cur parameter block consists of only one byte - we thus can send it right away
// There does not exist a range parameter block for mute
TU_LOG2(" Get Mute of channel: %u\r\n", channelNum);
return tud_control_xfer(rhport, p_request, &mute[channelNum], 1);
case AUDIO_FU_CTRL_VOLUME:
switch ( p_request->bRequest )
{
case AUDIO_CS_REQ_CUR:
TU_LOG2(" Get Volume of channel: %u\r\n", channelNum);
return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum]));
case AUDIO_CS_REQ_RANGE:
TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum);
// Copy values - only for testing - better is version below
audio_control_range_2_n_t(1)
ret;
ret.wNumSubRanges = 1;
ret.subrange[0].bMin = -90; // -90 dB
ret.subrange[0].bMax = 90; // +90 dB
ret.subrange[0].bRes = 1; // 1 dB steps
return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret));
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
break;
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
}
// Clock Source unit
if ( entityID == 4 )
{
switch ( ctrlSel )
{
case AUDIO_CS_CTRL_SAM_FREQ:
// channelNum is always zero in this case
switch ( p_request->bRequest )
{
case AUDIO_CS_REQ_CUR:
TU_LOG2(" Get Sample Freq.\r\n");
return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
case AUDIO_CS_REQ_RANGE:
TU_LOG2(" Get Sample Freq. range\r\n");
return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng));
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
break;
case AUDIO_CS_CTRL_CLK_VALID:
// Only cur attribute exists for this request
TU_LOG2(" Get Sample Freq. valid\r\n");
return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
}
TU_LOG2(" Unsupported entity: %d\r\n", entityID);
return false; // Yet not implemented
}
bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
{
(void) rhport;
(void) itf;
(void) ep_in;
(void) cur_alt_setting;
tud_audio_write ((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_EP_SZ_IN - 2);
return true;
}
bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
{
(void) rhport;
(void) n_bytes_copied;
(void) itf;
(void) ep_in;
(void) cur_alt_setting;
for (size_t cnt = 0; cnt < (CFG_TUD_AUDIO_EP_SZ_IN - 2) / 2; cnt++)
{
test_buffer_audio[cnt] = startVal++;
}
return true;
}
bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
(void) rhport;
(void) p_request;
startVal = 0;
return true;
}
//--------------------------------------------------------------------+
// BLINKING TASK
//--------------------------------------------------------------------+
void led_blinking_task(void)
{
static uint32_t start_ms = 0;
static bool led_state = false;
// Blink every interval ms
if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}

@ -0,0 +1,38 @@
import sounddevice as sd
import matplotlib.pyplot as plt
import numpy as np
import platform
import csv
if __name__ == '__main__':
# If you got "ValueError: No input device matching", that is because your PC name example device
# differently from tested list below. Uncomment the next line to see full list and try to pick correct one
# print(sd.query_devices())
fs = 48000 # Sample rate
duration = 100e-3 # Duration of recording
if platform.system() == 'Windows':
# MME is needed since there are more than one MicNode device APIs (at least in Windows)
device = 'Microphone (MicNode) MME'
elif platform.system() == 'Darwin':
device = 'MicNode'
else:
device ='default'
myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=1, dtype='int16', device=device)
print('Waiting...')
sd.wait() # Wait until recording is finished
print('Done!')
time = np.arange(0, duration, 1 / fs) # time vector
plt.plot(time, myrecording)
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.title('MicNode')
plt.show()
samples = np.array(myrecording)
np.savetxt('Output.csv', samples, delimiter=",", fmt='%s')

@ -0,0 +1,125 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// Board Specific Configuration
//--------------------------------------------------------------------+
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_TUD_RHPORT
#define BOARD_TUD_RHPORT 0
#endif
// RHPort max operational speed can defined by board.mk
#ifndef BOARD_TUD_MAX_SPEED
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif
// Enable Device stack
#define CFG_TUD_ENABLED 1
// Default is max speed that hardware controller could support with on-chip PHY
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
// #define CFG_TUSB_DEBUG 0
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
#define CFG_TUD_AUDIO 1
#define CFG_TUD_CDC 0
#define CFG_TUD_MSC 0
#define CFG_TUD_HID 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
//--------------------------------------------------------------------
// AUDIO CLASS DRIVER CONFIGURATION
//--------------------------------------------------------------------
// Have a look into audio_device.h for all configurations
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN
#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor!
#define CFG_TUD_AUDIO_EP_SZ_IN (48 + 1) * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x CFG_TUD_AUDIO_N_CHANNELS_TX Channels - One extra sample is needed for asynchronous transfer adjustment, see feedback EP
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN // Maximum EP IN size for all AS alternate settings used
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN + 1
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

@ -0,0 +1,165 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] AUDIO | MIDI | HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) )
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
ITF_NUM_AUDIO_CONTROL = 0,
ITF_NUM_AUDIO_STREAMING,
ITF_NUM_TOTAL
};
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_AUDIO 0x03
#elif TU_CHECK_MCU(OPT_MCU_NRF5X)
// nRF5x ISO can only be endpoint 8
#define EPNUM_AUDIO 0x08
#else
#define EPNUM_AUDIO 0x01
#endif
uint8_t const desc_configuration[] =
{
// Interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP Out & EP In address, EP size
TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN)
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
return desc_configuration;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"PaniRCorp", // 1: Manufacturer
"MicNode", // 2: Product
"123456", // 3: Serials, should use chip ID
"UAC2", // 4: Audio Interface
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
uint8_t chr_count;
if ( index == 0)
{
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}else
{
// Convert ASCII string into UTF-16
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > 31 ) chr_count = 31;
for(uint8_t i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}

@ -0,0 +1,42 @@
cmake_minimum_required(VERSION 3.5)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# Check for -DFAMILY=
if(FAMILY MATCHES "^esp32s[2-3]")
# use BOARD-Directory name for project id
get_filename_component(PROJECT ${CMAKE_CURRENT_SOURCE_DIR} NAME)
set(PROJECT ${BOARD}-${PROJECT})
# TOP is absolute path to root directory of TinyUSB git repo
set(TOP "../../..")
get_filename_component(TOP "${TOP}" REALPATH)
project(${PROJECT})
else()
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
project(${PROJECT})
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
)
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
family_configure_device_example(${PROJECT})
endif()

@ -0,0 +1,12 @@
include ../../../tools/top.mk
include ../../make.mk
INC += \
src \
$(TOP)/hw \
# Example source
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
include ../../rules.mk

@ -0,0 +1,3 @@
CONFIG_IDF_CMAKE=y
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y

@ -0,0 +1,17 @@
# FAMILY = esp32sx
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "."
REQUIRES freertos soc)
file(TO_NATIVE_PATH "${TOP}/hw/bsp/${FAMILY}/boards/${BOARD}/board.cmake" board_cmake)
if(EXISTS ${board_cmake})
include(${board_cmake})
endif()
idf_component_get_property( FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH)
target_include_directories(${COMPONENT_TARGET} PUBLIC
"${FREERTOS_ORIG_INCLUDE_PATH}"
"${TOP}/hw"
"${TOP}/src"
)

@ -0,0 +1,86 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "bsp/board.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
/* Blink pattern
* - 250 ms : button is not pressed
* - 1000 ms : button is pressed (and hold)
*/
enum {
BLINK_PRESSED = 250,
BLINK_UNPRESSED = 1000
};
#define HELLO_STR "Hello from TinyUSB\r\n"
int main(void)
{
board_init();
board_led_write(true);
uint32_t start_ms = 0;
bool led_state = false;
while (1)
{
uint32_t interval_ms = board_button_read() ? BLINK_PRESSED : BLINK_UNPRESSED;
// Blink and print every interval ms
if ( !(board_millis() - start_ms < interval_ms) )
{
board_uart_write(HELLO_STR, strlen(HELLO_STR));
start_ms = board_millis();
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}
// echo
uint8_t ch;
if ( board_uart_read(&ch, 1) > 0 )
{
board_uart_write(&ch, 1);
}
}
return 0;
}
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
void app_main(void)
{
main();
}
#endif

@ -0,0 +1,77 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
// board_test example is special example that doesn't enable device or host stack
// This can cause some TinyUSB API missing, this define hack to allow us to fill those API
// to pass the compilation process
#define tud_int_handler(x)
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
// This example only test LED & GPIO, disable both device and host stack
#define CFG_TUD_ENABLED 0
#define CFG_TUH_ENABLED 0
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
// #define CFG_TUSB_DEBUG 0
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.5)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
project(${PROJECT})
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
)
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
family_configure_device_example(${PROJECT})

@ -0,0 +1,12 @@
include ../../../tools/top.mk
include ../../make.mk
INC += \
src \
$(TOP)/hw \
# Example source
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
include ../../rules.mk

@ -0,0 +1,103 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "bsp/board.h"
#include "tusb.h"
//------------- prototypes -------------//
static void cdc_task(void);
/*------------- MAIN -------------*/
int main(void)
{
board_init();
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
while (1)
{
tud_task(); // tinyusb device task
cdc_task();
}
return 0;
}
// echo to either Serial0 or Serial1
// with Serial0 as all lower case, Serial1 as all upper case
static void echo_serial_port(uint8_t itf, uint8_t buf[], uint32_t count)
{
uint8_t const case_diff = 'a' - 'A';
for(uint32_t i=0; i<count; i++)
{
if (itf == 0)
{
// echo back 1st port as lower case
if (isupper(buf[i])) buf[i] += case_diff;
}
else
{
// echo back 2nd port as upper case
if (islower(buf[i])) buf[i] -= case_diff;
}
tud_cdc_n_write_char(itf, buf[i]);
}
tud_cdc_n_write_flush(itf);
}
//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
static void cdc_task(void)
{
uint8_t itf;
for (itf = 0; itf < CFG_TUD_CDC; itf++)
{
// connected() check for DTR bit
// Most but not all terminal client set this when making connection
// if ( tud_cdc_n_connected(itf) )
{
if ( tud_cdc_n_available(itf) )
{
uint8_t buf[64];
uint32_t count = tud_cdc_n_read(itf, buf, sizeof(buf));
// echo back to both serial ports
echo_serial_port(0, buf, count);
echo_serial_port(1, buf, count);
}
}
}
}

@ -0,0 +1,111 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// Board Specific Configuration
//--------------------------------------------------------------------+
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_TUD_RHPORT
#define BOARD_TUD_RHPORT 0
#endif
// RHPort max operational speed can defined by board.mk
#ifndef BOARD_TUD_MAX_SPEED
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by board.mk
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif
// Enable Device stack
#define CFG_TUD_ENABLED 1
// Default is max speed that hardware controller could support with on-chip PHY
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
#define CFG_TUD_CDC 2
#define CFG_TUD_MSC 0
#define CFG_TUD_HID 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
// CDC Endpoint transfer buffer size, more is faster
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

@ -0,0 +1,264 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] MIDI | HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
#define USB_VID 0xCafe
#define USB_BCD 0x0200
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
ITF_NUM_CDC_0 = 0,
ITF_NUM_CDC_0_DATA,
ITF_NUM_CDC_1,
ITF_NUM_CDC_1_DATA,
ITF_NUM_TOTAL
};
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
#define EPNUM_CDC_0_IN 0x82
#define EPNUM_CDC_1_NOTIF 0x84
#define EPNUM_CDC_1_OUT 0x05
#define EPNUM_CDC_1_IN 0x85
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
#define EPNUM_CDC_0_IN 0x83
#define EPNUM_CDC_1_NOTIF 0x84
#define EPNUM_CDC_1_OUT 0x05
#define EPNUM_CDC_1_IN 0x86
#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X
// FT9XX doesn't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
#define EPNUM_CDC_0_IN 0x83
#define EPNUM_CDC_1_NOTIF 0x84
#define EPNUM_CDC_1_OUT 0x05
#define EPNUM_CDC_1_IN 0x86
#else
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
#define EPNUM_CDC_0_IN 0x82
#define EPNUM_CDC_1_NOTIF 0x83
#define EPNUM_CDC_1_OUT 0x04
#define EPNUM_CDC_1_IN 0x84
#endif
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
};
#if TUD_OPT_HIGH_SPEED
// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
uint8_t const desc_hs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512),
};
// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
tusb_desc_device_qualifier_t const desc_device_qualifier =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.bNumConfigurations = 0x01,
.bReserved = 0x00
};
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
uint8_t const* tud_descriptor_device_qualifier_cb(void)
{
return (uint8_t const*) &desc_device_qualifier;
}
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration;
}
#endif // highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
"123456", // 3: Serials, should use chip ID
"TinyUSB CDC", // 4: CDC Interface
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
uint8_t chr_count;
if ( index == 0)
{
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}else
{
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > 31 ) chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}

@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.5)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
project(${PROJECT})
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
)
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
family_configure_device_example(${PROJECT})

@ -0,0 +1,12 @@
include ../../../tools/top.mk
include ../../make.mk
INC += \
src \
$(TOP)/hw \
# Example source
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
include ../../rules.mk

@ -0,0 +1,169 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "bsp/board.h"
#include "tusb.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
/* Blink pattern
* - 250 ms : device not mounted
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
enum
{
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
};
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
void led_blinking_task(void);
void cdc_task(void);
/*------------- MAIN -------------*/
int main(void)
{
board_init();
// init device stack on configured roothub port
tusb_init(BOARD_TUD_RHPORT);
while (1)
{
tud_task(); // tinyusb device task
led_blinking_task();
cdc_task();
}
return 0;
}
//--------------------------------------------------------------------+
// Device callbacks
//--------------------------------------------------------------------+
// Invoked when device is mounted
void tud_mount_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
}
// Invoked when device is unmounted
void tud_umount_cb(void)
{
blink_interval_ms = BLINK_NOT_MOUNTED;
}
// Invoked when usb bus is suspended
// remote_wakeup_en : if host allow us to perform remote wakeup
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en)
{
(void)remote_wakeup_en;
blink_interval_ms = BLINK_SUSPENDED;
}
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
}
//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
void cdc_task(void)
{
// connected() check for DTR bit
// Most but not all terminal client set this when making connection
// if ( tud_cdc_connected() )
{
// connected and there are data available
if (tud_cdc_available())
{
// read data
char buf[64];
uint32_t count = tud_cdc_read(buf, sizeof(buf));
(void)count;
// Echo back
// Note: Skip echo by commenting out write() and write_flush()
// for throughput test e.g
// $ dd if=/dev/zero of=/dev/ttyACM0 count=10000
tud_cdc_write(buf, count);
tud_cdc_write_flush();
}
}
}
// Invoked when cdc when line state changed e.g connected/disconnected
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
{
(void)itf;
(void)rts;
// TODO set some indicator
if (dtr)
{
// Terminal connected
}
else
{
// Terminal disconnected
}
}
// Invoked when CDC interface received data from host
void tud_cdc_rx_cb(uint8_t itf)
{
(void)itf;
}
//--------------------------------------------------------------------+
// BLINKING TASK
//--------------------------------------------------------------------+
void led_blinking_task(void)
{
static uint32_t start_ms = 0;
static bool led_state = false;
// Blink every interval ms
if (board_millis() - start_ms < blink_interval_ms)
return; // not enough time
start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}

@ -0,0 +1,272 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "bsp/board.h"
#include "tusb.h"
#if CFG_TUD_MSC
// whether host does safe-eject
static bool ejected = false;
// Some MCU doesn't have enough 8KB SRAM to store the whole disk
// We will use Flash as read-only disk with board that has
// CFG_EXAMPLE_MSC_READONLY defined
#define README_CONTENTS \
"This is tinyusb's MassStorage Class demo.\r\n\r\n\
If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb"
enum
{
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
DISK_BLOCK_SIZE = 512
};
#ifdef CFG_EXAMPLE_MSC_READONLY
const
#endif
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
{
//------------- Block0: Boot Sector -------------//
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
// sector_per_cluster = 1; reserved_sectors = 1;
// fat_num = 1; fat12_root_entry_num = 16;
// sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
// drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
// filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
// FAT magic code at offset 510-511
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' ,
'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
// Zero up to 2 last bytes of FAT magic code
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
},
//------------- Block1: FAT12 Table -------------//
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
},
//------------- Block2: Root Directory -------------//
{
// first entry is volume label
'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// second entry is readme file
'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
},
//------------- Block3: Readme Content -------------//
README_CONTENTS
};
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{
(void) lun;
const char vid[] = "TinyUSB";
const char pid[] = "Mass Storage";
const char rev[] = "1.0";
memcpy(vendor_id , vid, strlen(vid));
memcpy(product_id , pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun)
{
(void) lun;
// RAM disk is ready until ejected
if (ejected) {
// Additional Sense 3A-00 is NOT_FOUND
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
return false;
}
return true;
}
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{
(void) lun;
*block_count = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
}
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
(void) lun;
(void) power_condition;
if ( load_eject )
{
if (start)
{
// load disk storage
}else
{
// unload disk storage
ejected = true;
}
}
return true;
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
(void) lun;
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
uint8_t const* addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
return (int32_t) bufsize;
}
bool tud_msc_is_writable_cb (uint8_t lun)
{
(void) lun;
#ifdef CFG_EXAMPLE_MSC_READONLY
return false;
#else
return true;
#endif
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
(void) lun;
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
#ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t* addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
#else
(void) lba; (void) offset; (void) buffer;
#endif
return (int32_t) bufsize;
}
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
// read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL;
int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
switch (scsi_cmd[0])
{
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
}
// return resplen must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize;
if ( response && (resplen > 0) )
{
if(in_xfer)
{
memcpy(buffer, response, (size_t) resplen);
}else
{
// SCSI output
}
}
return (int32_t) resplen;
}
#endif

@ -0,0 +1,114 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// Board Specific Configuration
//--------------------------------------------------------------------+
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_TUD_RHPORT
#define BOARD_TUD_RHPORT 0
#endif
// RHPort max operational speed can defined by board.mk
#ifndef BOARD_TUD_MAX_SPEED
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
//--------------------------------------------------------------------
// Common Configuration
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif
// Enable Device stack
#define CFG_TUD_ENABLED 1
// Default is max speed that hardware controller could support with on-chip PHY
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
#define CFG_TUD_CDC 1
#define CFG_TUD_MSC 1
#define CFG_TUD_HID 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
// CDC Endpoint transfer buffer size, more is faster
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
// MSC Buffer size of Device Mass storage
#define CFG_TUD_MSC_EP_BUFSIZE 512
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

@ -0,0 +1,288 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
#define USB_VID 0xCafe
#define USB_BCD 0x0200
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_MSC,
ITF_NUM_TOTAL
};
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ...
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_MSC_OUT 0x05
#define EPNUM_MSC_IN 0x85
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x83
#define EPNUM_MSC_OUT 0x04
#define EPNUM_MSC_IN 0x85
#elif CFG_TUSB_MCU == OPT_MCU_CXD56
// CXD56 doesn't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
// CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number
// 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN)
#define EPNUM_CDC_NOTIF 0x83
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x81
#define EPNUM_MSC_OUT 0x05
#define EPNUM_MSC_IN 0x84
#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X
// FT9XX doesn't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x83
#define EPNUM_MSC_OUT 0x04
#define EPNUM_MSC_IN 0x85
#else
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_MSC_OUT 0x03
#define EPNUM_MSC_IN 0x83
#endif
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
// full speed configuration
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
};
#if TUD_OPT_HIGH_SPEED
// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
// high speed configuration
uint8_t const desc_hs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
};
// other speed configuration
uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
tusb_desc_device_qualifier_t const desc_device_qualifier =
{
.bLength = sizeof(tusb_desc_device_qualifier_t),
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
.bcdUSB = USB_BCD,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.bNumConfigurations = 0x01,
.bReserved = 0x00
};
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
uint8_t const* tud_descriptor_device_qualifier_cb(void)
{
return (uint8_t const*) &desc_device_qualifier;
}
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
// Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
CONFIG_TOTAL_LEN);
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
return desc_other_speed_config;
}
#endif // highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
"123456789012", // 3: Serials, should use chip ID
"TinyUSB CDC", // 4: CDC Interface
"TinyUSB MSC", // 5: MSC Interface
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
uint8_t chr_count;
if ( index == 0)
{
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}else
{
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > 31 ) chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.5)
# TOP is absolute path to root directory of TinyUSB git repo
# needed for esp32sx build. TODO could be removed later on
set(TOP "../../..")
get_filename_component(TOP "${TOP}" REALPATH)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
project(${PROJECT})
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
# Check for -DFAMILY=
if(FAMILY MATCHES "^esp32s[2-3]")
else()
message(FATAL_ERROR "Invalid FAMILY specified: ${FAMILY}")
endif()

@ -0,0 +1,49 @@
DEPS_SUBMODULES += lib/FreeRTOS-Kernel
include ../../../tools/top.mk
include ../../make.mk
FREERTOS_SRC = lib/FreeRTOS-Kernel
FREERTOS_PORTABLE_SRC= $(FREERTOS_SRC)/portable/$(if $(USE_IAR),IAR,GCC)/$(FREERTOS_PORT)
INC += \
src \
src/FreeRTOSConfig \
$(TOP)/hw \
$(TOP)/$(FREERTOS_SRC)/include \
$(TOP)/$(FREERTOS_PORTABLE_SRC)
# Example source
EXAMPLE_SOURCE = \
src/freertos_hook.c \
src/main.c \
src/msc_disk.c \
src/usb_descriptors.c
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
# FreeRTOS source, all files in port folder
SRC_C += \
$(FREERTOS_SRC)/list.c \
$(FREERTOS_SRC)/queue.c \
$(FREERTOS_SRC)/tasks.c \
$(FREERTOS_SRC)/timers.c \
$(subst ../../../,,$(wildcard ../../../$(FREERTOS_PORTABLE_SRC)/*.c))
SRC_S += \
$(subst ../../../,,$(wildcard ../../../$(FREERTOS_PORTABLE_SRC)/*.s))
# include heap manage if configSUPPORT_DYNAMIC_ALLOCATION = 1
# SRC_C += $(FREERTOS_SRC)/portable/MemMang/heap_1.c
# CFLAGS += -Wno-error=sign-compare
# Suppress FreeRTOSConfig.h warnings
GCC_CFLAGS += -Wno-error=redundant-decls
# Suppress FreeRTOS source warnings
GCC_CFLAGS += -Wno-error=cast-qual
# FreeRTOS (lto + Os) linker issue
LDFLAGS += -Wl,--undefined=vTaskSwitchContext
include ../../rules.mk

@ -0,0 +1,3 @@
CONFIG_IDF_CMAKE=y
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y

@ -0,0 +1,12 @@
mcu:CH32V307
mcu:CXD56
mcu:F1C100S
mcu:GD32VF103
mcu:MKL25ZXX
mcu:MSP430x5xx
mcu:RP2040
mcu:SAMD11
mcu:SAMX7X
mcu:VALENTYUSB_EPTRI
family:broadcom_32bit
family:broadcom_64bit

@ -0,0 +1,35 @@
idf_component_register(SRCS "main.c" "usb_descriptors.c" "msc_disk.c"
INCLUDE_DIRS "."
REQUIRES freertos soc)
file(TO_NATIVE_PATH "${TOP}/hw/bsp/${FAMILY}/boards/${BOARD}/board.cmake" board_cmake)
if(EXISTS ${board_cmake})
include(${board_cmake})
endif()
target_include_directories(${COMPONENT_TARGET} PUBLIC
"${TOP}/hw"
"${TOP}/src"
)
target_compile_definitions(${COMPONENT_TARGET} PUBLIC
ESP_PLATFORM
)
target_sources(${COMPONENT_TARGET} PUBLIC
"${TOP}/src/tusb.c"
"${TOP}/src/common/tusb_fifo.c"
"${TOP}/src/device/usbd.c"
"${TOP}/src/device/usbd_control.c"
"${TOP}/src/class/cdc/cdc_device.c"
"${TOP}/src/class/dfu/dfu_rt_device.c"
"${TOP}/src/class/hid/hid_device.c"
"${TOP}/src/class/midi/midi_device.c"
"${TOP}/src/class/msc/msc_device.c"
"${TOP}/src/class/net/ecm_rndis_device.c"
"${TOP}/src/class/net/ncm_device.c"
"${TOP}/src/class/usbtmc/usbtmc_device.c"
"${TOP}/src/class/vendor/vendor_device.c"
"${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c"
)

@ -0,0 +1,206 @@
/*
* FreeRTOS Kernel V10.0.0
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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. If you wish to use our Amazon
* FreeRTOS name, please do so in a fair use way that does not cause confusion.
*
* 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.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
// skip if included from IAR assembler
#ifndef __IASMARM__
// Include MCU header
#include "bsp/board_mcu.h"
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
#error "ESP32-Sx should use IDF's FreeRTOSConfig.h"
#endif
// TODO fix later
#if CFG_TUSB_MCU == OPT_MCU_MM32F327X
extern u32 SystemCoreClock;
#else
// FIXME cause redundant-decls warnings
extern uint32_t SystemCoreClock;
#endif
#endif
/* Cortex M23/M33 port configuration. */
#define configENABLE_MPU 0
#define configENABLE_FPU 1
#define configENABLE_TRUSTZONE 0
#define configMINIMAL_SECURE_STACK_SIZE ( 1024 )
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#define configCPU_CLOCK_HZ SystemCoreClock
#define configTICK_RATE_HZ ( 1000 )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( 128 )
#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
#define configMAX_TASK_NAME_LEN 16
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 2
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 0
/* Hook function related definitions. */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning
#define configCHECK_FOR_STACK_OVERFLOW 2
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1 // legacy trace
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 2
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2)
#define configTIMER_QUEUE_LENGTH 32
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
/* Optional functions - most linkers will remove unused functions anyway. */
#define INCLUDE_vTaskPrioritySet 0
#define INCLUDE_uxTaskPriorityGet 0
#define INCLUDE_vTaskDelete 0
#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY
#define INCLUDE_xResumeFromISR 0
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 0
#define INCLUDE_xTaskGetCurrentTaskHandle 0
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#define INCLUDE_xTaskGetIdleTaskHandle 0
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
#define INCLUDE_pcTaskGetTaskName 0
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xEventGroupSetBitFromISR 0
#define INCLUDE_xTimerPendFunctionCall 0
/* Define to trap errors during development. */
// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
#define configASSERT(_exp) \
do {\
if ( !(_exp) ) { \
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
if ( (*ARM_CM_DHCSR) & 1UL ) { /* Only halt mcu if debugger is attached */ \
taskDISABLE_INTERRUPTS(); \
__asm("BKPT #0\n"); \
}\
}\
} while(0)
#else
#define configASSERT( x )
#endif
#ifdef __RX__
/* Renesas RX series */
#define vSoftwareInterruptISR INT_Excep_ICU_SWINT
#define vTickISR INT_Excep_CMT0_CMI0
#define configPERIPHERAL_CLOCK_HZ (configCPU_CLOCK_HZ/2)
#define configKERNEL_INTERRUPT_PRIORITY 1
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 4
#else
/* FreeRTOS hooks to NVIC vectors */
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
#define vPortSVCHandler SVC_Handler
//--------------------------------------------------------------------+
// Interrupt nesting behavior configuration.
//--------------------------------------------------------------------+
#if defined(__NVIC_PRIO_BITS)
// For Cortex-M specific: __NVIC_PRIO_BITS is defined in core_cmx.h
#define configPRIO_BITS __NVIC_PRIO_BITS
#elif defined(__ECLIC_INTCTLBITS)
// RISC-V Bumblebee core from nuclei
#define configPRIO_BITS __ECLIC_INTCTLBITS
#elif defined(__IASMARM__)
// FIXME: IAR Assembler cannot include mcu header directly to get __NVIC_PRIO_BITS.
// Therefore we will hard coded it to minimum value of 2 to get pass ci build.
// IAR user must update this to correct value of the target MCU
#message "configPRIO_BITS is hard coded to 2 to pass IAR build only. User should update it per MCU"
#define configPRIO_BITS 2
#else
#error "FreeRTOS configPRIO_BITS to be defined"
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<<configPRIO_BITS) - 1)
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#endif
#endif /* __FREERTOS_CONFIG__H */

@ -0,0 +1,114 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "FreeRTOS.h"
#include "task.h"
#include "common/tusb_common.h"
void vApplicationMallocFailedHook(void)
{
taskDISABLE_INTERRUPTS();
TU_ASSERT(false, );
}
void vApplicationStackOverflowHook(xTaskHandle pxTask, char *pcTaskName)
{
(void) pxTask;
(void) pcTaskName;
taskDISABLE_INTERRUPTS();
TU_ASSERT(false, );
}
/* configSUPPORT_STATIC_ALLOCATION is set to 1, so the application must provide an
* implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
* used by the Idle task. */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
/* If the buffers to be provided to the Idle task are declared inside this
* function then they must be declared static - otherwise they will be allocated on
* the stack and so not exists after this function exits. */
static StaticTask_t xIdleTaskTCB;
static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
/* Pass out a pointer to the StaticTask_t structure in which the Idle task's
state will be stored. */
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
/* Pass out the array that will be used as the Idle task's stack. */
*ppxIdleTaskStackBuffer = uxIdleTaskStack;
/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
Note that, as the array is necessarily of type StackType_t,
configMINIMAL_STACK_SIZE is specified in words, not bytes. */
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
/* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
* application must provide an implementation of vApplicationGetTimerTaskMemory()
* to provide the memory that is used by the Timer service task. */
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize )
{
/* If the buffers to be provided to the Timer task are declared inside this
* function then they must be declared static - otherwise they will be allocated on
* the stack and so not exists after this function exits. */
static StaticTask_t xTimerTaskTCB;
static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
/* Pass out a pointer to the StaticTask_t structure in which the Timer
task's state will be stored. */
*ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
/* Pass out the array that will be used as the Timer task's stack. */
*ppxTimerTaskStackBuffer = uxTimerTaskStack;
/* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
Note that, as the array is necessarily of type StackType_t,
configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X
#include "iodefine.h"
void vApplicationSetupTimerInterrupt(void)
{
/* Enable CMT0 */
SYSTEM.PRCR.WORD = (0xA5u<<8) | TU_BIT(1);
MSTP(CMT0) = 0;
SYSTEM.PRCR.WORD = (0xA5u<<8);
CMT0.CMCNT = 0;
CMT0.CMCOR = (unsigned short)(((configPERIPHERAL_CLOCK_HZ/configTICK_RATE_HZ)-1)/128);
CMT0.CMCR.WORD = TU_BIT(6) | 2;
IR(CMT0, CMI0) = 0;
IPR(CMT0, CMI0) = configKERNEL_INTERRUPT_PRIORITY;
IEN(CMT0, CMI0) = 1;
CMT.CMSTR0.BIT.STR0 = 1;
}
#endif

@ -0,0 +1,251 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "bsp/board.h"
#include "tusb.h"
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#define USBD_STACK_SIZE 4096
#else
#include "FreeRTOS.h"
#include "semphr.h"
#include "queue.h"
#include "task.h"
#include "timers.h"
// Increase stack size when debug log is enabled
#define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1)
#endif
#define CDC_STACK_SZIE configMINIMAL_STACK_SIZE
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
/* Blink pattern
* - 250 ms : device not mounted
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
enum {
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
};
// static timer & task
#if configSUPPORT_STATIC_ALLOCATION
StaticTimer_t blinky_tmdef;
StackType_t usb_device_stack[USBD_STACK_SIZE];
StaticTask_t usb_device_taskdef;
StackType_t cdc_stack[CDC_STACK_SZIE];
StaticTask_t cdc_taskdef;
#endif
TimerHandle_t blinky_tm;
void led_blinky_cb(TimerHandle_t xTimer);
void usb_device_task(void* param);
void cdc_task(void* params);
//--------------------------------------------------------------------+
// Main
//--------------------------------------------------------------------+
int main(void)
{
board_init();
#if configSUPPORT_STATIC_ALLOCATION
// soft timer for blinky
blinky_tm = xTimerCreateStatic(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb, &blinky_tmdef);
// Create a task for tinyusb device stack
xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef);
// Create CDC task
xTaskCreateStatic(cdc_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES-2, cdc_stack, &cdc_taskdef);
#else
blinky_tm = xTimerCreate(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb);
xTaskCreate( usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, NULL);
xTaskCreate( cdc_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES-2, NULL);
#endif
xTimerStart(blinky_tm, 0);
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
vTaskStartScheduler();
#endif
return 0;
}
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
void app_main(void)
{
main();
}
#endif
// USB Device Driver task
// This top level thread process all usb events and invoke callbacks
void usb_device_task(void* param)
{
(void) param;
// init device stack on configured roothub port
// This should be called after scheduler/kernel is started.
// Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API.
tud_init(BOARD_TUD_RHPORT);
// RTOS forever loop
while (1)
{
// put this thread to waiting state until there is new events
tud_task();
// following code only run if tud_task() process at least 1 event
tud_cdc_write_flush();
}
}
//--------------------------------------------------------------------+
// Device callbacks
//--------------------------------------------------------------------+
// Invoked when device is mounted
void tud_mount_cb(void)
{
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
}
// Invoked when device is unmounted
void tud_umount_cb(void)
{
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0);
}
// Invoked when usb bus is suspended
// remote_wakeup_en : if host allow us to perform remote wakeup
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en)
{
(void) remote_wakeup_en;
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_SUSPENDED), 0);
}
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
}
//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
void cdc_task(void* params)
{
(void) params;
// RTOS forever loop
while ( 1 )
{
// connected() check for DTR bit
// Most but not all terminal client set this when making connection
// if ( tud_cdc_connected() )
{
// There are data available
while ( tud_cdc_available() )
{
uint8_t buf[64];
// read and echo back
uint32_t count = tud_cdc_read(buf, sizeof(buf));
(void) count;
// Echo back
// Note: Skip echo by commenting out write() and write_flush()
// for throughput test e.g
// $ dd if=/dev/zero of=/dev/ttyACM0 count=10000
tud_cdc_write(buf, count);
}
tud_cdc_write_flush();
}
// For ESP32-Sx this delay is essential to allow idle how to run and reset watchdog
vTaskDelay(1);
}
}
// Invoked when cdc when line state changed e.g connected/disconnected
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
{
(void) itf;
(void) rts;
// TODO set some indicator
if ( dtr )
{
// Terminal connected
}else
{
// Terminal disconnected
}
}
// Invoked when CDC interface received data from host
void tud_cdc_rx_cb(uint8_t itf)
{
(void) itf;
}
//--------------------------------------------------------------------+
// BLINKING TASK
//--------------------------------------------------------------------+
void led_blinky_cb(TimerHandle_t xTimer)
{
(void) xTimer;
static bool led_state = false;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}

@ -0,0 +1,250 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "bsp/board.h"
#include "tusb.h"
#if CFG_TUD_MSC
// Some MCU doesn't have enough 8KB SRAM to store the whole disk
// We will use Flash as read-only disk with board that has
// CFG_EXAMPLE_MSC_READONLY defined
#define README_CONTENTS \
"This is tinyusb's MassStorage Class demo.\r\n\r\n\
If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb"
enum
{
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
DISK_BLOCK_SIZE = 512
};
#ifdef CFG_EXAMPLE_MSC_READONLY
const
#endif
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
{
//------------- Block0: Boot Sector -------------//
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
// sector_per_cluster = 1; reserved_sectors = 1;
// fat_num = 1; fat12_root_entry_num = 16;
// sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
// drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
// filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
// FAT magic code at offset 510-511
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' ,
'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
// Zero up to 2 last bytes of FAT magic code
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
},
//------------- Block1: FAT12 Table -------------//
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
},
//------------- Block2: Root Directory -------------//
{
// first entry is volume label
'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// second entry is readme file
'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
},
//------------- Block3: Readme Content -------------//
README_CONTENTS
};
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{
(void) lun;
const char vid[] = "TinyUSB";
const char pid[] = "Mass Storage";
const char rev[] = "1.0";
memcpy(vendor_id , vid, strlen(vid));
memcpy(product_id , pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun)
{
(void) lun;
return true; // RAM disk is always ready
}
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{
(void) lun;
*block_count = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
}
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
(void) lun;
(void) power_condition;
if ( load_eject )
{
if (start)
{
// load disk storage
}else
{
// unload disk storage
}
}
return true;
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
(void) lun;
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
uint8_t const* addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
return bufsize;
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
(void) lun;
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
#ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t* addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
#else
(void) lba; (void) offset; (void) buffer;
#endif
return bufsize;
}
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
// read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL;
int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
switch (scsi_cmd[0])
{
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
}
// return resplen must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize;
if ( response && (resplen > 0) )
{
if(in_xfer)
{
memcpy(buffer, response, resplen);
}else
{
// SCSI output
}
}
return resplen;
}
#endif

@ -0,0 +1,119 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// Board Specific Configuration
//--------------------------------------------------------------------+
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_TUD_RHPORT
#define BOARD_TUD_RHPORT 0
#endif
// RHPort max operational speed can defined by board.mk
#ifndef BOARD_TUD_MAX_SPEED
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by board.mk
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
// This examples use FreeRTOS
#define CFG_TUSB_OS OPT_OS_FREERTOS
// Espressif IDF requires "freertos/" prefix in include path
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
// can be defined by compiler in DEBUG build
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif
// Enable Device stack
#define CFG_TUD_ENABLED 1
// Default is max speed that hardware controller could support with on-chip PHY
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
#define CFG_TUD_CDC 1
#define CFG_TUD_MSC 1
#define CFG_TUD_HID 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
// CDC Endpoint transfer buffer size, more is faster
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
// MSC Buffer size of Device Mass storage
#define CFG_TUD_MSC_EP_BUFSIZE 512
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

@ -0,0 +1,264 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
#define USB_VID 0xCafe
#define USB_BCD 0x0200
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_MSC,
ITF_NUM_TOTAL
};
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ...
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_MSC_OUT 0x05
#define EPNUM_MSC_IN 0x85
#elif CFG_TUSB_MCU == OPT_MCU_SAMG
// SAMG doesn't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x83
#define EPNUM_MSC_OUT 0x04
#define EPNUM_MSC_IN 0x85
#else
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define EPNUM_MSC_OUT 0x03
#define EPNUM_MSC_IN 0x83
#endif
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
};
#if TUD_OPT_HIGH_SPEED
// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
// high speed configuration
uint8_t const desc_hs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
};
// other speed configuration
uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
tusb_desc_device_qualifier_t const desc_device_qualifier =
{
.bLength = sizeof(tusb_desc_device_qualifier_t),
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
.bcdUSB = USB_BCD,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.bNumConfigurations = 0x01,
.bReserved = 0x00
};
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
uint8_t const* tud_descriptor_device_qualifier_cb(void)
{
return (uint8_t const*) &desc_device_qualifier;
}
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
// Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
CONFIG_TOTAL_LEN);
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
return desc_other_speed_config;
}
#endif // highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
"123456789012", // 3: Serials, should use chip ID
"TinyUSB CDC", // 4: CDC Interface
"TinyUSB MSC", // 5: MSC Interface
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
uint8_t chr_count;
if ( index == 0)
{
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}else
{
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > 31 ) chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}

@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.5)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
project(${PROJECT})
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
)
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
family_configure_device_example(${PROJECT})

@ -0,0 +1,15 @@
include ../../../tools/top.mk
include ../../make.mk
INC += \
src \
$(TOP)/hw \
# Example source
EXAMPLE_SOURCE = \
src/main.c \
src/usb_descriptors.c
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
include ../../rules.mk

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save