Merge branch 'feature/msc_example_hotplug' into 'master'

MSC example made hot plugable

Closes IDFGH-6758

See merge request espressif/esp-idf!17813
This commit is contained in:
Martin Válik 2022-05-11 20:56:49 +08:00
commit 20fdf3bdf1
2 changed files with 90 additions and 50 deletions

View File

@ -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:

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#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 <esp_vfs_fat.h>
#define USB_DISCONNECT_PIN GPIO_NUM_10
#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 QueueHandle_t app_queue;
static SemaphoreHandle_t ready_to_uninstall_usb;
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,7 +85,8 @@ static void file_operations(void)
}
}
ESP_LOGI(TAG, "Writing file");
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");
@ -75,7 +94,9 @@ static void file_operations(void)
}
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,
};
do {
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);
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");
}