Merge remote-tracking branch 'upstream/master' into edpt_ISO_xfer

Conflicts:
	src/common/tusb_fifo.h
	src/osal/osal_none.h
This commit is contained in:
Reinhard Panhuber 2021-02-23 19:47:57 +01:00
commit e223d46033
58 changed files with 1247 additions and 3543 deletions

View File

@ -47,6 +47,9 @@
- Board support for NuTiny NUC120, NUC121s, NUC125s, NUC126V, NUC505
- Improve multiple cdc interfaces API & add cdc_dual_ports example
- **[Raspberry Pi Team](https://github.com/raspberrypi)**
- Add new DCD port for **Raspberry Pi RP2040**
- **[Reinhard Panhuber](https://github.com/PanRe)**
- Add new class driver for **USB Audio Class 2.0 (UAC2)**
- Enhance tu_fifo with unmasked pointer, which better support DMA

View File

@ -41,6 +41,7 @@ This code base already had supported for a handful of following boards (sorted a
- [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)
### MicroChip SAMG

View File

@ -165,6 +165,9 @@ void midi_task(void)
{
static uint32_t start_ms = 0;
uint8_t const cable_num = 0; // MIDI jack associated with USB endpoint
uint8_t const channel = 0; // 0 for channel 1
// The MIDI interface always creates input and output port/jack descriptors
// regardless of these being used or not. Therefore incoming traffic should be read
// (possibly just discarded) to avoid the sender blocking in IO
@ -183,10 +186,10 @@ void midi_task(void)
if (previous < 0) previous = sizeof(note_sequence) - 1;
// Send Note On for current position at full velocity (127) on channel 1.
tudi_midi_write24(0, 0x90, note_sequence[note_pos], 127);
tud_midi_write24(cable_num, 0x90 | channel, note_sequence[note_pos], 127);
// Send Note Off for previous note.
tudi_midi_write24(0, 0x80, note_sequence[previous], 0);
tud_midi_write24(cable_num, 0x80 | channel, note_sequence[previous], 0);
// Increment position
note_pos++;

View File

@ -125,6 +125,9 @@ void midi_task(void)
{
static uint32_t start_ms = 0;
uint8_t const cable_num = 0; // MIDI jack associated with USB endpoint
uint8_t const channel = 0; // 0 for channel 1
// The MIDI interface always creates input and output port/jack descriptors
// regardless of these being used or not. Therefore incoming traffic should be read
// (possibly just discarded) to avoid the sender blocking in IO
@ -143,10 +146,10 @@ void midi_task(void)
if (previous < 0) previous = sizeof(note_sequence) - 1;
// Send Note On for current position at full velocity (127) on channel 1.
tudi_midi_write24(0, 0x90, note_sequence[note_pos], 127);
tud_midi_write24(cable_num, 0x90 | channel, note_sequence[note_pos], 127);
// Send Note Off for previous note.
tudi_midi_write24(0, 0x80, note_sequence[previous], 0);
tud_midi_write24(cable_num, 0x80 | channel, note_sequence[previous], 0);
// Increment position
note_pos++;

View File

@ -19,9 +19,9 @@ SRC_C += \
src/host/hub.c \
src/host/usbh.c \
src/host/usbh_control.c \
src/host/ehci/ehci.c \
src/host/ohci/ohci.c \
src/portable/nxp/lpc18_43/hcd_lpc18_43.c \
src/portable/ehci/ehci.c \
src/portable/ohci/ohci.c \
src/portable/nxp/transdimension/hcd_transdimension.c \
src/portable/nxp/lpc17_40/hcd_lpc17_40.c
include ../../rules.mk

View File

@ -31,31 +31,6 @@
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
static scsi_inquiry_resp_t inquiry_resp;
static scsi_read_capacity10_resp_t capacity_resp;
uint32_t block_size;
uint32_t block_count;
bool capacity_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
{
(void) dev_addr;
(void) cbw;
if (csw->status != 0)
{
printf("Read Capacity (10) failed\r\n");
return false;
}
// Capacity response field: Block size and Last LBA are both Big-Endian
block_count = tu_ntohl(capacity_resp.last_lba) + 1;
block_size = tu_ntohl(capacity_resp.block_size);
printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size));
printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size);
return true;
}
bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
{
@ -68,21 +43,23 @@ bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const
// Print out Vendor ID, Product ID and Rev
printf("%.8s %.16s rev %.4s\r\n", inquiry_resp.vendor_id, inquiry_resp.product_id, inquiry_resp.product_rev);
// Read capacity of device
tuh_msc_read_capacity(dev_addr, cbw->lun, &capacity_resp, capacity_complete_cb);
// Get capacity of device
uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun);
uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun);
printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size));
printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size);
return true;
}
//------------- IMPLEMENTATION -------------//
void tuh_msc_mounted_cb(uint8_t dev_addr)
void tuh_msc_mount_cb(uint8_t dev_addr)
{
printf("A MassStorage device is mounted\r\n");
block_size = block_count = 0;
uint8_t const lun = 0;
tuh_msc_scsi_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb);
tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb);
//
// //------------- file system (only 1 LUN support) -------------//
// uint8_t phy_disk = dev_addr-1;
@ -96,13 +73,6 @@ void tuh_msc_mounted_cb(uint8_t dev_addr)
// return;
// }
//
// puts("---------------------------------------------------------------------");
// puts("- MASSSTORAGE CLASS CLI IS A IMMATURE CODE. DISK-WRITING COMMANDS");
// puts("- SUCH AS cp(COPY), mkdir(MAKE DIRECTORY) ARE POTENTIAL TO DAMAGE");
// puts("- YOUR USB THUMBDRIVE. USING THOSE COMMANDS ARE AT YOUR OWN RISK.");
// puts("- THE AUTHOR HAS NO RESPONSIBILITY WITH YOUR DEVICE NOR ITS DATA");
// puts("---------------------------------------------------------------------");
//
// f_chdrive(phy_disk); // change to newly mounted drive
// f_chdir("/"); // root as current dir
//
@ -110,7 +80,7 @@ void tuh_msc_mounted_cb(uint8_t dev_addr)
// }
}
void tuh_msc_unmounted_cb(uint8_t dev_addr)
void tuh_msc_unmount_cb(uint8_t dev_addr)
{
(void) dev_addr;
printf("A MassStorage device is unmounted\r\n");
@ -133,11 +103,4 @@ void tuh_msc_unmounted_cb(uint8_t dev_addr)
// }
}
//void tuh_msc_scsi_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
//{
// (void) dev_addr;
// (void) cbw;
// (void) csw;
//}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,129 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>host_os_none</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
<dictionary>
<key>?name?</key>
<value></value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.append_environment</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
<value>all</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildArguments</key>
<value></value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildCommand</key>
<value>make</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildLocation</key>
<value>${workspace_loc:/host/Debug}</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
<value>clean</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.contents</key>
<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
<value>false</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableFullBuild</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
<value>all</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.stopOnError</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
<value>true</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
<linkedResources>
<link>
<name>boards</name>
<type>2</type>
<locationURI>PARENT-3-PROJECT_LOC/boards</locationURI>
</link>
<link>
<name>fatfs</name>
<type>2</type>
<locationURI>PARENT-3-PROJECT_LOC/vendor/fatfs</locationURI>
</link>
<link>
<name>mcu</name>
<type>2</type>
<locationURI>PARENT-3-PROJECT_LOC/mcu</locationURI>
</link>
<link>
<name>src</name>
<type>2</type>
<locationURI>PARENT-1-PROJECT_LOC/src</locationURI>
</link>
<link>
<name>tinyusb</name>
<type>2</type>
<locationURI>PARENT-3-PROJECT_LOC/tinyusb</locationURI>
</link>
</linkedResources>
<filteredResources>
<filter>
<id>1394685086167</id>
<name>mcu</name>
<type>26</type>
<matcher>
<id>org.eclipse.ui.ide.multiFilter</id>
<arguments>1.0-name-matches-false-false-iar</arguments>
</matcher>
</filter>
<filter>
<id>1394685086182</id>
<name>mcu</name>
<type>26</type>
<matcher>
<id>org.eclipse.ui.ide.multiFilter</id>
<arguments>1.0-name-matches-false-false-keil</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

View File

@ -1,70 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
/** \ingroup TBD
* \defgroup TBD
* \brief TBD
*
* @{
*/
#ifndef _TUSB_APP_OS_PRIO_H_
#define _TUSB_APP_OS_PRIO_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "tusb.h"
#if CFG_TUSB_OS == OPT_OS_NONE
#define LOWER_PRIO(x) 0 // does not matter
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
#define LOWER_PRIO(x) ((x)-1) // freeRTOS lower number --> lower priority
#elif CFG_TUSB_OS == TUSB_OS_CMSIS_RTX
#define LOWER_PRIO(x) ((x)-1) // CMSIS-RTOS lower number --> lower priority
#else
#error Priority is not configured for this RTOS
#endif
enum {
STANDARD_APP_TASK_PRIO = LOWER_PRIO(CFG_TUD_TASK_PRIO), // Application Task is lower than usb system task
LED_BLINKING_APP_TASK_PRIO = LOWER_PRIO(STANDARD_APP_TASK_PRIO), // Blinking task is lower than normal task
KEYBOARD_APP_TASK_PRIO = STANDARD_APP_TASK_PRIO,
MOUSE_APP_TASK_PRIO = STANDARD_APP_TASK_PRIO,
CDC_SERIAL_APP_TASK_PRIO = STANDARD_APP_TASK_PRIO,
MSC_APP_TASK_PRIO = STANDARD_APP_TASK_PRIO
};
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_APP_OS_PRIO_H_ */
/** @} */

View File

@ -1,157 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
#include "cdc_serial_host_app.h"
#include "app_os_prio.h"
#if CFG_TUH_CDC
#define QUEUE_SERIAL_DEPTH 100
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
static osal_semaphore_t sem_hdl;
enum { SERIAL_BUFFER_SIZE = 64 };
CFG_TUSB_MEM_SECTION static uint8_t serial_in_buffer[SERIAL_BUFFER_SIZE];
CFG_TUSB_MEM_SECTION static uint8_t serial_out_buffer[SERIAL_BUFFER_SIZE];
static uint8_t received_bytes; // set by transfer complete callback
//--------------------------------------------------------------------+
// tinyusb callbacks
//--------------------------------------------------------------------+
void tuh_cdc_mounted_cb(uint8_t dev_addr)
{ // application set-up
printf("\na CDC device (address %d) is mounted\n", dev_addr);
tu_memclr(serial_in_buffer, sizeof(serial_in_buffer));
tu_memclr(serial_out_buffer, sizeof(serial_out_buffer));
received_bytes = 0;
osal_semaphore_reset(sem_hdl);
tuh_cdc_receive(dev_addr, serial_in_buffer, SERIAL_BUFFER_SIZE, true); // schedule first transfer
}
void tuh_cdc_unmounted_cb(uint8_t dev_addr)
{ // application tear-down
printf("\na CDC device (address %d) is unmounted \n", dev_addr);
}
// invoked ISR context
void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes)
{
(void) dev_addr; // compiler warnings
switch ( pipe_id )
{
case CDC_PIPE_DATA_IN:
switch(event)
{
case XFER_RESULT_SUCCESS:
received_bytes = xferred_bytes;
osal_semaphore_post(sem_hdl); // notify main task
break;
case XFER_RESULT_FAILED:
received_bytes = 0; // ignore
tuh_cdc_receive(dev_addr, serial_in_buffer, SERIAL_BUFFER_SIZE, true); // waiting for next data
break;
case XFER_RESULT_STALLED:
default :
break;
}
break;
case CDC_PIPE_DATA_OUT:
case CDC_PIPE_NOTIFICATION:
default:
break;
}
}
//--------------------------------------------------------------------+
// APPLICATION
//--------------------------------------------------------------------+
void cdc_serial_host_app_init(void)
{
sem_hdl = osal_semaphore_create(1, 0);
TU_ASSERT( sem_hdl, VOID_RETURN);
TU_VERIFY( osal_task_create(cdc_serial_host_app_task, "cdc", 128, NULL, CDC_SERIAL_APP_TASK_PRIO), );
}
//------------- main task -------------//
void cdc_serial_host_app_task( void* param )
{
(void) param;
OSAL_TASK_BEGIN
//------------- send characters got from uart terminal to the first CDC device -------------//
for(uint8_t dev_addr=1; dev_addr <= CFG_TUSB_HOST_DEVICE_MAX; dev_addr++)
{
if ( tuh_cdc_serial_is_mounted(dev_addr) )
{
int ch_tx = getchar();
if ( ch_tx > 0 )
{ // USB is much faster than serial, here we assume usb is always complete. There could be some characters missing though
serial_out_buffer[0] = (uint8_t) ch_tx;
if ( !tuh_cdc_is_busy(dev_addr, CDC_PIPE_DATA_OUT) )
{
tuh_cdc_send(dev_addr, serial_out_buffer, 1, false); // no need for callback on serial out pipe
}
}
break; // demo app only communicate with the first CDC-capable device
}
}
//------------- print out received characters -------------//
tusb_error_t error;
osal_semaphore_wait(sem_hdl, 100, &error); // waiting for incoming data
if ( TUSB_ERROR_NONE == error)
{
for(uint8_t i=0; i<received_bytes; i++) putchar(serial_in_buffer[i]);
for(uint8_t dev_addr=1; dev_addr <= CFG_TUSB_HOST_DEVICE_MAX; dev_addr++)
{
if ( tuh_cdc_serial_is_mounted(dev_addr) )
{
tuh_cdc_receive(dev_addr, serial_in_buffer, SERIAL_BUFFER_SIZE, true);
break; // demo app only communicate with the first CDC-capable device
}
}
}
OSAL_TASK_END
}
#endif

View File

@ -1,62 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
/** \ingroup TBD
* \defgroup TBD
* \brief TBD
*
* @{
*/
#ifndef _TUSB_CDC_SERIAL_HOST_APP_H_
#define _TUSB_CDC_SERIAL_HOST_APP_H_
#include "board.h"
#include "tusb.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CFG_TUH_CDC
void cdc_serial_host_app_init(void);
void cdc_serial_host_app_task(void* param);
#else
#define cdc_serial_host_app_init()
#define cdc_serial_host_app_task(x)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CDC_SERIAL_HOST_APP_H_ */
/** @} */

View File

@ -1,164 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "keyboard_host_app.h"
#include "app_os_prio.h"
#if CFG_TUH_HID_KEYBOARD
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
#define QUEUE_KEYBOARD_REPORT_DEPTH 4
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
static osal_queue_t queue_kbd_hdl;
CFG_TUSB_MEM_SECTION static hid_keyboard_report_t usb_keyboard_report;
static inline uint8_t keycode_to_ascii(uint8_t modifier, uint8_t keycode);
static inline void process_kbd_report(hid_keyboard_report_t const * report);
//--------------------------------------------------------------------+
// tinyusb callbacks
//--------------------------------------------------------------------+
void tuh_hid_keyboard_mounted_cb(uint8_t dev_addr)
{
// application set-up
printf("\na Keyboard device (address %d) is mounted\n", dev_addr);
osal_queue_flush(queue_kbd_hdl);
tuh_hid_keyboard_get_report(dev_addr, (uint8_t*) &usb_keyboard_report); // first report
}
void tuh_hid_keyboard_unmounted_cb(uint8_t dev_addr)
{
// application tear-down
printf("\na Keyboard device (address %d) is unmounted\n", dev_addr);
}
// invoked ISR context
void tuh_hid_keyboard_isr(uint8_t dev_addr, xfer_result_t event)
{
switch(event)
{
case XFER_RESULT_SUCCESS:
osal_queue_send(queue_kbd_hdl, &usb_keyboard_report);
tuh_hid_keyboard_get_report(dev_addr, (uint8_t*) &usb_keyboard_report);
break;
case XFER_RESULT_FAILED:
tuh_hid_keyboard_get_report(dev_addr, (uint8_t*) &usb_keyboard_report); // ignore & continue
break;
default :
break;
}
}
//--------------------------------------------------------------------+
// APPLICATION
//--------------------------------------------------------------------+
void keyboard_host_app_init(void)
{
tu_memclr(&usb_keyboard_report, sizeof(hid_keyboard_report_t));
queue_kbd_hdl = osal_queue_create( QUEUE_KEYBOARD_REPORT_DEPTH, sizeof(hid_keyboard_report_t) );
TU_ASSERT( queue_kbd_hdl, VOID_RETURN );
TU_VERIFY( osal_task_create(keyboard_host_app_task, "kbd", 128, NULL, KEYBOARD_APP_TASK_PRIO), );
}
//------------- main task -------------//
void keyboard_host_app_task(void* param)
{
(void) param;
OSAL_TASK_BEGIN
hid_keyboard_report_t kbd_report;
tusb_error_t error;
osal_queue_receive(queue_kbd_hdl, &kbd_report, OSAL_TIMEOUT_WAIT_FOREVER, &error);
(void) error; // suppress compiler warning
process_kbd_report(&kbd_report);
OSAL_TASK_END
}
//--------------------------------------------------------------------+
// HELPER
//--------------------------------------------------------------------+
// look up new key in previous keys
static inline bool find_key_in_report(hid_keyboard_report_t const *p_report, uint8_t keycode)
{
for(uint8_t i=0; i<6; i++)
{
if (p_report->keycode[i] == keycode) return true;
}
return false;
}
static inline void process_kbd_report(hid_keyboard_report_t const *p_new_report)
{
static hid_keyboard_report_t prev_report = { 0, 0, {0} }; // previous report to check key released
//------------- example code ignore control (non-printable) key affects -------------//
for(uint8_t i=0; i<6; i++)
{
if ( p_new_report->keycode[i] )
{
if ( find_key_in_report(&prev_report, p_new_report->keycode[i]) )
{
// exist in previous report means the current key is holding
}else
{
// not existed in previous report means the current key is pressed
uint8_t ch = keycode_to_ascii(p_new_report->modifier, p_new_report->keycode[i]);
putchar(ch);
if ( ch == '\r' ) putchar('\n'); // added new line for enter key
}
}
// TODO example skips key released
}
prev_report = *p_new_report;
}
static inline uint8_t keycode_to_ascii(uint8_t modifier, uint8_t keycode)
{
// TODO max of keycode_ascii_tbl
return keycode > 128 ? 0 :
hid_keycode_to_ascii_tbl [modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT) ? 1 : 0] [keycode];
}
#endif

View File

@ -1,68 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
/** \file
* \brief TBD
*
* \note TBD
*/
/** \ingroup TBD
* \defgroup TBD
* \brief TBD
*
* @{
*/
#ifndef _TUSB_KEYBOARD_HOST_APP_H_
#define _TUSB_KEYBOARD_HOST_APP_H_
#include "board.h"
#include "tusb.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CFG_TUH_HID_KEYBOARD
void keyboard_host_app_init(void);
void keyboard_host_app_task(void* param);
#else
#define keyboard_host_app_init()
#define keyboard_host_app_task(x)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_KEYBOARD_HOST_APP_H_ */
/** @} */

View File

@ -1,131 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "board.h"
#include "tusb.h"
#include "mouse_host_app.h"
#include "keyboard_host_app.h"
#include "msc_host_app.h"
#include "cdc_serial_host_app.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
void print_greeting(void);
//--------------------------------------------------------------------+
// IMPLEMENTATION
//--------------------------------------------------------------------+
#if CFG_TUSB_OS == OPT_OS_NONE
// like a real RTOS, this function is a main loop invoking each task in application and never return
void os_none_start_scheduler(void)
{
while (1)
{
tusb_task();
led_blinking_task(NULL);
keyboard_host_app_task(NULL);
mouse_host_app_task(NULL);
msc_host_app_task(NULL);
cdc_serial_host_app_task(NULL);
}
}
#endif
int main(void)
{
#if CFG_TUSB_OS == TUSB_OS_CMSIS_RTX
osKernelInitialize(); // CMSIS RTX requires kernel init before any other OS functions
#endif
board_init();
print_greeting();
tusb_init();
//------------- application task init -------------//
led_blinking_init();
keyboard_host_app_init();
mouse_host_app_init();
msc_host_app_init();
cdc_serial_host_app_init();
//------------- start OS scheduler (never return) -------------//
#if CFG_TUSB_OS == OPT_OS_FREERTOS
vTaskStartScheduler();
#elif CFG_TUSB_OS == OPT_OS_NONE
os_none_start_scheduler();
#elif CFG_TUSB_OS == TUSB_OS_CMSIS_RTX
osKernelStart();
#else
#error need to start RTOS schduler
#endif
return 0;
}
//--------------------------------------------------------------------+
// HELPER FUNCTION
//--------------------------------------------------------------------+
void print_greeting(void)
{
char const * const rtos_name[] =
{
[OPT_OS_NONE] = "None",
[OPT_OS_FREERTOS] = "FreeRTOS",
};
puts("\n\
--------------------------------------------------------------------\n\
- Host Demo (a tinyusb example)\n\
- if you find any bugs or get any questions, feel free to file an\n\
- issue at https://github.com/hathach/tinyusb\n\
--------------------------------------------------------------------\n"
);
puts("This HOST demo is configured to support:");
printf(" - RTOS = %s\n", rtos_name[CFG_TUSB_OS]);
if (CFG_TUH_HUB ) puts(" - Hub (1 level only)");
if (CFG_TUH_HID_MOUSE ) puts(" - HID Mouse");
if (CFG_TUH_HID_KEYBOARD ) puts(" - HID Keyboard");
if (CFG_TUH_MSC ) puts(" - Mass Storage");
if (CFG_TUH_CDC ) puts(" - Communication Device Class");
}

View File

@ -1,169 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "mouse_host_app.h"
#include "app_os_prio.h"
#if CFG_TUH_HID_MOUSE
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
#define QUEUE_MOUSE_REPORT_DEPTH 4
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
static osal_queue_t queue_mouse_hdl;
CFG_TUSB_MEM_SECTION static hid_mouse_report_t usb_mouse_report;
static inline void process_mouse_report(hid_mouse_report_t const * p_report);
//--------------------------------------------------------------------+
// tinyusb callbacks
//--------------------------------------------------------------------+
void tuh_hid_mouse_mounted_cb(uint8_t dev_addr)
{
// application set-up
printf("\na Mouse device (address %d) is mounted\n", dev_addr);
osal_queue_flush(queue_mouse_hdl);
(void) tuh_hid_mouse_get_report(dev_addr, (uint8_t*) &usb_mouse_report); // first report
}
void tuh_hid_mouse_unmounted_cb(uint8_t dev_addr)
{
// application tear-down
printf("\na Mouse device (address %d) is unmounted\n", dev_addr);
}
// invoked ISR context
void tuh_hid_mouse_isr(uint8_t dev_addr, xfer_result_t event)
{
switch(event)
{
case XFER_RESULT_SUCCESS:
osal_queue_send(queue_mouse_hdl, &usb_mouse_report);
(void) tuh_hid_mouse_get_report(dev_addr, (uint8_t*) &usb_mouse_report);
break;
case XFER_RESULT_FAILED:
(void) tuh_hid_mouse_get_report(dev_addr, (uint8_t*) &usb_mouse_report); // ignore & continue
break;
default :
break;
}
}
//--------------------------------------------------------------------+
// APPLICATION CODE
// NOTICE: MOUSE REPORT IS NOT CORRECT UNTIL A DECENT HID PARSER IS
// IMPLEMENTED, MEANWHILE IT CAN MISS DISPLAY BUTTONS OR X,Y etc
//--------------------------------------------------------------------+
void mouse_host_app_init(void)
{
tu_memclr(&usb_mouse_report, sizeof(hid_mouse_report_t));
queue_mouse_hdl = osal_queue_create( QUEUE_MOUSE_REPORT_DEPTH, sizeof(hid_mouse_report_t) );
TU_ASSERT( queue_mouse_hdl, VOID_RETURN);
TU_VERIFY( osal_task_create(mouse_host_app_task, "mouse", 128, NULL, MOUSE_APP_TASK_PRIO), );
}
//------------- main task -------------//
void mouse_host_app_task(void* param)
{
(void) param;
OSAL_TASK_BEGIN
tusb_error_t error;
hid_mouse_report_t mouse_report;
osal_queue_receive(queue_mouse_hdl, &mouse_report, OSAL_TIMEOUT_WAIT_FOREVER, &error);
(void) error; // suppress compiler's warnings
process_mouse_report(&mouse_report);
OSAL_TASK_END
}
//--------------------------------------------------------------------+
// HELPER
//--------------------------------------------------------------------+
void cursor_movement(int8_t x, int8_t y, int8_t wheel)
{
//------------- X -------------//
if ( x < 0)
{
printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left
}else if ( x > 0)
{
printf(ANSI_CURSOR_FORWARD(%d), x); // move right
}else { }
//------------- Y -------------//
if ( y < 0)
{
printf(ANSI_CURSOR_UP(%d), (-y)); // move up
}else if ( y > 0)
{
printf(ANSI_CURSOR_DOWN(%d), y); // move down
}else { }
//------------- wheel -------------//
if (wheel < 0)
{
printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up
}else if (wheel > 0)
{
printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down
}else { }
}
static inline void process_mouse_report(hid_mouse_report_t const * p_report)
{
static hid_mouse_report_t prev_report = { 0, 0, 0, 0 };
//------------- button state -------------//
uint8_t button_changed_mask = p_report->buttons ^ prev_report.buttons;
if ( button_changed_mask & p_report->buttons)
{
printf(" %c%c%c ",
p_report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-',
p_report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-',
p_report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-');
}
//------------- cursor movement -------------//
cursor_movement(p_report->x, p_report->y, p_report->wheel);
}
#endif

View File

@ -1,71 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
/** \file
* \brief TBD
*
* \note TBD
*/
/** \ingroup TBD
* \defgroup TBD
* \brief TBD
*
* @{
*/
#ifndef _TUSB_MOUSE_HOST_APP_H_
#define _TUSB_MOUSE_HOST_APP_H_
#include <stdint.h>
#include <stdbool.h>
#include "board.h"
#include "tusb.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CFG_TUH_HID_MOUSE
void mouse_host_app_init(void);
void mouse_host_app_task(void* param);
#else
#define mouse_host_app_init()
#define mouse_host_app_task(x)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_MOUSE_HOST_APP_H_ */
/** @} */

View File

@ -1,473 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
#include "msc_cli.h"
#include "ctype.h"
#if CFG_TUH_MSC
#include "ff.h"
#include "diskio.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
#define CLI_MAX_BUFFER 256
#define CLI_FILE_READ_BUFFER (4*1024)
enum {
ASCII_BACKSPACE = 8,
};
typedef enum
{
CLI_ERROR_NONE = 0,
CLI_ERROR_INVALID_PARA,
CLI_ERROR_INVALID_PATH,
CLI_ERROR_FILE_EXISTED,
CLI_ERROR_FAILED
}cli_error_t;
static char const * const cli_error_message[] =
{
[CLI_ERROR_NONE ] = 0,
[CLI_ERROR_INVALID_PARA ] = "Invalid parameter(s)",
[CLI_ERROR_INVALID_PATH ] = "No such file or directory",
[CLI_ERROR_FILE_EXISTED ] = "file or directory already exists",
[CLI_ERROR_FAILED ] = "failed to execute"
};
//--------------------------------------------------------------------+
// CLI Database definition
//--------------------------------------------------------------------+
// command, function, description
#define CLI_COMMAND_TABLE(ENTRY) \
ENTRY(unknown , cli_cmd_unknown , NULL ) \
ENTRY(help , cli_cmd_help , NULL ) \
ENTRY(cls , cli_cmd_clear , "Clear the screen.\n cls\n" ) \
ENTRY(ls , cli_cmd_list , "List information of the FILEs.\n ls\n" ) \
ENTRY(cd , cli_cmd_changedir, "change the current directory.\n cd a_folder\n" ) \
ENTRY(cat , cli_cmd_cat , "display contents of a file.\n cat a_file.txt\n" ) \
ENTRY(cp , cli_cmd_copy , "Copies one or more files to another location.\n cp a_file.txt dir1/another_file.txt\n cp a_file.txt dir1\n" ) \
ENTRY(mkdir , cli_cmd_mkdir , "Create a DIRECTORY, if it does not already exist.\n mkdir <new folder>\n" ) \
ENTRY(mv , cli_cmd_move , "Rename or move a DIRECTORY or a FILE.\n mv old_name.txt new_name.txt\n mv old_name.txt dir1/new_name.txt\n" ) \
ENTRY(rm , cli_cmd_remove , "Remove (delete) an empty DIRECTORY or FILE.\n rm deleted_name.txt\n rm empty_dir\n" ) \
//--------------------------------------------------------------------+
// Expands the function to have the standard function signature
//--------------------------------------------------------------------+
#define CLI_PROTOTYPE_EXPAND(command, function, description) \
cli_error_t function(char * p_para);
CLI_COMMAND_TABLE(CLI_PROTOTYPE_EXPAND)
//--------------------------------------------------------------------+
// Expand to enum value
//--------------------------------------------------------------------+
#define CLI_ENUM_EXPAND(command, function, description) CLI_CMDTYPE_##command,
typedef enum
{
CLI_COMMAND_TABLE(CLI_ENUM_EXPAND)
CLI_CMDTYPE_COUNT
}cli_cmdtype_t;
//--------------------------------------------------------------------+
// Expand to string table
//--------------------------------------------------------------------+
#define CLI_STRING_EXPAND(command, function, description) #command,
char const* const cli_string_tbl[] =
{
CLI_COMMAND_TABLE(CLI_STRING_EXPAND)
};
//--------------------------------------------------------------------+
// Expand to Description table
//--------------------------------------------------------------------+
#define CLI_DESCRIPTION_EXPAND(command, function, description) description,
char const* const cli_description_tbl[] =
{
CLI_COMMAND_TABLE(CLI_DESCRIPTION_EXPAND)
};
//--------------------------------------------------------------------+
// Expand to Command Lookup Table
//--------------------------------------------------------------------+
#define CMD_LOOKUP_EXPAND(command, function, description)\
[CLI_CMDTYPE_##command] = function,\
typedef cli_error_t (* const cli_cmdfunc_t)(char *);
static cli_cmdfunc_t cli_command_tbl[] =
{
CLI_COMMAND_TABLE(CMD_LOOKUP_EXPAND)
};
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
CFG_TUSB_MEM_SECTION uint8_t fileread_buffer[CLI_FILE_READ_BUFFER];
static char cli_buffer[CLI_MAX_BUFFER];
static char volume_label[20];
static inline void drive_number2letter(char * p_path)
{
if (p_path[1] == ':')
{
p_path[0] = 'E' + p_path[0] - '0' ;
}
}
static inline void drive_letter2number(char * p_path)
{
if (p_path[1] == ':')
{
p_path[0] = p_path[0] - 'E' + '0';
}
}
//--------------------------------------------------------------------+
// IMPLEMENTATION
//--------------------------------------------------------------------+
// NOTES: prompt re-use cli_buffer --> should not be called when cli_buffer has contents
void cli_command_prompt(void)
{
f_getcwd(cli_buffer, CLI_MAX_BUFFER);
drive_number2letter(cli_buffer);
printf("\n%s %s\n$ ",
(volume_label[0] !=0) ? volume_label : "No Label",
cli_buffer);
tu_memclr(cli_buffer, CLI_MAX_BUFFER);
}
void cli_init(void)
{
tu_memclr(cli_buffer, CLI_MAX_BUFFER);
f_getlabel(NULL, volume_label, NULL);
cli_command_prompt();
}
void cli_poll(char ch)
{
if ( isprint(ch) )
{ // accumulate & echo
if (strlen(cli_buffer) < CLI_MAX_BUFFER)
{
cli_buffer[ strlen(cli_buffer) ] = ch;
putchar(ch);
}else
{
puts("cli buffer overflows");
tu_memclr(cli_buffer, CLI_MAX_BUFFER);
}
}
else if ( ch == ASCII_BACKSPACE && strlen(cli_buffer))
{
printf(ANSI_CURSOR_BACKWARD(1) ANSI_ERASE_LINE(0) ); // move cursor back & clear to the end of line
cli_buffer[ strlen(cli_buffer)-1 ] = 0;
}
else if ( ch == '\r')
{ // execute command
//------------- Separate Command & Parameter -------------//
putchar('\n');
char* p_space = strchr(cli_buffer, ' ');
uint32_t command_len = (p_space == NULL) ? strlen(cli_buffer) : (uint32_t) (p_space - cli_buffer);
char* p_para = (p_space == NULL) ? (cli_buffer+command_len) : (p_space+1); // point to NULL-character or after space
//------------- Find entered command in lookup table & execute it -------------//
uint8_t cmd_id;
for(cmd_id = CLI_CMDTYPE_COUNT - 1; cmd_id > CLI_CMDTYPE_unknown; cmd_id--)
{
if( 0 == strncmp(cli_buffer, cli_string_tbl[cmd_id], command_len) ) break;
}
cli_error_t error = cli_command_tbl[cmd_id]( p_para ); // command execution, (unknown command if cannot find)
if (CLI_ERROR_NONE != error) puts(cli_error_message[error]); // error message output if any
cli_command_prompt(); // print out current path
}
else if (ch=='\t') // \t may be used for auto-complete later
{
}
}
//--------------------------------------------------------------------+
// UNKNOWN Command
//--------------------------------------------------------------------+
cli_error_t cli_cmd_unknown(char * p_para)
{
(void) p_para;
puts("unknown command, please type \"help\" for list of supported commands");
return CLI_ERROR_NONE;
}
//--------------------------------------------------------------------+
// HELP command
//--------------------------------------------------------------------+
cli_error_t cli_cmd_help(char * p_para)
{
(void) p_para;
puts("current supported commands are:");
for(uint8_t cmd_id = CLI_CMDTYPE_help+1; cmd_id < CLI_CMDTYPE_COUNT; cmd_id++)
{
printf("%s\t%s\n", cli_string_tbl[cmd_id], cli_description_tbl[cmd_id]);
}
return CLI_ERROR_NONE;
}
//--------------------------------------------------------------------+
// Clear Screen Command
//--------------------------------------------------------------------+
cli_error_t cli_cmd_clear(char* p_para)
{
(void) p_para;
printf(ANSI_ERASE_SCREEN(2) ANSI_CURSOR_POSITION(1,1) );
return CLI_ERROR_NONE;
}
//--------------------------------------------------------------------+
// LS Command
//--------------------------------------------------------------------+
cli_error_t cli_cmd_list(char * p_para)
{
if ( strlen(p_para) == 0 ) // list current directory
{
DIR target_dir;
if ( FR_OK != f_opendir(&target_dir, ".") ) return CLI_ERROR_FAILED;
TCHAR long_filename[_MAX_LFN];
FILINFO dir_entry =
{
.lfname = long_filename,
.lfsize = _MAX_LFN
};
while( (f_readdir(&target_dir, &dir_entry) == FR_OK) && dir_entry.fname[0] != 0)
{
if ( dir_entry.fname[0] != '.' ) // ignore . and .. entry
{
TCHAR const * const p_name = (dir_entry.lfname[0] != 0) ? dir_entry.lfname : dir_entry.fname;
if ( dir_entry.fattrib & AM_DIR ) // directory
{
printf("/%s", p_name);
}else
{
printf("%-40s%d KB", p_name, dir_entry.fsize / 1000);
}
putchar('\n');
}
}
// (void) f_closedir(&target_dir);
}
else
{
puts("ls only supports list current directory only, try to cd to that folder first");
return CLI_ERROR_INVALID_PARA;
}
return CLI_ERROR_NONE;
}
//--------------------------------------------------------------------+
// CD Command
//--------------------------------------------------------------------+
cli_error_t cli_cmd_changedir(char * p_para)
{
if ( strlen(p_para) == 0 ) return CLI_ERROR_INVALID_PARA;
drive_letter2number(p_para);
if ( FR_OK != f_chdir(p_para) )
{
return CLI_ERROR_INVALID_PATH;
}
if ( p_para[1] == ':')
{ // path has drive letter --> change drive, update volume label
f_chdrive(p_para[0] - '0');
f_getlabel(NULL, volume_label, NULL);
}
return CLI_ERROR_NONE;
}
//--------------------------------------------------------------------+
// CAT Command
//--------------------------------------------------------------------+
cli_error_t cli_cmd_cat(char *p_para)
{
if ( strlen(p_para) == 0 ) return CLI_ERROR_INVALID_PARA;
FIL file;
switch( f_open(&file, p_para, FA_READ) )
{
case FR_OK:
{
uint32_t bytes_read = 0;
if ( (FR_OK == f_read(&file, fileread_buffer, CLI_FILE_READ_BUFFER, &bytes_read)) && (bytes_read > 0) )
{
if ( file.fsize < 0x80000 ) // ~ 500KB
{
putchar('\n');
do {
for(uint32_t i=0; i<bytes_read; i++) putchar( fileread_buffer[i] );
}while( (FR_OK == f_read(&file, fileread_buffer, CLI_FILE_READ_BUFFER, &bytes_read)) && (bytes_read > 0) );
}else
{ // not display file contents if first character is not printable (high chance of binary file)
printf("%s 's contents is too large\n", p_para);
}
}
f_close(&file);
}
break;
case FR_INVALID_NAME:
return CLI_ERROR_INVALID_PATH;
default :
return CLI_ERROR_FAILED;
}
return CLI_ERROR_NONE;
}
//--------------------------------------------------------------------+
// Make Directory command
//--------------------------------------------------------------------+
cli_error_t cli_cmd_mkdir(char *p_para)
{
if ( strlen(p_para) == 0 ) return CLI_ERROR_INVALID_PARA;
return (f_mkdir(p_para) == FR_OK) ? CLI_ERROR_NONE : CLI_ERROR_FAILED;
}
//--------------------------------------------------------------------+
// COPY command
//--------------------------------------------------------------------+
cli_error_t cli_cmd_copy(char *p_para)
{
char* p_space = strchr(p_para, ' ');
if ( p_space == NULL ) return CLI_ERROR_INVALID_PARA;
*p_space = 0; // replace space by NULL-character
char* p_dest = p_space+1;
if ( strlen(p_dest) == 0 ) return CLI_ERROR_INVALID_PARA;
drive_letter2number(p_para);
drive_letter2number(p_dest);
//------------- Check Existence of source file -------------//
FIL src_file;
if ( FR_OK != f_open(&src_file , p_para, FA_READ) ) return CLI_ERROR_INVALID_PATH;
//------------- Check if dest path is a folder or a non-existing file (overwritten is not allowed) -------------//
FILINFO dest_entry;
if ( (f_stat(p_dest, &dest_entry) == FR_OK) && (dest_entry.fattrib & AM_DIR) )
{ // the destination is an existed folder --> auto append dest filename to be the folder
strcat(p_dest, "/");
strcat(p_dest, p_para);
}
//------------- Open dest file and start the copy -------------//
cli_error_t error = CLI_ERROR_NONE;
FIL dest_file;
switch ( f_open(&dest_file, p_dest, FA_WRITE | FA_CREATE_NEW) )
{
case FR_EXIST:
error = CLI_ERROR_FILE_EXISTED;
break;
case FR_OK:
while(1) // copying
{
uint32_t bytes_read = 0;
uint32_t bytes_write = 0;
FRESULT res;
res = f_read(&src_file, fileread_buffer, CLI_FILE_READ_BUFFER, &bytes_read); /* Read a chunk of src file */
if ( (res != FR_OK) || (bytes_read == 0) ) break; /* error or eof */
res = f_write(&dest_file, fileread_buffer, bytes_read, &bytes_write); /* Write it to the dst file */
if ( (res != FR_OK) || (bytes_write < bytes_read) ) break; /* error or disk full */
}
f_close(&dest_file);
break;
default:
error = CLI_ERROR_FAILED;
break;
}
f_close(&src_file);
return error;
}
//--------------------------------------------------------------------+
// MOVE/RENAME
//--------------------------------------------------------------------+
cli_error_t cli_cmd_move(char *p_para)
{
char* p_space = strchr(p_para, ' ');
if ( p_space == NULL ) return CLI_ERROR_INVALID_PARA;
*p_space = 0; // replace space by NULL-character
char* p_dest = p_space+1;
if ( strlen(p_dest) == 0 ) return CLI_ERROR_INVALID_PARA;
return (f_rename(p_para, p_dest) == FR_OK ) ? CLI_ERROR_NONE : CLI_ERROR_FAILED;
}
//--------------------------------------------------------------------+
// REMOVE
//--------------------------------------------------------------------+
cli_error_t cli_cmd_remove(char *p_para)
{
if ( strlen(p_para) == 0 ) return CLI_ERROR_INVALID_PARA;
switch( f_unlink(p_para) )
{
case FR_OK: return CLI_ERROR_NONE;
case FR_DENIED:
printf("cannot remove readonly file/foler or non-empty folder\n");
break;
default: break;
}
return CLI_ERROR_FAILED;
}
#endif

View File

@ -1,52 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
#ifndef _TUSB_MSC_CLI_H_
#define _TUSB_MSC_CLI_H_
#include "board.h"
#include "tusb.h"
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// PUBLIC API
//--------------------------------------------------------------------+
void cli_init(void);
void cli_poll(char ch);
//--------------------------------------------------------------------+
// Callback API
//--------------------------------------------------------------------+
#ifdef __cplusplus
}
#endif
#endif // _TUSB_CLI_H_

View File

@ -1,170 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "msc_host_app.h"
#include "app_os_prio.h"
#if CFG_TUH_MSC
#include "msc_cli.h"
#include "ff.h"
#include "diskio.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
CFG_TUSB_MEM_SECTION static FATFS fatfs[CFG_TUSB_HOST_DEVICE_MAX];
//--------------------------------------------------------------------+
// tinyusb callbacks
//--------------------------------------------------------------------+
void tuh_msc_mounted_cb(uint8_t dev_addr)
{
puts("\na MassStorage device is mounted");
//------------- Disk Information -------------//
// SCSI VendorID[8] & ProductID[16] from Inquiry Command
uint8_t const* p_vendor = tuh_msc_get_vendor_name(dev_addr);
uint8_t const* p_product = tuh_msc_get_product_name(dev_addr);
for(uint8_t i=0; i<8; i++) putchar(p_vendor[i]);
putchar(' ');
for(uint8_t i=0; i<16; i++) putchar(p_product[i]);
putchar('\n');
uint32_t last_lba, block_size;
tuh_msc_read_capacity(dev_addr, &last_lba, &block_size);
printf("Disk Size: %d MB\n", (last_lba+1)/ ((1024*1024)/block_size) );
printf("LBA 0-0x%X Block Size: %d\n", last_lba, block_size);
//------------- file system (only 1 LUN support) -------------//
uint8_t phy_disk = dev_addr-1;
disk_initialize(phy_disk);
if ( disk_is_ready(phy_disk) )
{
if ( f_mount(phy_disk, &fatfs[phy_disk]) != FR_OK )
{
puts("mount failed");
return;
}
puts("---------------------------------------------------------------------");
puts("- MASSSTORAGE CLASS CLI IS A IMMATURE CODE. DISK-WRITING COMMANDS");
puts("- SUCH AS cp(COPY), mkdir(MAKE DIRECTORY) ARE POTENTIAL TO DAMAGE");
puts("- YOUR USB THUMBDRIVE. USING THOSE COMMANDS ARE AT YOUR OWN RISK.");
puts("- THE AUTHOR HAS NO RESPONSIBILITY WITH YOUR DEVICE NOR ITS DATA");
puts("---------------------------------------------------------------------");
f_chdrive(phy_disk); // change to newly mounted drive
f_chdir("/"); // root as current dir
cli_init();
}
}
void tuh_msc_unmounted_cb(uint8_t dev_addr)
{
puts("\na MassStorage device is unmounted");
uint8_t phy_disk = dev_addr-1;
f_mount(phy_disk, NULL); // unmount disk
disk_deinitialize(phy_disk);
if ( phy_disk == f_get_current_drive() )
{ // active drive is unplugged --> change to other drive
for(uint8_t i=0; i<CFG_TUSB_HOST_DEVICE_MAX; i++)
{
if ( disk_is_ready(i) )
{
f_chdrive(i);
cli_init(); // refractor, rename
}
}
}
}
// invoked ISR context
void tuh_msc_isr(uint8_t dev_addr, xfer_result_t event, uint32_t xferred_bytes)
{
(void) dev_addr;
(void) event;
(void) xferred_bytes;
}
//--------------------------------------------------------------------+
// APPLICATION CODE
//--------------------------------------------------------------------+
void msc_host_app_init(void)
{
osal_task_create( msc_host_app_task, "msc", 512, NULL, MSC_APP_TASK_PRIO);
diskio_init();
}
//------------- main task -------------//
void msc_host_app_task(void* param)
{
(void) param;;
OSAL_TASK_BEGIN
bool is_any_disk_mounted;
osal_task_delay(10);
is_any_disk_mounted = false;
for(uint8_t phy_disk=0; phy_disk < CFG_TUSB_HOST_DEVICE_MAX; phy_disk++)
{
if ( disk_is_ready(phy_disk) )
{
is_any_disk_mounted = true;
break;
}
}
if ( is_any_disk_mounted )
{
int ch = getchar();
if ( ch > 0 )
{
cli_poll( (char) ch);
}
}
OSAL_TASK_END
}
#endif

View File

@ -1,63 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
/** \ingroup TBD
* \defgroup TBD
* \brief TBD
*
* @{
*/
#ifndef _TUSB_MSC_HOST_APP_H_
#define _TUSB_MSC_HOST_APP_H_
#include "board.h"
#include "tusb.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CFG_TUH_MSC
void msc_host_app_init(void);
void msc_host_app_task(void* param);
#else
#define msc_host_app_init()
#define msc_host_app_task(x)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_MSC_HOST_APP_H_ */
/** @} */

View File

@ -1,64 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
#include "rndis_host_app.h"
#include "app_os_prio.h"
#if CFG_TUH_CDC && CFG_TUH_CDC_RNDIS
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
void tusbh_cdc_rndis_mounted_cb(uint8_t dev_addr)
{ // application set-up
uint8_t mac_address[6];
printf("\nan RNDIS device is mounted\n");
tusbh_cdc_rndis_get_mac_addr(dev_addr, mac_address);
printf("MAC Address ");
for(uint8_t i=0; i<6; i++) printf("%X ", mac_address[i]);
printf("\n");
}
void tusbh_cdc_rndis_unmounted_cb(uint8_t dev_addr)
{
// application tear-down
printf("\nan RNDIS device is unmounted\n");
}
void rndis_host_app_init(void)
{
}
void rndis_host_app_task(void* param)
{
OSAL_TASK_BEGIN
OSAL_TASK_END
}
#endif

View File

@ -1,63 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
/** \ingroup TBD
* \defgroup TBD
* \brief TBD
*
* @{
*/
#ifndef _TUSB_RNDIS_HOST_APP_H_
#define _TUSB_RNDIS_HOST_APP_H_
#include "board.h"
#include "tusb.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CFG_TUH_CDC && CFG_TUH_CDC_RNDIS
void rndis_host_app_init(void);
void rndis_host_app_task(void* param);
#else
#define rndis_host_app_init()
#define rndis_host_app_task(x)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_RNDIS_HOST_APP_H_ */
/** @} */

View File

@ -1,101 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// CONTROLLER CONFIGURATION
//--------------------------------------------------------------------+
//#define CFG_TUSB_MCU will be passed from IDE for easy board/mcu switching
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST)
//--------------------------------------------------------------------+
// HOST CONFIGURATION
//--------------------------------------------------------------------+
//------------- CLASS -------------//
#define CFG_TUH_HUB 1
#define CFG_TUH_HID_KEYBOARD 1
#define CFG_TUH_HID_MOUSE 1
#define CFG_TUSB_HOST_HID_GENERIC 0 // (not yet supported)
#define CFG_TUH_MSC 1
#define CFG_TUH_CDC 1
#define CFG_TUSB_HOST_DEVICE_MAX (CFG_TUH_HUB ? 5 : 1) // normal hub has 4 ports
//--------------------------------------------------------------------+
// COMMON CONFIGURATION
//--------------------------------------------------------------------+
#define CFG_TUSB_DEBUG 1
//#define CFG_TUSB_OS OPT_OS_NONE // defined using eclipse build
//#define CFG_TUD_TASK_PRIO 0 // defined using eclipse build
//--------------------------------------------------------------------+
// USB RAM PLACEMENT
//--------------------------------------------------------------------+
#ifdef __CODE_RED // make use of code red's support for ram region macros
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X
#define CFG_TUSB_MEM_SECTION // LPC17xx USB DMA can access all address
#elif (CFG_TUSB_MCU == OPT_MCU_LPC43XX)
#define CFG_TUSB_MEM_SECTION TU_ATTR_SECTION(.data.$RAM3)
#endif
#elif defined __CC_ARM // Compiled with Keil armcc
#if (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X)
#define CFG_TUSB_MEM_SECTION // LPC17xx USB DMA can access all address
#elif (CFG_TUSB_MCU == OPT_MCU_LPC43XX)
#define CFG_TUSB_MEM_SECTION // Use keil tool configure to have AHB SRAM as default memory
#endif
#elif defined __ICCARM__ // compiled with IAR
#if (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X)
// LP175x_6x can access all but CMSIS-RTX causes overflow in 32KB SRAM --> move to AHB ram
#define CFG_TUSB_MEM_SECTION _Pragma("location=\".sram\"")
#elif (CFG_TUSB_MCU == OPT_MCU_LPC43XX)
#define CFG_TUSB_MEM_SECTION _Pragma("location=\".ahb_sram1\"")
#endif
#else
#error compiler not specified
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

View File

@ -82,10 +82,15 @@ void board_init(void)
LPUART_Init(UART_PORT, &uart_config, (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U));
//------------- USB0 -------------//
// Clock
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
// USB1
// CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
// CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U);
USBPHY_Type* usb_phy;
// RT105x RT106x have dual USB controller. TODO support USB2
@ -106,10 +111,6 @@ void board_init(void)
phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
usb_phy->TX = phytx;
// USB1
// CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
// CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U);
}
//--------------------------------------------------------------------+

View File

@ -157,51 +157,12 @@ void board_init(void)
Chip_UART_TXEnable(UART_DEV);
//------------- USB -------------//
enum {
USBMODE_DEVICE = 2,
USBMODE_HOST = 3
};
enum {
USBMODE_VBUS_LOW = 0,
USBMODE_VBUS_HIGH = 1
};
// USB0
#if CFG_TUSB_RHPORT0_MODE
Chip_USB0_Init();
// Host/Device mode can only be set right after controller reset
LPC_USB0->USBCMD_D |= 0x02;
while( LPC_USB0->USBCMD_D & 0x02 ) {}
// Set mode
#if CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST
LPC_USB0->USBMODE_H = USBMODE_HOST | (USBMODE_VBUS_HIGH << 5);
LPC_USB0->PORTSC1_H |= (1<<24); // FIXME force full speed for debugging
#else // TODO OTG
LPC_USB0->USBMODE_D = USBMODE_DEVICE;
LPC_USB0->OTGSC = (1<<3) | (1<<0) /*| (1<<16)| (1<<24)| (1<<25)| (1<<26)| (1<<27)| (1<<28)| (1<<29)| (1<<30)*/;
#endif
#endif
// USB1
#if CFG_TUSB_RHPORT1_MODE
Chip_USB1_Init();
// // Reset controller
// LPC_USB1->USBCMD_D |= 0x02;
// while( LPC_USB1->USBCMD_D & 0x02 ) {}
//
// // Set mode
// #if CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST
// LPC_USB1->USBMODE_H = USBMODE_HOST | (USBMODE_VBUS_HIGH << 5);
// #else // TODO OTG
// LPC_USB1->USBMODE_D = USBMODE_DEVICE;
// #endif
//
// // USB1 as fullspeed
// LPC_USB1->PORTSC1_D |= (1<<24);
#endif
}

View File

@ -31,9 +31,13 @@
extern "C" {
#endif
#define LED_PIN 14
#define LED_PIN 13
#define LED_STATE_ON 1
#define NEOPIXEL_PIN 16
#define NEOPIXEL_POWER_PIN 17
#define NEOPIXEL_POWER_STATE 1
// Button pin is BOOTSEL which is flash CS pin
#define BUTTON_BOOTSEL
#define BUTTON_STATE_ACTIVE 0

View File

@ -34,6 +34,10 @@
#define LED_PIN 11
#define LED_STATE_ON 1
#define NEOPIXEL_PIN 17
#define NEOPIXEL_POWER_PIN 16
#define NEOPIXEL_POWER_STATE 1
// Button pin is BOOTSEL which is flash CS pin
#define BUTTON_BOOTSEL
#define BUTTON_STATE_ACTIVE 0

View File

@ -35,6 +35,10 @@
#define LED_PIN 11
#define LED_STATE_ON 1
#define NEOPIXEL_PIN 12
#define NEOPIXEL_POWER_PIN 11
#define NEOPIXEL_POWER_STATE 1
// Button pin is BOOTSEL which is flash CS pin
#define BUTTON_BOOTSEL
#define BUTTON_STATE_ACTIVE 0

View File

@ -110,8 +110,10 @@ void stdio_rtt_init(void)
void board_init(void)
{
#ifdef LED_PIN
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
#endif
// Button
#ifndef BUTTON_BOOTSEL
@ -141,7 +143,9 @@ void board_init(void)
void board_led_write(bool state)
{
#ifdef LED_PIN
gpio_put(LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON));
#endif
}
uint32_t board_button_read(void)

View File

@ -0,0 +1,50 @@
CONF_CPU_FREQUENCY ?= 120000000
CFLAGS += \
-mthumb \
-mabi=aapcs \
-mlong-calls \
-mcpu=cortex-m4 \
-mfloat-abi=hard \
-mfpu=fpv4-sp-d16 \
-nostdlib -nostartfiles \
-D__SAME54P20A__ \
-DCONF_CPU_FREQUENCY=$(CONF_CPU_FREQUENCY) \
-DCFG_TUSB_MCU=OPT_MCU_SAME5X \
# -DSVC_Handler=SVCall_Handler
# All source paths should be relative to the top level.
LD_FILE = hw/bsp/$(BOARD)/same54p20a_flash.ld
SRC_C += \
hw/mcu/microchip/asf4/same54/gcc/gcc/startup_same54.c \
hw/mcu/microchip/asf4/same54/gcc/system_same54.c \
hw/mcu/microchip/asf4/same54/hal/utils/src/utils_syscalls.c
INC += \
$(TOP)/hw/mcu/microchip/asf4/same54/ \
$(TOP)/hw/mcu/microchip/asf4/same54/config \
$(TOP)/hw/mcu/microchip/asf4/same54/include \
$(TOP)/hw/mcu/microchip/asf4/same54/hal/include \
$(TOP)/hw/mcu/microchip/asf4/same54/hal/utils/include \
$(TOP)/hw/mcu/microchip/asf4/same54/hpl/port \
$(TOP)/hw/mcu/microchip/asf4/same54/hri \
$(TOP)/hw/mcu/microchip/asf4/same54/CMSIS/Include
# For TinyUSB port source
VENDOR = microchip
CHIP_FAMILY = samd
# For freeRTOS port source
FREERTOS_PORT = ARM_CM4F
# For flash-jlink target
JLINK_DEVICE = ATSAME54P20
# flash using edbg from https://github.com/ataradov/edbg
flash: $(BUILD)/$(PROJECT).bin
edbg --verbose -t same54 -pv -f $<

View File

@ -0,0 +1,163 @@
/**
* \file
*
* \brief Linker script for running in internal FLASH on the SAME54P20A
*
* Copyright (c) 2019 Microchip Technology Inc.
*
* \asf_license_start
*
* \page License
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the Licence at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* \asf_license_stop
*
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00000000, LENGTH = 0x00100000
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
bkupram (rwx) : ORIGIN = 0x47000000, LENGTH = 0x00002000
qspi (rwx) : ORIGIN = 0x04000000, LENGTH = 0x01000000
}
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x10000;
/* Section Definitions */
SECTIONS
{
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
_efixed = .; /* End of text section */
} > rom
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN (__exidx_end = .);
. = ALIGN(4);
_etext = .;
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
.bkupram (NOLOAD):
{
. = ALIGN(8);
_sbkupram = .;
*(.bkupram .bkupram.*);
. = ALIGN(8);
_ebkupram = .;
} > bkupram
.qspi (NOLOAD):
{
. = ALIGN(8);
_sqspi = .;
*(.qspi .qspi.*);
. = ALIGN(8);
_eqspi = .;
} > qspi
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
. = ALIGN(4);
_sbss = . ;
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
_ezero = .;
} > ram
/* stack section */
.stack (NOLOAD):
{
. = ALIGN(8);
_sstack = .;
. = . + STACK_SIZE;
. = ALIGN(8);
_estack = .;
} > ram
. = ALIGN(4);
_end = . ;
}

View File

@ -0,0 +1,162 @@
/**
* \file
*
* \brief Linker script for running in internal SRAM on the SAME54P20A
*
* Copyright (c) 2019 Microchip Technology Inc.
*
* \asf_license_start
*
* \page License
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the Licence at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* \asf_license_stop
*
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
bkupram (rwx) : ORIGIN = 0x47000000, LENGTH = 0x00002000
qspi (rwx) : ORIGIN = 0x04000000, LENGTH = 0x01000000
}
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x10000;
/* Section Definitions */
SECTIONS
{
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
_efixed = .; /* End of text section */
} > ram
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > ram
PROVIDE_HIDDEN (__exidx_end = .);
. = ALIGN(4);
_etext = .;
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
.bkupram (NOLOAD):
{
. = ALIGN(8);
_sbkupram = .;
*(.bkupram .bkupram.*);
. = ALIGN(8);
_ebkupram = .;
} > bkupram
.qspi (NOLOAD):
{
. = ALIGN(8);
_sqspi = .;
*(.qspi .qspi.*);
. = ALIGN(8);
_eqspi = .;
} > qspi
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
. = ALIGN(4);
_sbss = . ;
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
_ezero = .;
} > ram
/* stack section */
.stack (NOLOAD):
{
. = ALIGN(8);
_sstack = .;
. = . + STACK_SIZE;
. = ALIGN(8);
_estack = .;
} > ram
. = ALIGN(4);
_end = . ;
}

View File

@ -0,0 +1,274 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021 Jean Gressmann <jean@0x42.de>
*
* 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 <sam.h>
#include "bsp/board.h"
#include <hal/include/hal_gpio.h>
//--------------------------------------------------------------------+
// Forward USB interrupt events to TinyUSB IRQ Handler
//--------------------------------------------------------------------+
void USB_0_Handler(void)
{
tud_int_handler(0);
}
void USB_1_Handler(void)
{
tud_int_handler(0);
}
void USB_2_Handler(void)
{
tud_int_handler(0);
}
void USB_3_Handler(void)
{
tud_int_handler(0);
}
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
#define LED_PIN PIN_PC18
#define BUTTON_PIN PIN_PB31
#define BOARD_SERCOM SERCOM2
#define BOARD_NAME "Microchip SAM E54 Xplained Pro"
static inline void init_clock(void)
{
/* configure for a 12MHz crystal connected to XIN1/XOUT1 */
OSCCTRL->XOSCCTRL[1].reg =
OSCCTRL_XOSCCTRL_STARTUP(6) | // 1.953 ms
OSCCTRL_XOSCCTRL_RUNSTDBY |
OSCCTRL_XOSCCTRL_ENALC |
OSCCTRL_XOSCCTRL_IMULT(4) | OSCCTRL_XOSCCTRL_IPTAT(3) | // 8MHz to 16MHz
OSCCTRL_XOSCCTRL_XTALEN |
OSCCTRL_XOSCCTRL_ENABLE;
while(0 == OSCCTRL->STATUS.bit.XOSCRDY1);
OSCCTRL->Dpll[0].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_DIV(5) | OSCCTRL_DPLLCTRLB_REFCLK_XOSC1; /* 12MHz / 12 = 1Mhz, input = XOSC1 */
OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x0) | OSCCTRL_DPLLRATIO_LDR((CONF_CPU_FREQUENCY / 1000000)-1); /* multiply to get CONF_CPU_FREQUENCY (default = 120MHz) */
OSCCTRL->Dpll[0].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_RUNSTDBY | OSCCTRL_DPLLCTRLA_ENABLE;
while(0 == OSCCTRL->Dpll[0].DPLLSTATUS.bit.CLKRDY); /* wait for the PLL0 to be ready */
OSCCTRL->Dpll[1].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_DIV(5) | OSCCTRL_DPLLCTRLB_REFCLK_XOSC1; /* 12MHz / 12 = 1Mhz, input = XOSC1 */
OSCCTRL->Dpll[1].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x0) | OSCCTRL_DPLLRATIO_LDR(47); /* multiply by 48 -> 48 MHz */
OSCCTRL->Dpll[1].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_RUNSTDBY | OSCCTRL_DPLLCTRLA_ENABLE;
while(0 == OSCCTRL->Dpll[1].DPLLSTATUS.bit.CLKRDY); /* wait for the PLL1 to be ready */
/* configure clock-generator 0 to use DPLL0 as source -> GCLK0 is used for the core */
GCLK->GENCTRL[0].reg =
GCLK_GENCTRL_DIV(0) |
GCLK_GENCTRL_RUNSTDBY |
GCLK_GENCTRL_GENEN |
GCLK_GENCTRL_SRC_DPLL0 |
GCLK_GENCTRL_IDC;
while(1 == GCLK->SYNCBUSY.bit.GENCTRL0); /* wait for the synchronization between clock domains to be complete */
/* configure clock-generator 1 to use DPLL1 as source -> for use with some peripheral */
GCLK->GENCTRL[1].reg =
GCLK_GENCTRL_DIV(0) |
GCLK_GENCTRL_RUNSTDBY |
GCLK_GENCTRL_GENEN |
GCLK_GENCTRL_SRC_DPLL1 |
GCLK_GENCTRL_IDC ;
while(1 == GCLK->SYNCBUSY.bit.GENCTRL1); /* wait for the synchronization between clock domains to be complete */
}
static inline void uart_init(void)
{
gpio_set_pin_function(PIN_PB24, PINMUX_PB24D_SERCOM2_PAD1);
gpio_set_pin_function(PIN_PB25, PINMUX_PB25D_SERCOM2_PAD0);
MCLK->APBBMASK.bit.SERCOM2_ = 1;
GCLK->PCHCTRL[SERCOM2_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK1 | GCLK_PCHCTRL_CHEN; /* setup SERCOM to use GLCK1 -> 48MHz */
BOARD_SERCOM->USART.CTRLA.bit.SWRST = 1; /* reset and disable SERCOM -> enable configuration */
while (BOARD_SERCOM->USART.SYNCBUSY.bit.SWRST);
BOARD_SERCOM->USART.CTRLA.reg =
SERCOM_USART_CTRLA_SAMPR(0) | /* 0 = 16x / arithmetic baud rate, 1 = 16x / fractional baud rate */
SERCOM_USART_CTRLA_SAMPA(0) | /* 16x over sampling */
SERCOM_USART_CTRLA_FORM(0) | /* 0x0 USART frame, 0x1 USART frame with parity, ... */
SERCOM_USART_CTRLA_DORD | /* LSB first */
SERCOM_USART_CTRLA_MODE(1) | /* 0x0 USART with external clock, 0x1 USART with internal clock */
SERCOM_USART_CTRLA_RXPO(1) | /* SERCOM PAD[1] is used for data reception */
SERCOM_USART_CTRLA_TXPO(0); /* SERCOM PAD[0] is used for data transmission */
BOARD_SERCOM->USART.CTRLB.reg = /* RXEM = 0 -> receiver disabled, LINCMD = 0 -> normal USART transmission, SFDE = 0 -> start-of-frame detection disabled, SBMODE = 0 -> one stop bit, CHSIZE = 0 -> 8 bits */
SERCOM_USART_CTRLB_TXEN | /* transmitter enabled */
SERCOM_USART_CTRLB_RXEN; /* receiver enabled */
// BOARD_SERCOM->USART.BAUD.reg = SERCOM_USART_BAUD_FRAC_FP(0) | SERCOM_USART_BAUD_FRAC_BAUD(26); /* 48000000/(16*115200) = 26.041666667 */
BOARD_SERCOM->USART.BAUD.reg = SERCOM_USART_BAUD_BAUD(63019); /* 65536*(116*115200/48000000) */
BOARD_SERCOM->SPI.CTRLA.bit.ENABLE = 1; /* activate SERCOM */
while (BOARD_SERCOM->USART.SYNCBUSY.bit.ENABLE); /* wait for SERCOM to be ready */
}
static inline void uart_send_buffer(uint8_t const *text, size_t len)
{
for (size_t i = 0; i < len; ++i) {
BOARD_SERCOM->USART.DATA.reg = text[i];
while((BOARD_SERCOM->USART.INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC) == 0);
}
}
static inline void uart_send_str(const char* text)
{
while (*text) {
BOARD_SERCOM->USART.DATA.reg = *text++;
while((BOARD_SERCOM->USART.INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC) == 0);
}
}
void board_init(void)
{
init_clock();
SystemCoreClock = CONF_CPU_FREQUENCY;
#if CFG_TUSB_OS == OPT_OS_NONE
SysTick_Config(CONF_CPU_FREQUENCY / 1000);
#endif
uart_init();
#if CFG_TUSB_DEBUG >= 2
uart_send_str(BOARD_NAME " UART initialized\n");
tu_printf(BOARD_NAME " reset cause %#02x\n", RSTC->RCAUSE.reg);
#endif
// LED0 init
gpio_set_pin_direction(LED_PIN, GPIO_DIRECTION_OUT);
gpio_set_pin_level(LED_PIN, 0);
#if CFG_TUSB_DEBUG >= 2
uart_send_str(BOARD_NAME " LED pin configured\n");
#endif
// BTN0 init
gpio_set_pin_function(BUTTON_PIN, GPIO_DIRECTION_IN);
gpio_set_pin_direction(BUTTON_PIN, GPIO_DIRECTION_IN);
gpio_set_pin_pull_mode(BUTTON_PIN, GPIO_PULL_UP);
#if CFG_TUSB_DEBUG >= 2
uart_send_str(BOARD_NAME " Button pin configured\n");
#endif
#if CFG_TUSB_OS == OPT_OS_FREERTOS
// If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
NVIC_SetPriority(USB_0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
NVIC_SetPriority(USB_1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
NVIC_SetPriority(USB_2_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
NVIC_SetPriority(USB_3_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
#endif
#if TUSB_OPT_DEVICE_ENABLED
#if CFG_TUSB_DEBUG >= 2
uart_send_str(BOARD_NAME " USB device enabled\n");
#endif
/* USB clock init
* The USB module requires a GCLK_USB of 48 MHz ~ 0.25% clock
* for low speed and full speed operation.
*/
hri_gclk_write_PCHCTRL_reg(GCLK, USB_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN);
hri_mclk_set_AHBMASK_USB_bit(MCLK);
hri_mclk_set_APBBMASK_USB_bit(MCLK);
// USB pin init
gpio_set_pin_direction(PIN_PA24, GPIO_DIRECTION_OUT);
gpio_set_pin_level(PIN_PA24, false);
gpio_set_pin_pull_mode(PIN_PA24, GPIO_PULL_OFF);
gpio_set_pin_direction(PIN_PA25, GPIO_DIRECTION_OUT);
gpio_set_pin_level(PIN_PA25, false);
gpio_set_pin_pull_mode(PIN_PA25, GPIO_PULL_OFF);
gpio_set_pin_function(PIN_PA24, PINMUX_PA24H_USB_DM);
gpio_set_pin_function(PIN_PA25, PINMUX_PA25H_USB_DP);
#if CFG_TUSB_DEBUG >= 2
uart_send_str(BOARD_NAME " USB device configured\n");
#endif
#endif
}
//--------------------------------------------------------------------+
// Board porting API
//--------------------------------------------------------------------+
void board_led_write(bool state)
{
gpio_set_pin_level(LED_PIN, state);
}
uint32_t board_button_read(void)
{
return (PORT->Group[1].IN.reg & 0x80000000) != 0x80000000;
}
int board_uart_read(uint8_t* buf, int len)
{
(void) buf; (void) len;
return 0;
}
int board_uart_write(void const * buf, int len)
{
if (len < 0) {
uart_send_str(buf);
} else {
uart_send_buffer(buf, len);
}
return len;
}
#if CFG_TUSB_OS == OPT_OS_NONE
volatile uint32_t system_ticks = 0;
void SysTick_Handler(void)
{
system_ticks++;
}
uint32_t board_millis(void)
{
return system_ticks;
}
#endif
// Required by __libc_init_array in startup code if we are compiling using
// -nostdlib/-nostartfiles.
void _init(void)
{
}

View File

@ -48,7 +48,7 @@ static DSTATUS disk_state[CFG_TUSB_HOST_DEVICE_MAX];
static DRESULT wait_for_io_complete(uint8_t usb_addr)
{
// TODO with RTOS, this should use semaphore instead of blocking
while ( tuh_msc_is_busy(usb_addr) )
while ( !tuh_msc_ready(usb_addr) )
{
// TODO should have timeout here
#if CFG_TUSB_OS != OPT_OS_NONE

View File

@ -1,4 +1,4 @@
/*
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@ -277,7 +277,7 @@ typedef struct TU_ATTR_PACKED
struct {
uint8_t handle_call : 1; ///< 0 - Device sends/receives call management information only over the Communications Class interface. 1 - Device can send/receive call management information over a Data Class interface.
uint8_t send_recv_call : 1; ///< 0 - Device does not handle call management itself. 1 - Device handles call management itself.
uint8_t : 0;
uint8_t TU_RESERVED : 6;
} bmCapabilities;
uint8_t bDataInterface;
@ -290,7 +290,7 @@ typedef struct TU_ATTR_PACKED
uint8_t support_line_request : 1; ///< Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State.
uint8_t support_send_break : 1; ///< Device supports the request Send_Break
uint8_t support_notification_network_connection : 1; ///< Device supports the notification Network_Connection.
uint8_t : 0;
uint8_t TU_RESERVED : 4;
}cdc_acm_capability_t;
TU_VERIFY_STATIC(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compiler");
@ -316,7 +316,7 @@ typedef struct TU_ATTR_PACKED
uint8_t require_pulse_setup : 1; ///< Device requires extra Pulse_Setup request during pulse dialing sequence to disengage holding circuit.
uint8_t support_aux_request : 1; ///< Device supports the request combination of Set_Aux_Line_State, Ring_Aux_Jack, and notification Aux_Jack_Hook_State.
uint8_t support_pulse_request : 1; ///< Device supports the request combination of Pulse_Setup, Send_Pulse, and Set_Pulse_Time.
uint8_t : 0;
uint8_t TU_RESERVED : 5;
} bmCapabilities;
}cdc_desc_func_direct_line_management_t;
@ -344,7 +344,7 @@ typedef struct TU_ATTR_PACKED
uint8_t simple_mode : 1;
uint8_t standalone_mode : 1;
uint8_t computer_centric_mode : 1;
uint8_t : 0;
uint8_t TU_RESERVED : 5;
} bmCapabilities;
}cdc_desc_func_telephone_operational_modes_t;
@ -363,7 +363,7 @@ typedef struct TU_ATTR_PACKED
uint32_t incoming_distinctive : 1; ///< 0 : Reports only incoming ringing. 1 : Reports incoming distinctive ringing patterns.
uint32_t dual_tone_multi_freq : 1; ///< 0 : Cannot report dual tone multi-frequency (DTMF) digits input remotely over the telephone line. 1 : Can report DTMF digits input remotely over the telephone line.
uint32_t line_state_change : 1; ///< 0 : Does not support line state change notification. 1 : Does support line state change notification
uint32_t : 0;
uint32_t TU_RESERVED : 26;
} bmCapabilities;
}cdc_desc_func_telephone_call_state_reporting_capabilities_t;

View File

@ -114,15 +114,15 @@ static void _prep_out_transaction (midid_interface_t* p_midi)
//--------------------------------------------------------------------+
// READ API
//--------------------------------------------------------------------+
uint32_t tud_midi_n_available(uint8_t itf, uint8_t jack_id)
uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num)
{
(void) jack_id;
(void) cable_num;
return tu_fifo_count(&_midid_itf[itf].rx_ff);
}
uint32_t tud_midi_n_read(uint8_t itf, uint8_t jack_id, void* buffer, uint32_t bufsize)
uint32_t tud_midi_n_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize)
{
(void) jack_id;
(void) cable_num;
midid_interface_t* midi = &_midid_itf[itf];
// Fill empty buffer
@ -158,9 +158,9 @@ uint32_t tud_midi_n_read(uint8_t itf, uint8_t jack_id, void* buffer, uint32_t bu
return n;
}
void tud_midi_n_read_flush (uint8_t itf, uint8_t jack_id)
void tud_midi_n_read_flush (uint8_t itf, uint8_t cable_num)
{
(void) jack_id;
(void) cable_num;
midid_interface_t* p_midi = &_midid_itf[itf];
tu_fifo_clear(&p_midi->rx_ff);
_prep_out_transaction(p_midi);
@ -205,7 +205,7 @@ static uint32_t write_flush(midid_interface_t* midi)
}
}
uint32_t tud_midi_n_write(uint8_t itf, uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize)
uint32_t tud_midi_n_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize)
{
midid_interface_t* midi = &_midid_itf[itf];
if (midi->itf_num == 0) {
@ -228,7 +228,7 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t jack_id, uint8_t const* buffer, u
midi->write_target_length = 4;
}
} else if ((msg >= 0x8 && msg <= 0xB) || msg == 0xE) {
midi->write_buffer[0] = jack_id << 4 | msg;
midi->write_buffer[0] = cable_num << 4 | msg;
midi->write_target_length = 4;
} else if (msg == 0xf) {
if (data == 0xf0) {
@ -246,7 +246,7 @@ uint32_t tud_midi_n_write(uint8_t itf, uint8_t jack_id, uint8_t const* buffer, u
}
} else {
// Pack individual bytes if we don't support packing them into words.
midi->write_buffer[0] = jack_id << 4 | 0xf;
midi->write_buffer[0] = cable_num << 4 | 0xf;
midi->write_buffer[2] = 0;
midi->write_buffer[3] = 0;
midi->write_buffer_length = 2;

View File

@ -60,13 +60,13 @@
// CFG_TUD_MIDI > 1
//--------------------------------------------------------------------+
bool tud_midi_n_mounted (uint8_t itf);
uint32_t tud_midi_n_available (uint8_t itf, uint8_t jack_id);
uint32_t tud_midi_n_read (uint8_t itf, uint8_t jack_id, void* buffer, uint32_t bufsize);
void tud_midi_n_read_flush (uint8_t itf, uint8_t jack_id);
uint32_t tud_midi_n_write (uint8_t itf, uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize);
uint32_t tud_midi_n_available (uint8_t itf, uint8_t cable_num);
uint32_t tud_midi_n_read (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize);
void tud_midi_n_read_flush (uint8_t itf, uint8_t cable_num);
uint32_t tud_midi_n_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize);
static inline
uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3);
uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3);
bool tud_midi_n_receive (uint8_t itf, uint8_t packet[4]);
bool tud_midi_n_send (uint8_t itf, uint8_t const packet[4]);
@ -78,8 +78,8 @@ static inline bool tud_midi_mounted (void);
static inline uint32_t tud_midi_available (void);
static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize);
static inline void tud_midi_read_flush (void);
static inline uint32_t tud_midi_write (uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize);
static inline uint32_t tudi_midi_write24 (uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3);
static inline uint32_t tud_midi_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize);
static inline uint32_t tud_midi_write24 (uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3);
static inline bool tud_midi_receive (uint8_t packet[4]);
static inline bool tud_midi_send (uint8_t const packet[4]);
@ -92,10 +92,10 @@ TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf);
// Inline Functions
//--------------------------------------------------------------------+
static inline uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3)
static inline uint32_t tud_midi_n_write24 (uint8_t itf, uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3)
{
uint8_t msg[3] = { b1, b2, b3 };
return tud_midi_n_write(itf, jack_id, msg, 3);
return tud_midi_n_write(itf, cable_num, msg, 3);
}
static inline bool tud_midi_mounted (void)
@ -118,15 +118,15 @@ static inline void tud_midi_read_flush (void)
tud_midi_n_read_flush(0, 0);
}
static inline uint32_t tud_midi_write (uint8_t jack_id, uint8_t const* buffer, uint32_t bufsize)
static inline uint32_t tud_midi_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize)
{
return tud_midi_n_write(0, jack_id, buffer, bufsize);
return tud_midi_n_write(0, cable_num, buffer, bufsize);
}
static inline uint32_t tudi_midi_write24 (uint8_t jack_id, uint8_t b1, uint8_t b2, uint8_t b3)
static inline uint32_t tud_midi_write24 (uint8_t cable_num, uint8_t b1, uint8_t b2, uint8_t b3)
{
uint8_t msg[3] = { b1, b2, b3 };
return tud_midi_write(jack_id, msg, 3);
return tud_midi_write(cable_num, msg, 3);
}
static inline bool tud_midi_receive (uint8_t packet[4])

View File

@ -47,14 +47,21 @@ enum
typedef struct
{
uint8_t itf_num;
uint8_t ep_in;
uint8_t ep_out;
uint8_t itf_num;
uint8_t ep_in;
uint8_t ep_out;
uint8_t max_lun;
uint8_t max_lun;
volatile bool mounted;
volatile bool configured; // Receive SET_CONFIGURE
volatile bool mounted; // Enumeration is complete
struct {
uint32_t block_size;
uint32_t block_count;
} capacity[CFG_TUH_MSC_MAXLUN];
//------------- SCSI -------------//
uint8_t stage;
void* buffer;
tuh_msc_complete_cb_t complete_cb;
@ -63,14 +70,15 @@ typedef struct
msc_csw_t csw;
}msch_interface_t;
CFG_TUSB_MEM_SECTION static msch_interface_t msch_data[CFG_TUSB_HOST_DEVICE_MAX];
CFG_TUSB_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUSB_HOST_DEVICE_MAX];
// buffer used to read scsi information when mounted, largest response data currently is inquiry
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msch_buffer[sizeof(scsi_inquiry_resp_t)];
// buffer used to read scsi information when mounted
// largest response data currently is inquiry TODO Inquiry is not part of enum anymore
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)];
static inline msch_interface_t* get_itf(uint8_t dev_addr)
{
return &msch_data[dev_addr-1];
return &_msch_itf[dev_addr-1];
}
//--------------------------------------------------------------------+
@ -82,34 +90,45 @@ uint8_t tuh_msc_get_maxlun(uint8_t dev_addr)
return p_msc->max_lun;
}
uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun)
{
msch_interface_t* p_msc = get_itf(dev_addr);
return p_msc->capacity[lun].block_count;
}
uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun)
{
msch_interface_t* p_msc = get_itf(dev_addr);
return p_msc->capacity[lun].block_size;
}
bool tuh_msc_mounted(uint8_t dev_addr)
{
msch_interface_t* p_msc = get_itf(dev_addr);
// is configured can be omitted
return tuh_device_is_configured(dev_addr) && p_msc->mounted;
return p_msc->mounted;
}
bool tuh_msc_is_busy(uint8_t dev_addr)
bool tuh_msc_ready(uint8_t dev_addr)
{
msch_interface_t* p_msc = get_itf(dev_addr);
return p_msc->mounted && hcd_edpt_busy(dev_addr, p_msc->ep_in);
return p_msc->mounted && !hcd_edpt_busy(dev_addr, p_msc->ep_in);
}
//--------------------------------------------------------------------+
// PUBLIC API: SCSI COMMAND
//--------------------------------------------------------------------+
static inline void msc_cbw_add_signature(msc_cbw_t *p_cbw, uint8_t lun)
static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun)
{
p_cbw->signature = MSC_CBW_SIGNATURE;
p_cbw->tag = 0x54555342; // TUSB
p_cbw->lun = lun;
tu_memclr(cbw, sizeof(msc_cbw_t));
cbw->signature = MSC_CBW_SIGNATURE;
cbw->tag = 0x54555342; // TUSB
cbw->lun = lun;
}
bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb)
{
msch_interface_t* p_msc = get_itf(dev_addr);
// TU_VERIFY(p_msc->mounted); // TODO part of the enumeration also use scsi command
TU_VERIFY(p_msc->configured);
// TODO claim endpoint
@ -125,12 +144,12 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu
bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb)
{
msch_interface_t* p_msc = get_itf(dev_addr);
if ( !p_msc->mounted ) return false;
msch_interface_t* p_msc = get_itf(dev_addr);
TU_VERIFY(p_msc->configured);
msc_cbw_t cbw = { 0 };
msc_cbw_t cbw;
cbw_init(&cbw, lun);
msc_cbw_add_signature(&cbw, lun);
cbw.total_bytes = sizeof(scsi_read_capacity10_resp_t);
cbw.dir = TUSB_DIR_IN_MASK;
cbw.cmd_len = sizeof(scsi_read_capacity10_t);
@ -139,11 +158,14 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb);
}
bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb)
bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb)
{
msc_cbw_t cbw = { 0 };
msch_interface_t* p_msc = get_itf(dev_addr);
TU_VERIFY(p_msc->mounted);
msc_cbw_t cbw;
cbw_init(&cbw, lun);
msc_cbw_add_signature(&cbw, lun);
cbw.total_bytes = sizeof(scsi_inquiry_resp_t);
cbw.dir = TUSB_DIR_IN_MASK;
cbw.cmd_len = sizeof(scsi_inquiry_t);
@ -160,26 +182,29 @@ bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* re
bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb)
{
msc_cbw_t cbw = { 0 };
msc_cbw_add_signature(&cbw, lun);
msch_interface_t* p_msc = get_itf(dev_addr);
TU_VERIFY(p_msc->configured);
cbw.total_bytes = 0; // Number of bytes
cbw.dir = TUSB_DIR_OUT;
cbw.cmd_len = sizeof(scsi_test_unit_ready_t);
cbw.command[0] = SCSI_CMD_TEST_UNIT_READY;
cbw.command[1] = lun; // according to wiki TODO need verification
msc_cbw_t cbw;
cbw_init(&cbw, lun);
cbw.total_bytes = 0;
cbw.dir = TUSB_DIR_OUT;
cbw.cmd_len = sizeof(scsi_test_unit_ready_t);
cbw.command[0] = SCSI_CMD_TEST_UNIT_READY;
cbw.command[1] = lun; // according to wiki TODO need verification
return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb);
}
bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb)
{
msc_cbw_t cbw = { 0 };
msc_cbw_add_signature(&cbw, lun);
msc_cbw_t cbw;
cbw_init(&cbw, lun);
cbw.total_bytes = 18; // TODO sense response
cbw.dir = TUSB_DIR_IN_MASK;
cbw.cmd_len = sizeof(scsi_request_sense_t);
cbw.dir = TUSB_DIR_IN_MASK;
cbw.cmd_len = sizeof(scsi_request_sense_t);
scsi_request_sense_t const cmd_request_sense =
{
@ -192,61 +217,54 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_ms
return tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb);
}
#if 0
tusb_error_t tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * p_buffer, uint32_t lba, uint16_t block_count)
bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb)
{
msch_interface_t* p_msch = &msch_data[dev_addr-1];
msch_interface_t* p_msc = get_itf(dev_addr);
TU_VERIFY(p_msc->mounted);
//------------- Command Block Wrapper -------------//
msc_cbw_add_signature(&p_msch->cbw, lun);
p_msch->cbw.total_bytes = p_msch->block_size*block_count; // Number of bytes
p_msch->cbw.dir = TUSB_DIR_IN_MASK;
p_msch->cbw.cmd_len = sizeof(scsi_read10_t);
//------------- SCSI command -------------//
scsi_read10_t cmd_read10 =msch_sem_hdl
msc_cbw_t cbw;
cbw_init(&cbw, lun);
cbw.total_bytes = block_count*p_msc->capacity[lun].block_size;
cbw.dir = TUSB_DIR_IN_MASK;
cbw.cmd_len = sizeof(scsi_read10_t);
scsi_read10_t const cmd_read10 =
{
.cmd_code = SCSI_CMD_READ_10,
.lba = tu_htonl(lba),
.block_count = tu_htons(block_count)
.cmd_code = SCSI_CMD_READ_10,
.lba = tu_htonl(lba),
.block_count = tu_htons(block_count)
};
memcpy(cbw.command, &cmd_read10, cbw.cmd_len);
return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb);
}
bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb)
{
msch_interface_t* p_msc = get_itf(dev_addr);
TU_VERIFY(p_msc->mounted);
msc_cbw_t cbw;
cbw_init(&cbw, lun);
cbw.total_bytes = block_count*p_msc->capacity[lun].block_size;
cbw.dir = TUSB_DIR_OUT;
cbw.cmd_len = sizeof(scsi_write10_t);
scsi_write10_t const cmd_write10 =
{
.cmd_code = SCSI_CMD_WRITE_10,
.lba = tu_htonl(lba),
.block_count = tu_htons(block_count)
};
memcpy(p_msch->cbw.command, &cmd_read10, p_msch->cbw.cmd_len);
memcpy(cbw.command, &cmd_write10, cbw.cmd_len);
TU_ASSERT_ERR ( send_cbw(dev_addr, p_msch, p_buffer));
return TUSB_ERROR_NONE;
return tuh_msc_scsi_command(dev_addr, &cbw, (void*) buffer, complete_cb);
}
tusb_error_t tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffer, uint32_t lba, uint16_t block_count)
{
msch_interface_t* p_msch = &msch_data[dev_addr-1];
//------------- Command Block Wrapper -------------//
msc_cbw_add_signature(&p_msch->cbw, lun);
p_msch->cbw.total_bytes = p_msch->block_size*block_count; // Number of bytes
p_msch->cbw.dir = TUSB_DIR_OUT;
p_msch->cbw.cmd_len = sizeof(scsi_write10_t);
//------------- SCSI command -------------//
scsi_write10_t cmd_write10 =
{
.cmd_code = SCSI_CMD_WRITE_10,
.lba = tu_htonl(lba),
.block_count = tu_htons(block_count)
};
memcpy(p_msch->cbw.command, &cmd_write10, p_msch->cbw.cmd_len);
TU_ASSERT_ERR ( send_cbw(dev_addr, p_msch, (void*) p_buffer));
return TUSB_ERROR_NONE;
}
#endif
#if 0
// MSC interface Reset (not used now)
bool tuh_msc_reset(uint8_t dev_addr)
@ -273,14 +291,14 @@ bool tuh_msc_reset(uint8_t dev_addr)
//--------------------------------------------------------------------+
void msch_init(void)
{
tu_memclr(msch_data, sizeof(msch_interface_t)*CFG_TUSB_HOST_DEVICE_MAX);
tu_memclr(_msch_itf, sizeof(msch_interface_t)*CFG_TUSB_HOST_DEVICE_MAX);
}
void msch_close(uint8_t dev_addr)
{
msch_interface_t* p_msc = get_itf(dev_addr);
tu_memclr(p_msc, sizeof(msch_interface_t));
tuh_msc_unmounted_cb(dev_addr); // invoke Application Callback
tuh_msc_unmount_cb(dev_addr); // invoke Application Callback
}
bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
@ -337,6 +355,7 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
{
@ -375,6 +394,8 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
msch_interface_t* p_msc = get_itf(dev_addr);
TU_ASSERT(p_msc->itf_num == itf_num);
p_msc->configured = true;
//------------- Get Max Lun -------------//
TU_LOG2("MSC Get Max Lun\r\n");
tusb_control_request_t request =
@ -402,12 +423,13 @@ static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t
msch_interface_t* p_msc = get_itf(dev_addr);
// STALL means zero
p_msc->max_lun = (XFER_RESULT_SUCCESS == result) ? msch_buffer[0] : 0;
p_msc->max_lun = (XFER_RESULT_SUCCESS == result) ? _msch_buffer[0] : 0;
p_msc->max_lun++; // MAX LUN is minus 1 by specs
// TODO multiple LUN support
TU_LOG2("SCSI Test Unit Ready\r\n");
tuh_msc_test_unit_ready(dev_addr, 0, config_test_unit_ready_complete);
uint8_t const lun = 0;
tuh_msc_test_unit_ready(dev_addr, lun, config_test_unit_ready_complete);
return true;
}
@ -416,19 +438,16 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* c
{
if (csw->status == 0)
{
msch_interface_t* p_msc = get_itf(dev_addr);
usbh_driver_set_config_complete(dev_addr, p_msc->itf_num);
// Unit is ready, Enumeration is complete
p_msc->mounted = true;
tuh_msc_mounted_cb(dev_addr);
// Unit is ready, read its capacity
TU_LOG2("SCSI Read Capacity\r\n");
tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) _msch_buffer, config_read_capacity_complete);
}else
{
// Note: During enumeration, some device fails Test Unit Ready and require a few retries
// with Request Sense to start working !!
// TODO limit number of retries
TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, msch_buffer, config_request_sense_complete));
TU_LOG2("SCSI Request Sense\r\n");
TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete));
}
return true;
@ -441,4 +460,24 @@ static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw
return true;
}
static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
{
TU_ASSERT(csw->status == 0);
msch_interface_t* p_msc = get_itf(dev_addr);
// Capacity response field: Block size and Last LBA are both Big-Endian
scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) _msch_buffer;
p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1;
p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size);
// Mark enumeration is complete
p_msc->mounted = true;
tuh_msc_mount_cb(dev_addr);
usbh_driver_set_config_complete(dev_addr, p_msc->itf_num);
return true;
}
#endif

View File

@ -35,6 +35,15 @@
extern "C" {
#endif
//--------------------------------------------------------------------+
// Class Driver Configuration
//--------------------------------------------------------------------+
#ifndef CFG_TUH_MSC_MAXLUN
#define CFG_TUH_MSC_MAXLUN 4
#endif
/** \addtogroup ClassDriver_MSC
* @{
* \defgroup MSC_Host Host
@ -51,73 +60,56 @@ typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, ms
// This function true after tuh_msc_mounted_cb() and false after tuh_msc_unmounted_cb()
bool tuh_msc_mounted(uint8_t dev_addr);
/** \brief Check if the interface is currently busy or not
* \param[in] dev_addr device address
* \retval true if the interface is busy meaning the stack is still transferring/waiting data from/to device
* \retval false if the interface is not busy meaning the stack successfully transferred data from/to device
* \note This function is used to check if previous transfer is complete (success or error), so that the next transfer
* can be scheduled. User needs to make sure the corresponding interface is mounted (by \ref tuh_msc_is_mounted)
* before calling this function
*/
bool tuh_msc_is_busy(uint8_t dev_addr);
// Check if the interface is currently ready or busy transferring data
bool tuh_msc_ready(uint8_t dev_addr);
// Get Max Lun
uint8_t tuh_msc_get_maxlun(uint8_t dev_addr);
// Carry out a full SCSI command (cbw, data, csw) in non-blocking manner.
// `complete_cb` callback is invoked when SCSI op is complete.
// Get number of block
uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun);
// Get block size in bytes
uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun);
// Perform a full SCSI command (cbw, data, csw) in non-blocking manner.
// Complete callback is invoked when SCSI op is complete.
// return true if success, false if there is already pending operation.
bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb);
// Carry out SCSI INQUIRY command in non-blocking manner.
bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb);
// Perform SCSI Inquiry command
// Complete callback is invoked when SCSI op is complete.
bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb);
// Carry out SCSI REQUEST SENSE (10) command in non-blocking manner.
// Perform SCSI Test Unit Ready command
// Complete callback is invoked when SCSI op is complete.
bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb);
// Carry out SCSI REQUEST SENSE (10) command in non-blocking manner.
// Perform SCSI Request Sense 10 command
// Complete callback is invoked when SCSI op is complete.
bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb);
// Carry out SCSI READ CAPACITY (10) command in non-blocking manner.
// Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer
// Complete callback is invoked when SCSI op is complete.
bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb);
// Perform SCSI Write 10 command. Write n blocks starting from LBA to device
// Complete callback is invoked when SCSI op is complete.
bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb);
// Perform SCSI Read Capacity 10 command
// Complete callback is invoked when SCSI op is complete.
// Note: during enumeration, host stack already carried out this request. Application can retrieve capacity by
// simply call tuh_msc_get_block_count() and tuh_msc_get_block_size()
bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb);
#if 0
/** \brief Perform SCSI READ 10 command to read data from MassStorage device
* \param[in] dev_addr device address
* \param[in] lun Targeted Logical Unit
* \param[out] p_buffer Buffer used to store data read from device. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION)
* \param[in] lba Starting Logical Block Address to be read
* \param[in] block_count Number of Block to be read
* \retval TUSB_ERROR_NONE on success
* \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device
* \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request)
* \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct
* \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the interface's callback function
*/
tusb_error_t tuh_msc_read10 (uint8_t dev_addr, uint8_t lun, void * p_buffer, uint32_t lba, uint16_t block_count);
/** \brief Perform SCSI WRITE 10 command to write data to MassStorage device
* \param[in] dev_addr device address
* \param[in] lun Targeted Logical Unit
* \param[in] p_buffer Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION)
* \param[in] lba Starting Logical Block Address to be written
* \param[in] block_count Number of Block to be written
* \retval TUSB_ERROR_NONE on success
* \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device
* \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request)
* \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct
* \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the interface's callback function
*/
tusb_error_t tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffer, uint32_t lba, uint16_t block_count);
#endif
//------------- Application Callback -------------//
// Invoked when a device with MassStorage interface is mounted
void tuh_msc_mounted_cb(uint8_t dev_addr);
void tuh_msc_mount_cb(uint8_t dev_addr);
// Invoked when a device with MassStorage interface is unmounted
void tuh_msc_unmounted_cb(uint8_t dev_addr);
void tuh_msc_unmount_cb(uint8_t dev_addr);
//--------------------------------------------------------------------+
// Internal Class Driver API

View File

@ -808,6 +808,8 @@ bool tu_fifo_clear(tu_fifo_t *f)
{
tu_fifo_lock(f);
f->rd_idx = f->wr_idx = 0;
f->max_pointer_idx = 2*f->depth-1;
f->non_used_index_space = UINT16_MAX - f->max_pointer_idx;
tu_fifo_unlock(f);
return true;

View File

@ -91,18 +91,22 @@ typedef struct
} tu_fifo_t;
#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
tu_fifo_t _name = { \
.buffer = _name##_buf, \
.depth = _depth, \
.item_size = sizeof(_type), \
.overwritable = _overwritable, \
.max_pointer_idx = 2*_depth-1, \
.non_used_index_space = UINT16_MAX - (2*_depth-1), \
.wr_mode = TU_FIFO_COPY_INC, \
.rd_mode = TU_FIFO_COPY_INC, \
}
#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \
{ \
.buffer = _buffer, \
.depth = _depth, \
.item_size = sizeof(_type), \
.overwritable = _overwritable, \
.max_pointer_idx = 2*(_depth)-1, \
.non_used_index_space = UINT16_MAX - (2*(_depth)-1) \
.wr_mode = TU_FIFO_COPY_INC, \
.rd_mode = TU_FIFO_COPY_INC, \
}
#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable)
bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable);
bool tu_fifo_clear(tu_fifo_t *f);

View File

@ -1,4 +1,4 @@
/*
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@ -342,7 +342,7 @@ typedef struct TU_ATTR_PACKED
struct TU_ATTR_PACKED {
uint16_t size : 11; ///< Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. \n For isochronous endpoints, this value is used to reserve the bus time in the schedule, required for the per-(micro)frame data payloads. The pipe may, on an ongoing basis, actually use less bandwidth than that reserved. The device reports, if necessary, the actual bandwidth used via its normal, non-USB defined mechanisms. \n For all endpoints, bits 10..0 specify the maximum packet size (in bytes). \n For high-speed isochronous and interrupt endpoints: \n Bits 12..11 specify the number of additional transaction opportunities per microframe: \n- 00 = None (1 transaction per microframe) \n- 01 = 1 additional (2 per microframe) \n- 10 = 2 additional (3 per microframe) \n- 11 = Reserved \n Bits 15..13 are reserved and must be set to zero.
uint16_t hs_period_mult : 2;
uint16_t : 0;
uint16_t TU_RESERVED : 3;
}wMaxPacketSize;
uint8_t bInterval ; ///< Interval for polling endpoint for data transfers. Expressed in frames or microframes depending on the device operating speed (i.e., either 1 millisecond or 125 us units). \n- For full-/high-speed isochronous endpoints, this value must be in the range from 1 to 16. The bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$). \n- For full-/low-speed interrupt endpoints, the value of this field may be from 1 to 255. \n- For high-speed interrupt endpoints, the bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$) . This value must be from 1 to 16. \n- For high-speed bulk/control OUT endpoints, the bInterval must specify the maximum NAK rate of the endpoint. A value of 0 indicates the endpoint never NAKs. Other values indicate at most 1 NAK each bInterval number of microframes. This value must be in the range from 0 to 255. \n Refer to Chapter 5 of USB 2.0 specification for more information.

View File

@ -98,7 +98,7 @@ enum {
//--------------------------------------------------------------------+
// Controller & Port API
//--------------------------------------------------------------------+
bool hcd_init(void);
bool hcd_init(uint8_t rhport);
void hcd_int_handler(uint8_t rhport);
void hcd_int_enable (uint8_t rhport);
void hcd_int_disable(uint8_t rhport);

View File

@ -1,4 +1,4 @@
/*
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@ -163,7 +163,7 @@ typedef struct {
uint16_t high_speed : 1;
uint16_t port_test_mode : 1;
uint16_t port_indicator_control : 1;
uint16_t : 0;
uint16_t TU_RESERVED : 3;
};
uint16_t value;

View File

@ -197,7 +197,7 @@ bool tuh_init(void)
usbh_class_drivers[drv_id].init();
}
TU_ASSERT(hcd_init());
TU_ASSERT(hcd_init(TUH_OPT_RHPORT));
hcd_int_enable(TUH_OPT_RHPORT);
return true;

View File

@ -130,18 +130,11 @@ typedef struct
typedef osal_queue_def_t* osal_queue_t;
// role device/host is used by OS NONE for mutex (disable usb isr) only
#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
osal_queue_def_t _name = { \
.role = _role, \
.ff = { \
.buffer = _name##_buf, \
.depth = _depth, \
.item_size = sizeof(_type), \
.overwritable = false, \
.max_pointer_idx = (2*(_depth))-1, \
.non_used_index_space = UINT16_MAX - (2*_depth-1),\
}\
#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
osal_queue_def_t _name = { \
.role = _role, \
.ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
}
// lock queue by disable USB interrupt

View File

@ -115,17 +115,10 @@ typedef struct
typedef osal_queue_def_t* osal_queue_t;
// role device/host is used by OS NONE for mutex (disable usb isr) only
#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
osal_queue_def_t _name = { \
.ff = { \
.buffer = _name##_buf, \
.depth = _depth, \
.item_size = sizeof(_type), \
.overwritable = false, \
.max_pointer_idx = 2*_depth-1, \
.non_used_index_space = UINT16_MAX - (2*_depth-1), \
}\
#define OSAL_QUEUE_DEF(_role, _name, _depth, _type) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
osal_queue_def_t _name = { \
.ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
}
// lock queue by disable USB interrupt

View File

@ -26,14 +26,17 @@
#include "common/tusb_common.h"
#if TUSB_OPT_HOST_ENABLED && (CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX)
#if TUSB_OPT_HOST_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || \
CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX )
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "osal/osal.h"
#include "../hcd.h"
#include "../usbh_hcd.h"
#include "host/hcd.h"
#include "host/usbh_hcd.h"
#include "ehci.h"
//--------------------------------------------------------------------+
@ -48,6 +51,7 @@ CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4096) static ehci_data_t ehci_data;
// EHCI portable
uint32_t hcd_ehci_register_addr(uint8_t rhport);
bool hcd_ehci_init (uint8_t rhport); // TODO move later
//--------------------------------------------------------------------+
// PROTOTYPE
@ -97,16 +101,9 @@ static void qtd_init (ehci_qtd_t* p_qtd, void* buffer, uint16_t total_bytes);
static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
static inline ehci_link_t* list_next (ehci_link_t *p_link_pointer);
static bool ehci_init (uint8_t rhport);
//--------------------------------------------------------------------+
// HCD API
//--------------------------------------------------------------------+
bool hcd_init(void)
{
tu_memclr(&ehci_data, sizeof(ehci_data_t));
return ehci_init(TUH_OPT_RHPORT);
}
uint32_t hcd_uframe_number(uint8_t rhport)
{
@ -203,8 +200,10 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
}
// EHCI controller init
static bool ehci_init(uint8_t rhport)
bool hcd_ehci_init(uint8_t rhport)
{
tu_memclr(&ehci_data, sizeof(ehci_data_t));
ehci_data.regs = (ehci_registers_t* ) hcd_ehci_register_addr(rhport);
ehci_registers_t* regs = ehci_data.regs;

View File

@ -1,4 +1,4 @@
/*
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@ -33,8 +33,6 @@
#ifndef _TUSB_EHCI_H_
#define _TUSB_EHCI_H_
#include "common/tusb_common.h"
#include "../hcd.h"
/* Abbreviation
* HC: Host Controller
@ -231,7 +229,6 @@ typedef struct TU_ATTR_ALIGNED(32)
uint32_t : 1; ///< reserved
uint32_t port_number : 7; ///< This field is the port number of the recipient transaction translator.
uint32_t direction : 1; ///< 0 = OUT; 1 = IN. This field encodes whether the full-speed transaction should be an IN or OUT.
uint32_t : 0; // padding to the end of current storage unit
// Word 2: Micro-frame Schedule Control
uint8_t int_smask ; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute complete-split transactions
@ -423,7 +420,7 @@ typedef volatile struct
uint32_t nxp_port_force_fullspeed : 1; ///< NXP customized: Writing this bit to a 1 will force the port to only connect at Full Speed. It disables the chirp sequence that allowsthe port to identify itself as High Speed. This is useful for testing FS configurations with a HS host, hub or device.
uint32_t : 1;
uint32_t nxp_port_speed : 2; ///< NXP customized: This register field indicates the speed atwhich the port is operating. For HS mode operation in the host controllerand HS/FS operation in the device controller the port routing steers data to the Protocol engine. For FS and LS mode operation in the host controller, the port routing steers data to the Protocol Engine w/ Embedded Transaction Translator. 0x0: Fullspeed, 0x1: Lowspeed, 0x2: Highspeed
uint32_t : 0; // padding to the boundary of storage unit
uint32_t TU_RESERVED : 4;
}portsc_bm;
};
}ehci_registers_t;
@ -461,4 +458,3 @@ typedef struct
/** @} */
/** @} */

View File

@ -1,50 +0,0 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
#include "tusb_option.h"
#if TUSB_OPT_HOST_ENABLED && (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX)
#include "chip.h"
// LPC18xx and 43xx use EHCI driver
void hcd_int_enable(uint8_t rhport)
{
NVIC_EnableIRQ(rhport ? USB1_IRQn : USB0_IRQn);
}
void hcd_int_disable(uint8_t rhport)
{
NVIC_DisableIRQ(rhport ? USB1_IRQn : USB0_IRQn);
}
uint32_t hcd_ehci_register_addr(uint8_t rhport)
{
return (uint32_t) (rhport ? &LPC_USB1->USBCMD_H : &LPC_USB0->USBCMD_H );
}
#endif

View File

@ -0,0 +1,136 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021, 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.
*
* This file is part of the TinyUSB stack.
*/
#ifndef COMMON_TRANSDIMENSION_H_
#define COMMON_TRANSDIMENSION_H_
#ifdef __cplusplus
extern "C" {
#endif
// USBCMD
enum {
USBCMD_RUN_STOP = TU_BIT(0),
USBCMD_RESET = TU_BIT(1),
USBCMD_SETUP_TRIPWIRE = TU_BIT(13),
USBCMD_ADD_QTD_TRIPWIRE = TU_BIT(14) ///< This bit is used as a semaphore to ensure the to proper addition of a new dTD to an active (primed) endpoints linked list. This bit is set and cleared by software during the process of adding a new dTD
// Interrupt Threshold bit 23:16
};
// PORTSC1
#define PORTSC1_PORT_SPEED_POS 26
enum {
PORTSC1_CURRENT_CONNECT_STATUS = TU_BIT(0),
PORTSC1_FORCE_PORT_RESUME = TU_BIT(6),
PORTSC1_SUSPEND = TU_BIT(7),
PORTSC1_FORCE_FULL_SPEED = TU_BIT(24),
PORTSC1_PORT_SPEED = TU_BIT(26) | TU_BIT(27)
};
// OTGSC
enum {
OTGSC_VBUS_DISCHARGE = TU_BIT(0),
OTGSC_VBUS_CHARGE = TU_BIT(1),
// OTGSC_HWASSIST_AUTORESET = TU_BIT(2),
OTGSC_OTG_TERMINATION = TU_BIT(3), ///< Must set to 1 when OTG go to device mode
OTGSC_DATA_PULSING = TU_BIT(4),
OTGSC_ID_PULLUP = TU_BIT(5),
// OTGSC_HWASSIT_DATA_PULSE = TU_BIT(6),
// OTGSC_HWASSIT_BDIS_ACONN = TU_BIT(7),
OTGSC_ID = TU_BIT(8), ///< 0 = A device, 1 = B Device
OTGSC_A_VBUS_VALID = TU_BIT(9),
OTGSC_A_SESSION_VALID = TU_BIT(10),
OTGSC_B_SESSION_VALID = TU_BIT(11),
OTGSC_B_SESSION_END = TU_BIT(12),
OTGSC_1MS_TOGGLE = TU_BIT(13),
OTGSC_DATA_BUS_PULSING_STATUS = TU_BIT(14),
};
// USBMode
enum {
USBMODE_CM_DEVICE = 2,
USBMODE_CM_HOST = 3,
USBMODE_SLOM = TU_BIT(3),
USBMODE_SDIS = TU_BIT(4),
USBMODE_VBUS_POWER_SELECT = TU_BIT(5), // Need to be enabled for LPC18XX/43XX in host mode
};
// Device Registers
typedef struct
{
//------------- ID + HW Parameter Registers-------------//
__I uint32_t TU_RESERVED[64]; ///< For iMX RT10xx, but not used by LPC18XX/LPC43XX
//------------- Capability Registers-------------//
__I uint8_t CAPLENGTH; ///< Capability Registers Length
__I uint8_t TU_RESERVED[1];
__I uint16_t HCIVERSION; ///< Host Controller Interface Version
__I uint32_t HCSPARAMS; ///< Host Controller Structural Parameters
__I uint32_t HCCPARAMS; ///< Host Controller Capability Parameters
__I uint32_t TU_RESERVED[5];
__I uint16_t DCIVERSION; ///< Device Controller Interface Version
__I uint8_t TU_RESERVED[2];
__I uint32_t DCCPARAMS; ///< Device Controller Capability Parameters
__I uint32_t TU_RESERVED[6];
//------------- Operational Registers -------------//
__IO uint32_t USBCMD; ///< USB Command Register
__IO uint32_t USBSTS; ///< USB Status Register
__IO uint32_t USBINTR; ///< Interrupt Enable Register
__IO uint32_t FRINDEX; ///< USB Frame Index
__I uint32_t TU_RESERVED;
__IO uint32_t DEVICEADDR; ///< Device Address
__IO uint32_t ENDPTLISTADDR; ///< Endpoint List Address
__I uint32_t TU_RESERVED;
__IO uint32_t BURSTSIZE; ///< Programmable Burst Size
__IO uint32_t TXFILLTUNING; ///< TX FIFO Fill Tuning
uint32_t TU_RESERVED[4];
__IO uint32_t ENDPTNAK; ///< Endpoint NAK
__IO uint32_t ENDPTNAKEN; ///< Endpoint NAK Enable
__I uint32_t TU_RESERVED;
__IO uint32_t PORTSC1; ///< Port Status & Control
__I uint32_t TU_RESERVED[7];
__IO uint32_t OTGSC; ///< On-The-Go Status & control
__IO uint32_t USBMODE; ///< USB Device Mode
__IO uint32_t ENDPTSETUPSTAT; ///< Endpoint Setup Status
__IO uint32_t ENDPTPRIME; ///< Endpoint Prime
__IO uint32_t ENDPTFLUSH; ///< Endpoint Flush
__I uint32_t ENDPTSTAT; ///< Endpoint Status
__IO uint32_t ENDPTCOMPLETE; ///< Endpoint Complete
__IO uint32_t ENDPTCTRL[8]; ///< Endpoint Control 0 - 7
} dcd_registers_t;
#ifdef __cplusplus
}
#endif
#endif /* COMMON_TRANSDIMENSION_H_ */

View File

@ -26,16 +26,12 @@
#include "tusb_option.h"
#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_LPC18XX || \
CFG_TUSB_MCU == OPT_MCU_LPC43XX || \
CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
#if TUSB_OPT_DEVICE_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "common/tusb_common.h"
#include "device/dcd.h"
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
#include "fsl_device_registers.h"
#else
@ -43,6 +39,10 @@
#include "chip.h"
#endif
#include "common/tusb_common.h"
#include "device/dcd.h"
#include "common_transdimension.h"
#if defined(__CORTEX_M) && __CORTEX_M == 7 && __DCACHE_PRESENT == 1
#define CleanInvalidateDCache_by_Addr SCB_CleanInvalidateDCache_by_Addr
#else
@ -61,15 +61,6 @@ enum {
ENDPTCTRL_ENABLE = TU_BIT(7)
};
// USBCMD
enum {
USBCMD_RUN_STOP = TU_BIT(0),
USBCMD_RESET = TU_BIT(1),
USBCMD_SETUP_TRIPWIRE = TU_BIT(13),
USBCMD_ADD_QTD_TRIPWIRE = TU_BIT(14) ///< This bit is used as a semaphore to ensure the to proper addition of a new dTD to an active (primed) endpoints linked list. This bit is set and cleared by software during the process of adding a new dTD
};
// Interrupt Threshold bit 23:16
// USBSTS, USBINTR
enum {
INTR_USB = TU_BIT(0),
@ -81,96 +72,6 @@ enum {
INTR_NAK = TU_BIT(16)
};
// PORTSC1
#define PORTSC1_PORT_SPEED_POS 26
enum {
PORTSC1_CURRENT_CONNECT_STATUS = TU_BIT(0),
PORTSC1_FORCE_PORT_RESUME = TU_BIT(6),
PORTSC1_SUSPEND = TU_BIT(7),
PORTSC1_FORCE_FULL_SPEED = TU_BIT(24),
PORTSC1_PORT_SPEED = TU_BIT(26) | TU_BIT(27)
};
// OTGSC
enum {
OTGSC_VBUS_DISCHARGE = TU_BIT(0),
OTGSC_VBUS_CHARGE = TU_BIT(1),
// OTGSC_HWASSIST_AUTORESET = TU_BIT(2),
OTGSC_OTG_TERMINATION = TU_BIT(3), ///< Must set to 1 when OTG go to device mode
OTGSC_DATA_PULSING = TU_BIT(4),
OTGSC_ID_PULLUP = TU_BIT(5),
// OTGSC_HWASSIT_DATA_PULSE = TU_BIT(6),
// OTGSC_HWASSIT_BDIS_ACONN = TU_BIT(7),
OTGSC_ID = TU_BIT(8), ///< 0 = A device, 1 = B Device
OTGSC_A_VBUS_VALID = TU_BIT(9),
OTGSC_A_SESSION_VALID = TU_BIT(10),
OTGSC_B_SESSION_VALID = TU_BIT(11),
OTGSC_B_SESSION_END = TU_BIT(12),
OTGSC_1MS_TOGGLE = TU_BIT(13),
OTGSC_DATA_BUS_PULSING_STATUS = TU_BIT(14),
};
// USBMode
enum {
USBMODE_CM_DEVICE = 2,
USBMODE_CM_HOST = 3,
USBMODE_SLOM = TU_BIT(3),
USBMODE_SDIS = TU_BIT(4),
USBMODE_VBUS_POWER_SELCT = TU_BIT(5), // Enable for LPC18XX/43XX in host most only
};
// Device Registers
typedef struct
{
//------------- ID + HW Parameter Registers-------------//
__I uint32_t TU_RESERVED[64]; ///< For iMX RT10xx, but not used by LPC18XX/LPC43XX
//------------- Capability Registers-------------//
__I uint8_t CAPLENGTH; ///< Capability Registers Length
__I uint8_t TU_RESERVED[1];
__I uint16_t HCIVERSION; ///< Host Controller Interface Version
__I uint32_t HCSPARAMS; ///< Host Controller Structural Parameters
__I uint32_t HCCPARAMS; ///< Host Controller Capability Parameters
__I uint32_t TU_RESERVED[5];
__I uint16_t DCIVERSION; ///< Device Controller Interface Version
__I uint8_t TU_RESERVED[2];
__I uint32_t DCCPARAMS; ///< Device Controller Capability Parameters
__I uint32_t TU_RESERVED[6];
//------------- Operational Registers -------------//
__IO uint32_t USBCMD; ///< USB Command Register
__IO uint32_t USBSTS; ///< USB Status Register
__IO uint32_t USBINTR; ///< Interrupt Enable Register
__IO uint32_t FRINDEX; ///< USB Frame Index
__I uint32_t TU_RESERVED;
__IO uint32_t DEVICEADDR; ///< Device Address
__IO uint32_t ENDPTLISTADDR; ///< Endpoint List Address
__I uint32_t TU_RESERVED;
__IO uint32_t BURSTSIZE; ///< Programmable Burst Size
__IO uint32_t TXFILLTUNING; ///< TX FIFO Fill Tuning
uint32_t TU_RESERVED[4];
__IO uint32_t ENDPTNAK; ///< Endpoint NAK
__IO uint32_t ENDPTNAKEN; ///< Endpoint NAK Enable
__I uint32_t TU_RESERVED;
__IO uint32_t PORTSC1; ///< Port Status & Control
__I uint32_t TU_RESERVED[7];
__IO uint32_t OTGSC; ///< On-The-Go Status & control
__IO uint32_t USBMODE; ///< USB Device Mode
__IO uint32_t ENDPTSETUPSTAT; ///< Endpoint Setup Status
__IO uint32_t ENDPTPRIME; ///< Endpoint Prime
__IO uint32_t ENDPTFLUSH; ///< Endpoint Flush
__I uint32_t ENDPTSTAT; ///< Endpoint Status
__IO uint32_t ENDPTCOMPLETE; ///< Endpoint Complete
__IO uint32_t ENDPTCTRL[8]; ///< Endpoint Control 0 - 7
} dcd_registers_t;
// Queue Transfer Descriptor
typedef struct
{
@ -280,7 +181,7 @@ CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
static dcd_data_t _dcd_data;
//--------------------------------------------------------------------+
// CONTROLLER API
// Controller API
//--------------------------------------------------------------------+
/// follows LPC43xx User Manual 23.10.3

View File

@ -0,0 +1,127 @@
/*
* 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.
*
* This file is part of the TinyUSB stack.
*/
#include "tusb_option.h"
// NXP Trans-Dimension USB IP implement EHCI for host functionality
#if TUSB_OPT_HOST_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX)
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
#include "fsl_device_registers.h"
#else
// LPCOpen for 18xx & 43xx
#include "chip.h"
#endif
#include "common/tusb_common.h"
#include "common_transdimension.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
// TODO can be merged with dcd_controller_t
typedef struct
{
uint32_t regs_base; // registers base
const IRQn_Type irqnum; // IRQ number
}hcd_controller_t;
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
static const hcd_controller_t _hcd_controller[] =
{
// RT1010 and RT1020 only has 1 USB controller
#if FSL_FEATURE_SOC_USBHS_COUNT == 1
{ .regs_base = USB_BASE , .irqnum = USB_OTG1_IRQn }
#else
{ .regs_base = USB1_BASE, .irqnum = USB_OTG1_IRQn },
{ .regs_base = USB2_BASE, .irqnum = USB_OTG2_IRQn }
#endif
};
#else
static const hcd_controller_t _hcd_controller[] =
{
{ .regs_base = LPC_USB0_BASE, .irqnum = USB0_IRQn },
{ .regs_base = LPC_USB1_BASE, .irqnum = USB1_IRQn }
};
#endif
// TODO better prototype later
extern bool hcd_ehci_init (uint8_t rhport); // from ehci.c
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
bool hcd_init(uint8_t rhport)
{
dcd_registers_t* dcd_reg = (dcd_registers_t*) _hcd_controller[rhport].regs_base;
// Reset controller
dcd_reg->USBCMD |= USBCMD_RESET;
while( dcd_reg->USBCMD & USBCMD_RESET ) {}
// Set mode to device, must be set immediately after reset
#if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX
// LPC18XX/43XX need to set VBUS Power Select to HIGH
// RHPORT1 is fullspeed only (need external PHY for Highspeed)
dcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
if (rhport == 1) dcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
#else
dcd_reg->USBMODE = USBMODE_CM_HOST;
#endif
// FIXME force full speed, still have issue with Highspeed enumeration
dcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
return hcd_ehci_init(rhport);
}
void hcd_int_enable(uint8_t rhport)
{
NVIC_EnableIRQ(_hcd_controller[rhport].irqnum);
}
void hcd_int_disable(uint8_t rhport)
{
NVIC_DisableIRQ(_hcd_controller[rhport].irqnum);
}
uint32_t hcd_ehci_register_addr(uint8_t rhport)
{
dcd_registers_t* hcd_reg = (dcd_registers_t*) _hcd_controller[rhport].regs_base;
// EHCI USBCMD has same address within dcd_register_t
return (uint32_t) &hcd_reg->USBCMD;
}
#endif

View File

@ -26,14 +26,16 @@
#include <common/tusb_common.h>
#if TUSB_OPT_HOST_ENABLED && (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
#if TUSB_OPT_HOST_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "osal/osal.h"
#include "../hcd.h"
#include "../usbh_hcd.h"
#include "host/hcd.h"
#include "host/usbh_hcd.h"
#include "ohci.h"
// TODO remove
@ -141,8 +143,10 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr);
// USBH-HCD API
//--------------------------------------------------------------------+
// Initialization according to 5.1.1.4
bool hcd_init(void)
bool hcd_init(uint8_t rhport)
{
(void) rhport;
//------------- Data Structure init -------------//
tu_memclr(&ohci_data, sizeof(ohci_data_t));
for(uint8_t i=0; i<32; i++)

View File

@ -1,4 +1,4 @@
/*
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@ -37,8 +37,6 @@
extern "C" {
#endif
#include "common/tusb_common.h"
//--------------------------------------------------------------------+
// OHCI CONFIGURATION & CONSTANTS
//--------------------------------------------------------------------+
@ -208,7 +206,7 @@ typedef volatile struct
uint32_t interrupt_routing : 1;
uint32_t remote_wakeup_connected : 1;
uint32_t remote_wakeup_enale : 1;
uint32_t : 0;
uint32_t TU_RESERVED : 21;
}control_bit;
};
@ -276,7 +274,7 @@ typedef volatile struct
uint32_t port_suspend_status_change : 1;
uint32_t port_over_current_indicator_change : 1;
uint32_t port_reset_status_change : 1;
uint32_t : 0;
uint32_t TU_RESERVED : 11;
}rhport_status_bit[2];
};
}ohci_registers_t;

View File

@ -153,8 +153,7 @@ void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t t
// Fill in info now that we're kicking off the hw
ep->total_len = total_len;
ep->len = 0;
// FIXME: What if low speed
ep->transfer_size = total_len > 64 ? 64 : total_len;
ep->transfer_size = tu_min32(total_len, ep->wMaxPacketSize);
ep->active = true;
ep->user_buf = buffer;
// Recalculate if this is the last buffer
@ -232,7 +231,7 @@ bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep)
// Now we have synced our state with the hardware. Is there more data to transfer?
uint remaining_bytes = ep->total_len - ep->len;
ep->transfer_size = remaining_bytes > 64 ? 64 : remaining_bytes;
ep->transfer_size = tu_min32(remaining_bytes, ep->wMaxPacketSize);
_hw_endpoint_update_last_buf(ep);
// Can happen because of programmer error so check for it

View File

@ -155,7 +155,24 @@ static void _dcd_disconnect(FAR struct usbdevclass_driver_s *driver, FAR struct
{
(void) driver;
tusb_speed_t speed = (dev->speed == 3) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL;
tusb_speed_t speed;
switch (dev->speed)
{
case USB_SPEED_LOW:
speed = TUSB_SPEED_LOW;
break;
case USB_SPEED_FULL:
speed = TUSB_SPEED_FULL;
break;
case USB_SPEED_HIGH:
speed = TUSB_SPEED_HIGH;
break;
default:
speed = TUSB_SPEED_HIGH;
break;
}
dcd_event_bus_reset(0, speed, true);
DEV_CONNECT(dev);
}