diff --git a/examples/peripherals/usb/host/msc/README.md b/examples/peripherals/usb/host/msc/README.md index 934ba54771..ad2f782401 100644 --- a/examples/peripherals/usb/host/msc/README.md +++ b/examples/peripherals/usb/host/msc/README.md @@ -6,7 +6,8 @@ ## Overview This example demonstrates usage of Mass Storage Class to get access to storage on USB memory stick. -Example caries out read and write file operations, as USB storage is mounted to Virtual filesystem. +Upon connection of USB stick, storage is mounted to Virtual filesystem. Example then creates `ESP` subdirectory(if not present already), as well as `text.txt` file. Its content is then repetitively printed to monitor until USB stick is manually ejected. User can decide whether or not to deinitialize the whole +USB stack or not by shorting GPIO10 to ground. When GPIO10 is left unconnected USB stack is not deinitialized, USB stick can be plugged-in again. ### Hardware Required @@ -29,6 +30,8 @@ ESP BOARD USB CONNECTOR (type A) -- ``` +Additionally, GPIO10 can be shorted to ground in order to deinitialize USB stack after ejecting USB stick. + ### Build and Flash Build the project and flash it to the board, then run monitor tool to view serial output: diff --git a/examples/peripherals/usb/host/msc/main/msc_example_main.c b/examples/peripherals/usb/host/msc/main/msc_example_main.c index 4a3d7371dd..f7e4abc875 100644 --- a/examples/peripherals/usb/host/msc/main/msc_example_main.c +++ b/examples/peripherals/usb/host/msc/main/msc_example_main.c @@ -1,17 +1,15 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD * - * SPDX-License-Identifier: Apache-2.0 + * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ -#include #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "freertos/queue.h" -#include "freertos/semphr.h" +#include "freertos/event_groups.h" #include "esp_err.h" #include "esp_log.h" #include "usb/usb_host.h" @@ -22,20 +20,34 @@ #include "esp_vfs.h" #include "errno.h" #include "hal/usb_hal.h" +#include "driver/gpio.h" +#include -static const char* TAG = "example"; +#define USB_DISCONNECT_PIN GPIO_NUM_10 -static QueueHandle_t app_queue; -static SemaphoreHandle_t ready_to_uninstall_usb; +#define READY_TO_UNINSTALL (HOST_NO_CLIENT | HOST_ALL_FREE) + +typedef enum { + HOST_NO_CLIENT = 0x1, + HOST_ALL_FREE = 0x2, + DEVICE_CONNECTED = 0x4, + DEVICE_DISCONNECTED = 0x8, + DEVICE_ADDRESS_MASK = 0xFF0, +} app_event_t; + +static const char *TAG = "example"; +static EventGroupHandle_t usb_flags; static void msc_event_cb(const msc_host_event_t *event, void *arg) { if (event->event == MSC_DEVICE_CONNECTED) { ESP_LOGI(TAG, "MSC device connected"); + // Obtained USB device address is placed after application events + xEventGroupSetBits(usb_flags, DEVICE_CONNECTED | (event->device.address << 4)); } else if (event->event == MSC_DEVICE_DISCONNECTED) { + xEventGroupSetBits(usb_flags, DEVICE_DISCONNECTED); ESP_LOGI(TAG, "MSC device disconnected"); } - xQueueSend(app_queue, event, 10); } static void print_device_info(msc_host_device_info_t *info) @@ -54,6 +66,12 @@ static void print_device_info(msc_host_device_info_t *info) wprintf(L"\t iSerialNumber: %S \n", info->iSerialNumber); } +static bool file_exists(const char *file_path) +{ + struct stat buffer; + return stat(file_path, &buffer) == 0; +} + static void file_operations(void) { const char *directory = "/usb/esp"; @@ -67,15 +85,18 @@ static void file_operations(void) } } - ESP_LOGI(TAG, "Writing file"); - FILE *f = fopen(file_path, "w"); - if (f == NULL) { - ESP_LOGE(TAG, "Failed to open file for writing"); - return; + if (!file_exists(file_path)) { + ESP_LOGI(TAG, "Creating file"); + FILE *f = fopen(file_path, "w"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for writing"); + return; + } + fprintf(f, "Hello World!\n"); + fclose(f); } - fprintf(f, "Hello World!\n"); - fclose(f); + FILE *f; ESP_LOGI(TAG, "Reading file"); f = fopen(file_path, "r"); if (f == NULL) { @@ -99,15 +120,16 @@ static void handle_usb_events(void *args) while (1) { uint32_t event_flags; usb_host_lib_handle_events(portMAX_DELAY, &event_flags); + // Release devices once all clients has deregistered if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { usb_host_device_free_all(); + xEventGroupSetBits(usb_flags, HOST_NO_CLIENT); } // Give ready_to_uninstall_usb semaphore to indicate that USB Host library // can be deinitialized, and terminate this task. if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { - xSemaphoreGive(ready_to_uninstall_usb); - break; + xEventGroupSetBits(usb_flags, HOST_ALL_FREE); } } @@ -116,29 +138,40 @@ static void handle_usb_events(void *args) static uint8_t wait_for_msc_device(void) { - msc_host_event_t app_event; + EventBits_t event; + ESP_LOGI(TAG, "Waiting for USB stick to be connected"); - xQueueReceive(app_queue, &app_event, portMAX_DELAY); - assert( app_event.event == MSC_DEVICE_CONNECTED ); - return app_event.device.address; + event = xEventGroupWaitBits(usb_flags, DEVICE_CONNECTED | DEVICE_ADDRESS_MASK, + pdTRUE, pdFALSE, portMAX_DELAY); + ESP_LOGI(TAG, "connection..."); + // Extract USB device address from event group bits + return (event & DEVICE_ADDRESS_MASK) >> 4; +} + +static bool wait_for_event(EventBits_t event, TickType_t timeout) +{ + return xEventGroupWaitBits(usb_flags, event, pdTRUE, pdTRUE, timeout) & event; } void app_main(void) { msc_host_device_handle_t msc_device; + msc_host_vfs_handle_t vfs_handle; + msc_host_device_info_t info; BaseType_t task_created; - ready_to_uninstall_usb = xSemaphoreCreateBinary(); - - app_queue = xQueueCreate(3, sizeof(msc_host_event_t)); - assert(app_queue); - - const usb_host_config_t host_config = { - .skip_phy_setup = false, - .intr_flags = ESP_INTR_FLAG_LEVEL1, + const gpio_config_t input_pin = { + .pin_bit_mask = (1 << USB_DISCONNECT_PIN), + .mode = GPIO_MODE_INPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, }; - ESP_ERROR_CHECK( usb_host_install(&host_config) ); + ESP_ERROR_CHECK( gpio_config(&input_pin) ); + usb_flags = xEventGroupCreate(); + assert(usb_flags); + + const usb_host_config_t host_config = { .intr_flags = ESP_INTR_FLAG_LEVEL1 }; + ESP_ERROR_CHECK( usb_host_install(&host_config) ); task_created = xTaskCreate(handle_usb_events, "usb_events", 2048, NULL, 2, NULL); assert(task_created); @@ -150,33 +183,37 @@ void app_main(void) }; ESP_ERROR_CHECK( msc_host_install(&msc_config) ); - uint8_t device_address = wait_for_msc_device(); - - ESP_ERROR_CHECK( msc_host_install_device(device_address, &msc_device) ); - - msc_host_print_descriptors(msc_device); - - msc_host_device_info_t info; - ESP_ERROR_CHECK( msc_host_get_device_info(msc_device, &info) ); - print_device_info(&info); - - msc_host_vfs_handle_t vfs_handle; const esp_vfs_fat_mount_config_t mount_config = { .format_if_mount_failed = false, .max_files = 3, .allocation_unit_size = 1024, }; - ESP_ERROR_CHECK( msc_host_vfs_register(msc_device, "/usb", &mount_config, &vfs_handle) ); + do { + uint8_t device_address = wait_for_msc_device(); - file_operations(); + ESP_ERROR_CHECK( msc_host_install_device(device_address, &msc_device) ); - ESP_ERROR_CHECK( msc_host_vfs_unregister(vfs_handle) ); - ESP_ERROR_CHECK( msc_host_uninstall_device(msc_device) ); + msc_host_print_descriptors(msc_device); + + ESP_ERROR_CHECK( msc_host_get_device_info(msc_device, &info) ); + print_device_info(&info); + + ESP_ERROR_CHECK( msc_host_vfs_register(msc_device, "/usb", &mount_config, &vfs_handle) ); + + while (!wait_for_event(DEVICE_DISCONNECTED, 200)) { + file_operations(); + } + + xEventGroupClearBits(usb_flags, READY_TO_UNINSTALL); + ESP_ERROR_CHECK( msc_host_vfs_unregister(vfs_handle) ); + ESP_ERROR_CHECK( msc_host_uninstall_device(msc_device) ); + + } while (gpio_get_level(USB_DISCONNECT_PIN) != 0); + + ESP_LOGI(TAG, "Uninitializing USB ..."); ESP_ERROR_CHECK( msc_host_uninstall() ); - - xSemaphoreTake(ready_to_uninstall_usb, portMAX_DELAY); + wait_for_event(READY_TO_UNINSTALL, portMAX_DELAY); ESP_ERROR_CHECK( usb_host_uninstall() ); - ESP_LOGI(TAG, "Done"); }