STM Урок 36. USB. Host Mass Storage Class. Часть 1



Урок 36

Часть 1

 

USB. Host Mass Storage Class

 

Проект создаём из проекта I2CLCD80. Назовем его USB_HOST_MSC_FATFS. Запустим проект в Cube, включим USB_OTG_FS в режим Host_Only включим там Activate_VBUS.

 

image03

 

В USB_DEVICE в разделе Class For FS IP выберем пункт Mass Storage Host Class

 

image05

 

Лапки портов PD4-PD7, PB8, PB9 отключим, это пережиток прошлых занятий

 

image04

 

В разделе FATFS включим USB Disk

 

image07

 

Лапку PC0 включим на выход

 

image06

 

 

Включим на выход ещё лапки портов отвечающие за красный и зеленый светодиоды

 

image01

 

В Clock Configuration выберем следующие делители (нажмите на картинку для увеличения изображения)

 

image00_0500

 

В Configuration прерывания там выставились сами.

Единственное можно включить поддержку кластеров до 4 кб

 

image02

 

Сгенерируем и запустим проект, подключим 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

 

 

Смотреть ВИДЕОУРОК

 

STM32 USB. Host Mass Storage Class

20 комментариев на “STM Урок 36. USB. Host Mass Storage Class. Часть 1
  1. Евгений:

    Чем обусловлено изменение кода 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 включим на выход". Зачем включали, если нигде не используем возможность отключения питания на устроймтво?

  2. Александр:

    А на 103 можно этот урок перевезти???
    спасибо…

    • Pavel:

      Нельзя. Нужен USB OTG интерфейс. Подойдут, например, stm32F105, stm32f107 или любые другие с интерфейсом USB OTG_FS или USB OTG_HS.

  3. 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)

  4. Ильшат:

    в исходнике изменения в USBH_UserProcess вообще не сделаны. Более того, программа вообще не обращается к этой функции. По-крайней мере, явно. я не увидел. и вообще не работает, а ваш исходник даже не собирается. в чем дело?

    • По всей видимости, что-то изменили со времён выхода урока в HAL.

    • А какая ошибка при сборке?
      Хотя даже ещё один вопрос предварительный, так как от Вас очень мало данных:
      Что именно не собирается? не генерируется проект в Cube MX (надеюсь объяснять не надо, чтобы версия Cube была та же какая была во время выхода урока, иначе пляски с бубном) или проект нормально генерится, но потом не собирается в Keil?

  5. Ильшат:

    1. не находит USBH_Path, впрочем, я нашел пример, откуда вы взяли ваш пример и там USBH_Path декларируется.
    2. однако ж, больше интересно про USBH_UserProcess?

  6. Ильшат:

    да, хотел сказать, чтобы вы не подумали, что у вас какие-то косяки в программах непреодолимые… а то, мне показалось, что комменты мои несколько пренебрежительные. хорошее дело делаете, частенько к вам захаживаю, удачи вам. а USBHPath — должен быть, так он в FATS назван.

  7. Дмитрий:

    При входе в этот модуль
    LCD_Clear()
    LCD_SetPos(0,0)
    LCD_String((char*)rtext)
    f_close(&MyFile)
    зависает в первой же функции, пробовал в дебаге
    а также зажигал диод в разных местах, после LCD_Clear() не горит.
    А вот запись на флэш получается.
    Ну и заодно огромное СПАСИБО за ваш нелёгкий труд!

  8. Дмитрий:

    Более подробно: в дебаге очищает экран LCD_Clear() и далее виснет на двух функциях
    в файле stm32f4xx_hal.c
    __weak uint32_t HAL_GetTick(void)
    {
    return uwTick;
    }

    while((HAL_GetTick() — tickstart) < wait) {}

    • evorontsov:

      То же самое… Разобраться так и не смог….

      Есть еще непонятное место: при чтении файла после создания и записи статус — FR_INVALID_OBJECT и, понятное дело не читает ничего. Если закомментировать создание и запись — все нормально читается. В чем может быть причина?

  9. Иван:

    Всем привет, Подскажите stm32f103С8Tx способен работать как USB HOST. Все примеры что нашел, это имитация HID устройств. А у меня задача USB клавиатуру подключить к МК.

  10. Sebastian:

    Здравствуйте, прежде всего большое спасибо за ваши уроки, вы лучшие.

    Я следил за вашей 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!

  11. Сергей Р.:

    После просмотра не понятно как переменная USBH_Path должна быть объявлена и проинициализирована.

  12. Илья:

    Здравствуйте! Спасибо за Ваш труд огромнейшее. Для новичка процесс освоения программирования 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 в проект генерирует библиотеку с ошибкой.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*