Урок 36
Часть 1
USB. Host Mass Storage Class
Проект создаём из проекта I2CLCD80. Назовем его USB_HOST_MSC_FATFS. Запустим проект в Cube, включим USB_OTG_FS в режим Host_Only включим там Activate_VBUS.
В USB_DEVICE в разделе Class For FS IP выберем пункт Mass Storage Host Class
Лапки портов PD4-PD7, PB8, PB9 отключим, это пережиток прошлых занятий
В разделе FATFS включим USB Disk
Лапку PC0 включим на выход
Включим на выход ещё лапки портов отвечающие за красный и зеленый светодиоды
В Clock Configuration выберем следующие делители (нажмите на картинку для увеличения изображения)
В Configuration прерывания там выставились сами.
Единственное можно включить поддержку кластеров до 4 кб
Сгенерируем и запустим проект, подключим lcd.c и настроим программатор на автоперезагрузку.
Соберем проект.
В main уберем весь пользовательский код кроме инициализации и очистки дисплея
/* USER CODE BEGIN 2 */
LCD_ini();
LCD_Clear();
/* USER CODE END 2 */
В файле usb_host.c подключим файл для файловой системы
/* USER CODE BEGIN 0 */
#include «ff_gen_drv.h»
/* USER CODE END 0 */
Также в этом файле кое-что заменим в функции USBH_UserProcess
static void USBH_UserProcess (USBH_HandleTypeDef *phost, uint8_t id)
{
/* USER CODE BEGIN 2 */
switch(id)
{
case HOST_USER_SELECT_CONFIGURATION:
break;
case HOST_USER_DISCONNECTION:
Appli_state = APPLICATION_DISCONNECT;
Appli_state = APPLICATION_IDLE;
f_mount(NULL, (TCHAR const*)»», 0);
break;
case HOST_USER_CLASS_ACTIVE:
Appli_state = APPLICATION_START;
break;
case HOST_USER_CONNECTION:
// Appli_state = APPLICATION_START;
break;
default:
break;
}
/* USER CODE END 2 */
}
В файле main.c объявим некоторые переменные
/* USER CODE BEGIN PV */
/* Private variables ———————————————————*/
extern ApplicationTypeDef Appli_state;
FATFS USBDISKFatFs; /* File system object for USB disk logical drive */
FIL MyFile; /* File object */
extern USBH_HandleTypeDef hUsbHostFS;
/* USER CODE END PV */
Также в файле main.c создадим функцию для считывания, создания и редактирования файлов и напишем туда включение зеленого светодиода, чтобы отследить, попали ли мы в данную функцию.
/* USER CODE BEGIN 0 */
void FileReadWrite(void)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
}
/* USER CODE END 0 */
Добавим код в бесконечный цикл
MX_USB_HOST_Process();
/* USER CODE BEGIN 3 */
if(Appli_state==APPLICATION_START)
{
FileReadWrite();
Appli_state = APPLICATION_IDLE;
}
else if(Appli_state==APPLICATION_IDLE)
{
}
}
/* USER CODE END 3 */
Подключим флеш-диск к компьютеру, создадим на нем текстовый файл «123.txt» с каким-нибудь содержимым, извлечем его из компьютера.
Подключим контроллер, флеш-диск к нему через кабель OTG.
Соберем проект, прошьем контроллер и посмотрим, попадём ли мы в нашу функцию по свечению зеленого светодиода.
В функцию мы попали, теперь можем здесь писать код, т.к. именно попав сюда, мы уверены, что всё у нас для этого готово. Добавим в данную функцию некоторые переменные
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); // здесь видим, что мы сюда попали
FRESULT res; /* FatFs function common result code */
uint32_t byteswritten, bytesread; /* File write/read counts */
uint8_t rtext[100]; /* File read buffer */
Вызовем функцию подключения нашего флеш-диска. Результат также смотрим с помощью светодиодов
uint8_t rtext[100]; /* File read buffer */
if(f_mount(&USBDISKFatFs, (TCHAR const*)USBH_Path, 0) != FR_OK)
{
/* FatFs Initialization Error */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); //красный цвет — сигнал ошибки
Error_Handler();
}
else
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); // здесь видим, что мы сюда попали
}
Вызовем функцию открытия файла для чтения. Также результат отследим по зеленому светодиоду, перенеся функции вызова управления лапками портов в другое место
if(f_mount(&USBDISKFatFs, (TCHAR const*)USBH_Path, 0) != FR_OK)
{
/* FatFs Initialization Error */
Error_Handler();
}
else
{
if(f_open(&MyFile, «123.txt», FA_READ) != FR_OK)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); //красный цвет — сигнал ошибки
Error_Handler();
}
else
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); // здесь видим, что мы сюда попали
}
}
Теперь напишем код считывания байтов из файла и отображения их на дисплее. В связи с этим мониторинг результатов с помощью светодиодов можно удалить
if(f_open(&MyFile, «123.txt», FA_READ) != FR_OK)
{
Error_Handler();
}
else
{
res = f_read(&MyFile, rtext, sizeof(rtext), (void *)&bytesread);
if((bytesread == 0) || (res != FR_OK))
{
Error_Handler();
}
else
{
LCD_Clear();
LCD_SetPos(0,0);
LCD_String((char*)rtext);
f_close(&MyFile);
}
}
В следующей части данного занятия мы попробуем создать файл и записать в него информацию.
Предыдущий урок Программирование МК STM32 Следующая часть
Отладочную плату можно приобрести здесь STM32F4-DISCOVERY
Смотреть ВИДЕОУРОК
Чем обусловлено изменение кода USBH_UserProcess?
Здесь:
case HOST_USER_DISCONNECTION:
Appli_state = APPLICATION_DISCONNECT;Appli_state = APPLICATION_IDLE;
f_mount(NULL, (TCHAR const*)"", 0);
break;
и здесь (в тексте статье удаленный элемент отсутствует):
case HOST_USER_CLASS_ACTIVE:
Appli_state = APPLICATION_READY;Appli_state = APPLICATION_START;
break;
Следующее: "Лапку PC0 включим на выход". Зачем включали, если нигде не используем возможность отключения питания на устроймтво?
А на 103 можно этот урок перевезти???
спасибо…
Нельзя. Нужен USB OTG интерфейс. Подойдут, например, stm32F105, stm32f107 или любые другие с интерфейсом USB OTG_FS или USB OTG_HS.
STM32 MSC for SD in SPI mode
Good morning
I wanted to congratulate the site. I had a need.
If possible, is there an example of MSC on SD — SPI instead of USB?
I have difficulty understanding how to proceed.
Thanks Silvio
(sorry for the language)
в исходнике изменения в USBH_UserProcess вообще не сделаны. Более того, программа вообще не обращается к этой функции. По-крайней мере, явно. я не увидел. и вообще не работает, а ваш исходник даже не собирается. в чем дело?
По всей видимости, что-то изменили со времён выхода урока в HAL.
А какая ошибка при сборке?
Хотя даже ещё один вопрос предварительный, так как от Вас очень мало данных:
Что именно не собирается? не генерируется проект в Cube MX (надеюсь объяснять не надо, чтобы версия Cube была та же какая была во время выхода урока, иначе пляски с бубном) или проект нормально генерится, но потом не собирается в Keil?
1. не находит USBH_Path, впрочем, я нашел пример, откуда вы взяли ваш пример и там USBH_Path декларируется.
2. однако ж, больше интересно про USBH_UserProcess?
да, хотел сказать, чтобы вы не подумали, что у вас какие-то косяки в программах непреодолимые… а то, мне показалось, что комменты мои несколько пренебрежительные. хорошее дело делаете, частенько к вам захаживаю, удачи вам. а USBHPath — должен быть, так он в FATS назван.
При входе в этот модуль
LCD_Clear()
LCD_SetPos(0,0)
LCD_String((char*)rtext)
f_close(&MyFile)
зависает в первой же функции, пробовал в дебаге
а также зажигал диод в разных местах, после LCD_Clear() не горит.
А вот запись на флэш получается.
Ну и заодно огромное СПАСИБО за ваш нелёгкий труд!
Более подробно: в дебаге очищает экран LCD_Clear() и далее виснет на двух функциях
в файле stm32f4xx_hal.c
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}
while((HAL_GetTick() — tickstart) < wait) {}
То же самое… Разобраться так и не смог….
Есть еще непонятное место: при чтении файла после создания и записи статус — FR_INVALID_OBJECT и, понятное дело не читает ничего. Если закомментировать создание и запись — все нормально читается. В чем может быть причина?
Всем привет, Подскажите stm32f103С8Tx способен работать как USB HOST. Все примеры что нашел, это имитация HID устройств. А у меня задача USB клавиатуру подключить к МК.
Здравствуйте, прежде всего большое спасибо за ваши уроки, вы лучшие.
Я следил за вашей SD-картой с помощью SPI и FATFS Tutorial, и это было замечательно, оно работало отлично.
Я хотел бы реализовать подключение USB этой работы. Я хочу добавить устройство USB Mass Sotrage в проект SPI FATFS на SD-карте.
Я использую ядро STM32F072RB, и я использую внутреннюю конфигурацию часов.
Спасибо большое! Я остаюсь внимательным. Ты самый лучший!
Hello, fist of all thank you very much for your tutorials, you are the best.
I have followed your SD Card with SPI and FATFS Tutorial and it was wonderful, it worked perfect.
I would like to implement a USB connection of that work. I mean, I would like to add a USB Mass Sotrage Device to the SD Card SPI FATFS project.
I am using a STM32F072RB Nucleo, and I am using internal clock configuration.
Thank you very much! I remain attentive. You are the best!
После просмотра не понятно как переменная USBH_Path должна быть объявлена и проинициализирована.
Это стандартная переменная USBHPath. Не надо ее объявлять и инициализировать ИМХО
Здравствуйте! Спасибо за Ваш труд огромнейшее. Для новичка процесс освоения программирования stm32 упрощается многократно с вашими уроками. У меня отладочная плата NUCLEO-F767ZI, работаю через stm32cubeIDE, почему-то не работает USB Host (на плате не светится светодиод LD8). При генерации кода Cube указал на необходимость указать параметры Platform Settings в USB_HOST (тут только Drive_VBUS_FS можно указать, выставил GPIO:Output PG6, на моей плате PG6 управляет включателем U12, а он в свою очередь запитывает VBUS). Ошибок при сборке проекта теперь нет, но не работает Host. Пытаюсь сравнивать с примером от ST (он работает, но библиотеки явно изменились), успехов пока нет. Прошу Вас уделить немного времени, может в настройках Cube надо что-то дополнительно указать…
Нашел решение. Неделю возился не видел, у Вас уже помощь попросил и решил еще раз все проверить, строчка за строчкой. Итак Cube в main.c в фукцию int main(void) вставляет вызов MX_USB_HOST_Init(), в этой инициализации есть вызов USBH_Start(&hUsbHostFS), далее вызов USBH_LL_DriverVBUS(phost, TRUE), в итоге вызывается MX_DriverVbusFS(state). В параметре передается TRUE. А вот описание:
void MX_DriverVbusFS(uint8_t state)
{
uint8_t data = state;
/* USER CODE BEGIN PREPARE_GPIO_DATA_VBUS_FS */
if(state == 0)
{
/* Drive high Charge pump */
data = GPIO_PIN_SET;
}
else
{
/* Drive low Charge pump */
data = GPIO_PIN_RESET;
}
/* USER CODE END PREPARE_GPIO_DATA_VBUS_FS */
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_6,(GPIO_PinState)data);
}.
Т.е. при конфигурировании USB_OTG_FS в режиме HOST only на PG6 (для NUCLEO-F767ZI управление VBUS) выдается низкий уровень. Должно быть наоборот иначе как запитать USB флешку. В примере от ST (FatFs_USBDisk), который у меня работал изначально, логика верная. Там в итоге череды вызовов вызывается:
USBH_StatusTypeDef USBH_LL_DriverVBUS(USBH_HandleTypeDef *phost, uint8_t state)
{
if(state == 0)
{
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_SET);
}
HAL_Delay(200);
return USBH_OK;
}
Параметр state == TRUE, на PG6 высокий уровень, выключатель U12 выдает запитывает USB флешку и светодиод LD8 светится, а я улыбаюсь.
Вот и причина неработоспособности. В итоге сам спросил, сам ответил))). Но может кому понадобится. Спасибо за внимание.
Возможно, что-то изменилось в библиотеках. Посмотрите примеры в репозитории.
FatFs_USBDisk это и есть название примера из репозитория, в нем все правильно. А вот Cube в проект генерирует библиотеку с ошибкой.