Stm32f103 после заливки программы не работает usb
Перепробовал все, от примеров до уроков. Проблема вот в чем. Подсоединяю плату в юсб, она включается, но юсб не работает, нужно нажать и немного подержать ресет на плате, тогда все ок, юсб поднимается и работает, данные шлю туда сюда без проблем. Но стоит опять опять сделать ресет, юсб пропадает и не поднимется пока не отключишь питание и не повторишь все снова. Работать невозможно, отлаживать тоже, постоянно перетыкать приходиться((
HID-USB на STM32F103C8 вынос мозга
Пытаюсь сотворить HID-USB на STM32F103C8. Использую CoolCox, вот такую платку и отладчик J-Link от.
USB CDC на STM32F103C8 в минимальном размере
Подскажите либы для организации CDC как виртуальный ком порт (с STшным драйвером) чтоб был.
STM32f103c8, USB - ограничение длины изохронной передачи
Добрый день! Пытаюсь сделать USB audyo устройство. Устройство работает, но я наткнулся на.
Проблема с USB концентратором: "Нехватка электропитания порта концентратота usb".
проблемы с материнской платой.суть проблемы такова-случайно задел системник рукой и в трее сразу.
черт с ней с отладкой, как решить проблему когда плату вставляю в юсб, она включается но юсб поднимается только после ручного ресета. Устройство уже готово, но пользоваться не удобно. Подтяжка Д+ распаяна на плате на постоянку
Новую тему создавать не буду, название абсолютно подходит и моей проблеме.
Камень STM32F103C8, среда Keil 4, завожу USB (виртуальный som-порт от ST).
Завелось, c жёсткой подтяжкой проводом, код Set_System (без всякого хлама) выглядел в таком виде. Структура инициализации прерываний заменена прямыми установками, потому что со структурой USB не определялся (сбой запроса дескриптора устройства), но скорей всего проблемы где-то в другом (см далее).
На плате была заложена подтяжка от контроллера. Добавил в код USB_DISCONNECT_PIN и прочее, ответственное за подтягивание.
Фрагмент из "hw_config.h":
- пустой цикл "for" о котором будет сказано позже
- тактирование GPIO
- структура для GPIO и её инициализация
- прямая инициализация GPIO через регистры
А теперь, что я имею на выходе.
Уровень оптимизации -O3
Функция Delay_ms полностью закомментирована
Прямая инициализация GPIO через регистры
Пустой цикл "for" при b < 257 (и более)
USB устройство обнаруживается
Уровень оптимизации -O3
Функция Delay_ms полностью закомментирована
Прямая инициализация GPIO через регистры
Пустой цикл "for" при b < 256 (и менее) или цикл закомментирован
Сбой запроса дескриптора устройства
Уровень оптимизации -O3
Функция Delay_ms раскомментирована
Прямая инициализация GPIO через регистры
Пустой цикл "for" (значение не важно; раскомментирована или закомментирована)
USB устройство обнаруживается
Уровень оптимизации -O3
Функция Delay_ms раскомментирована
Инициализация GPIO через структуру
Пустой цикл "for" при b < 256 (и менее) или цикл закомментирован
Сбой запроса дескриптора устройства
Уровень оптимизации -O3
Функция Delay_ms раскомментирована
Инициализация GPIO через структуру
Пустой цикл "for" при b < 257 (и более)
USB устройство обнаруживается
Уровень оптимизации -O0
Функция Delay_ms полностью закомментирована
Прямая инициализация GPIO через регистры
Пустой цикл "for" закомментирован
USB устройство обнаруживается
Уровень оптимизации -O0
Функция Delay_ms полностью закомментирована
Прямая инициализация GPIO через регистры
Пустой цикл "for" при любом значении
Сбой запроса дескриптора устройства
Уровень оптимизации -O0
Функция Delay_ms раскомментированна
Прямая инициализация GPIO через регистры
Пустой цикл "for" при любом значении или закомментирован
Сбой запроса дескриптора устройства
Уровень оптимизации -O0
Функция Delay_ms раскомментированна
Инициализация GPIO через структуру
Пустой цикл "for" закомментирован
USB устройство обнаруживается
Уровень оптимизации -O0
Функция Delay_ms раскомментированна
Инициализация GPIO через структуру
Пустой цикл "for" при любом значении
Сбой запроса дескриптора устройства
Уровень оптимизации -O0
Функция Delay_ms полностью закомментирована
Инициализация GPIO через структуру
Пустой цикл "for" закомментирован
Сбой запроса дескриптора устройства
Уровень оптимизации -O0
Функция Delay_ms полностью закомментирована
Инициализация GPIO через структуру
Пустой цикл "for" при b < 1426 (и более)
Сбой запроса дескриптора устройства
Уровень оптимизации -O0
Функция Delay_ms полностью закомментирована
Инициализация GPIO через структуру
Пустой цикл "for" при b < 1425 (и менее)
USB устройство обнаруживается
Может что-то упустил. Но совершенно не понимаю от чего это зависит, и почему именно так.
Прям нигия программирования.
Весь код hw_config.c
/* Exported functions ------------------------------------------------------- */
void Set_System(void);
void Set_USBClock(void);
void Enter_LowPowerMode(void);
void Leave_LowPowerMode(void);
void USB_Ymtirrupts_Config(void);
void USB_Cable_Config (FunctionalState NewState);
void Homdle_USBAsynchXfer (void);
void Get_SerialNum(void);
/************************ (C) COPYRIGHT STMicroitistronics *****END OF FILE****/
В своем проекте я использую микроконтроллер STM32F103C8 и фреймворк stm32duino. Этот клон Ардуино предлагает специальный бутлоадер, который позволяет заливать прошивку через USB, без использования внешних компонентов типа ST-Link или USB-UART переходника.
Сегодня мне понадобилось поработать с голым контроллером из-под CooCox и без stm32duino. Но вот в чем проблема. Даже простая моргалка лампочкой влитая через этот бутлоадер не работает.
Давайте разбираться. Возможно, мои выкладки покажутся кому-то банальностью. Но я только начинаю изучать контроллеры STM32 и на поиск проблемы убил как минимум полдня. Вдруг эта статья сократит кому-то время разработки.
Я ничего не имею против ST-Link и других отладчиков. Но в моем готовом устройстве его не будет, но точно будет USB. Почему бы сразу не заложить возможность обновлять прошивку через USB? Лично я нахожу этот способ удобным. тем более что все равно у меня уже подключен шнурок по которому идет питание и USB Serial.
Давайте посмотрим как работает бутлоадер. Для начала на примере контроллеров AVR. Почему я о нем вспомнил? Я переходил с Arduino и подсознательно ожидал такого же поведения. Но в STM32 оказалось все по другому. Потому хочу рассказать о разнице этих двух микроконтроллеров.
Итак. В микроконтроллерах AVR ATMega под бутлоадер можно зарезервировать некоторое количество памяти ближе к концу флеша. С помощью fuse битов можно регулировать с какого адреса будет стартовать программа. Если бутлоадера нет — программа стартует с адреса 0x0000. Если бутлоадер есть — он запускается с некоторого другого адреса (скажем, в ATMega32 с 0x3C00, если размер бутлоадера выбран 2к).
Когда бутлоадер сделал свои дела он передает управление основной программе с адреса 0x0000. Т.е. программа всегда стартует с адреса 0x0000. Компилятор и линковщик работают с учетом того, что код будет находится в начале адресного пространства.
В микроконтроллерах STM32 все не так. Все программы стартуют с адреса 0x0800000. Бутлоадер не является чем-то таким особенным. Это такая же программа, которая стартует с того же самого начального адреса. В процессе работы бутлоадер может принять прошивку (через USB или UART, считать с флешки, принять со спутника, достать из подпространства, whatever. ) и записать ее по адресам выше чем находится сам загрузчик. Ну и, конечно же, в конце своей работы передать управление основной программе.
Так вот при компиляции прошивки нужно знать куда же бутлоадер запишет прошивку и соответствующим образом скорректировать адреса.
На этом с теорией все. Переходим к практике. Ниже пошаговая инструкция как прикрутить USB загрузчик к микроконтроллерам серии STM32F1xx, а может быть и к некоторым другим тоже.
Есть, правда, некоторые ограничения по схемотехнике. Тут я, к сожалению, не силен. ЯТП нужен подтягивающий резистор 1.5к для порта PA12 (он же USB D+). Это позволяет загрузчику в нужные моменты времени подключаться и отключаться от USB.
-
Указать линкеру стартовый адрес. В CooCox это делается в настройках проекта, вкладка Link, раздел Memory Areas, Адрес IROM1 Start Address. Бутлоадер занимает первые 8 килобайт, значит стартовый адрес прошивки будет 0x0800000 + 0x2000 = 0x08002000. Поле Size, наверное, тоже стоит уменьшить на 8к.
Вместо COM20 нужно подставить свой порт куда прицепился микроконтроллер.
Заливатор штука очень нежная, относительных путей не любит. так что путь к прошивке нужно указывать полностью.
1EAF:0003 — это VID и PID
Чтобы не нажимать каждый раз ресет, платы основанные на libmaple/stm32duino используют трюк. Они слушают usb serial порт. Если там возникает сигнал DTR и передается ключевая последовательность байт, то микроконтроллер перегружается в бутлоадер. Смотреть в функцию rxHook().
Из-за этого может возникнуть неудобство. Если микроконтроллер заглючил и повис, то он уже не слушает порт. Следовательно он не может услышать ключевую последовательность и перегрузиться в бутлоадер. Тогда только ресет в помощь.
На этом все. Надеюсь моя статья прольет свет на то, как работает загрузчик в STM32 и как можно загружать прошивку через USB порт. К сожалению порог вхождения по прежнему высок, но вдруг кому-то моя статья поможет его преодолеть.
Если статья Вам понравилась, Вы можете поддержать меня купив чашечку кофе.
На дворе 2014 год, а для связи микроконтроллеров с ПК самым популярным средством является обычный последовательный порт. С ним легко начать работать, он до примитивности прост в понимании — просто поток байт.
Однако все современные стандарты исключили COM порт из состава ПК и приходится использовать USB-UART переходники, чтобы получить доступ к своему проекту на МК. Не всегда он есть под рукой. Не всегда такой переходник работает стабильно из-за проблем с драйверами. Есть и другие недостатки.
Но каждый раз, когда заходит разговор о том, применять USB или последовательный порт, находится множество поклонников логической простоты UART. И у них есть на то основания. Однако, хорошо ведь иметь альтернативу?
Меня давно просили рассказать как организовать пакетный обмен данными между ПК и МК на примере STM32F103. Я дам готовый рабочий проект и расскажу как его адаптировать для своих нужд. А уж вы сами решите — нужно оно вам или нет.
Выбор профиля HID
USB-HID — довольно обширный класс устройств, поэтому прежде всего придется выбрать какое именно устройство мы будем создавать.
Мы можем создать эмуляцию клавиатуры, мыши, джойстика и других устройств ввода, а можем создать свое устройство, чтобы не зависеть от довольно жестких рамок стандарта и свободно обмениваться данными с ПК.
Я расскажу как cделать Custom HID device. Это дает максимальную свободу. Чтобы не затягивать статью, постараюсь рассказать максимально кратко — описаний стандарта в сети и без меня много, но лично мне они слабо помогли, когда понадобилось решить конкретную задачу.
Структура проекта
- Папка USB-FS с библиотекой «STM32F10x, STM32L1xx and STM32F3xx USB-FS-Device Driver» версии 4.0.0.
- В папках Inc и Src файлы:
platform_config.h — здесь собраны определения, касающиеся конкретной платы и семейства МК
stm32_it.h, stm32_it.c — здесь определены обработчики прерываний
usb_conf.h, usb_endp.c — здесь определяются конечные точки (Endpoint), размеры и адреса их буферов, функции-обработчики
usb_desc.h, usb_desc.c — здесь собрана информаци о самом устройстве — как оно будет определяться при подключении к ПК и определены размеры и формат пакетов данных
hw_config.c — здесь собрана вся работа с отправкой данных на ПК
hw_config.h, usb_istr.h, usb_prop.h, usb_pwr.h
usb_istr.c, usb_prop.c, usb_pwr.c — нужны для работы USB-FS библиотеки, но лезть в них необязательно
Инициализация USB
Для корректной работы USB модуля важна частота работы МК. Далеко не все частоты позволяют правильно задать тактирование USB. В нашем случае используется кварцевый генератор на 8МГц и МК работает на частоте 72МГц, а USB модуль на 48МГц.
В main.c достаточно включить всего несколько строк кода
В функции Set_System() производится настройка пина подтяжки линии D+ к питанию для программного подключения/отключения устройства от ПК (в нашей плате не используется), настраивается прерывание и инициализируются светодиоды и кнопки для демонстрационного проекта.
В USB_Interrupts_Config() настраиваются прерывания в зависимости от семейства МК (поддерживаются F10x, F37x, L1x).
Функция USB_Init() запускает работу USB модуля. Если временно нужно отключить для отладки работу с USB, просто закомментируйте эту строку.
Далее в бесконечном цикле проверяется, удалось ли сконфигурировать USB модуль при подключении к ПК. Если все сработало верно и устройство успешно подключилось, ПК включен и не находится в режиме энергосбережения, то состояние будет CONFIGURED.
Далее проверяется, была ли закончена предыдущая передача данных в ПК и если да, то готовится к отправке новый пакет в функции RHIDCheckState()
Размер пакета и частота передачи
USB-HID девайс не может сам инициировать передачу, т.к. координацией шины занимается host устройство — ПК. Поэтому при подготовке USB дескриптора нашего устройства, мы пишем, как часто нужно опрашивать наше устройство. По спецификации максимальная частота опроса — 1кГц и максимальный размер передаваемого за раз пакета — 64 байта. Если этого недостаточно — придется использовать другие режимы работы — вроде USB bulk, но там уже без драйверов не обойтись.
За настройку взаимодействия с ПК отвечают 3 дескриптора:
В комментариях все довольно прозрачно. Обратите внимание на DEVICE_VER_L, DEVICE_VER_H — это константы из usb_desc.h, которые вы можете изменить для идентификации версии своего устройства.
Здесь стоит обратить внимание на константу wMaxPacketSize — она определяет максимальный размер пакета, которым мы будем обмениваться с ПК. Проект так настроен, чтобы при ее изменении менялись и размеры буферов. Но не забывайте, что больше 0x40 по стандарту указывать не стоит. С этой константой будьте осторожны — если передаваемый пакет будет отличаться по размеру — будут проблемы!
Следующая за ним константа с комментарием bInterval — это период опроса устройства в миллисекундах. Для нашего устройства задано 32мс.
Это самый важный дескриптор — он описывает протокол обмена и функционал устройства. Его формирование — не самая простая задача. Если допустить ошибку при формировании дескриптора — устройство перестанет работать. Формат дескриптора очень жесткий. Есть даже специальная утилита HID Descriptor tool. А в корне проекта лежит файл «RHID.hid» с описанным выше дескриптором для редактирования в этой утилите. Но если вы не понимаете, что делаете, лучше не лезть.
Для простоты я сделал две константы:
RPT3_COUNT — размер OUTPUT буфера в байтах для передачи пакета в МК (в примере — 1 байт)
RPT4_COUNT — размер INPUT буфера в байтах для передачи пакета в ПК (в примере — 4 байта)
Размер любого из этих буферов не должен превышать wMaxPacketSize. Меньше — можно.
Кстати, превратить Custom HID в другой HID девайс, например, клавиатуру или джойстик можно фактически только переписав ReportDescriptor и изменив класс и подкласс устройства в дескрипторе конфигурации.
Что такое Report
- REPORT_ID = 1 и 2 — команда МК включить/выключить LED1/LED2. Содержит поле размером 1 бит с желаемым состоянием светодиода и поддерживает отправку как методом SET_REPORT так и методом SET_FEATURE (об этом чуть позже).
- REPORT_ID = 3 — передает один байт в МК. Просто, чтобы показать, как передать данные МК. Мы будем передавать положение ползунка.
- REPORT_ID = 4 — это репорт для передачи данных ПК. Возвращает информацию о текущем состоянии светодиодов, кнопок (если они есть) и возвращает переданный в репорте с байт, чтобы показать, что данные приняты.
Цикл обмена
Массив uint8_t Buffer[RPT4_COUNT+1] определен как размер полезных данных входящего (рассматривается всегда с точки зрения хоста) пакета + байт ID. Это важно — если размер буфера будет отличаться — будут проблемы. Поэтому для изменения размеров буфера редактируйте значение константы в usb_desc.h.
В функции мы собираем данные в пакет, устанавливаем флаг PrevXferComplete = 0, говорящий о том, что данные отправляются и вызываем функциии библиотеки USB_SIL_Write и SetEPTxValid для отправки данных хосту.
Все, на этом передача данных хосту закончена.
С приемом данных немного сложнее — есть два способа послать данные девайсу — один из них заключается в использовании описанных в дескрипторе репорта возможностей устройства (Features), с соответствующими параметрами посредством функции SET_FEAUTRE. Это некоторая абстракция, для красивого управления устройством с кучей функций, чтобы можно было вызывать осмысленные функции, а не просто слать поток байт.
Второй способ — это работа с устройством как с файлом — просто записываем в него пакет как в файл. Этот метод называется SET_REPORT. На деле работает чуть-чуть медленнее.
Наше устройство поддерживает оба метода, о чем мы и сказали хосту в дескрипторе репортов.
Обработка SET_FEATURE
Данные, отправленные методом SET_FEAUTRE обрабатываются в usb_prop.c
Здесь мы проверяем первый байт в репорте и в соответствии с ним обрабатываем остаток пакета — управляем светодиодами или просто берем байт, отправленный нам хостом и кладем в пакет для последующей отправки обратно в функции RHIDCheckState.
Под Report_Buf зарезервировано wMaxPacketSize байт, чтобы влез любой пакет, который нам отправит хост.
Данные, отправленные методом SET_REPORT обрабатываются в usb_endp.c
Здесь почти то же самое, только нужно самостоятельно забрать данные вызовом USB_SIL_Read(EP1_OUT, Receive_Buffer) и в конце сообщить, что мы закончили вызовом SetEPRxStatus(ENDP1, EP_RX_VALID);
Настраивать устройство, передавать и принимать данные в пакетах нужного размера с нужной нам периодичностью мы научились.
Собираем проект и прошиваем в устройство.
Работать, это будет примерно так:
Также я написал маленькую демо-софтинку, которая автоматически определяет подключение к компу и отключение нашего девайса по его VID и PID, отображает статус — подключено/отключено индикатором рядом с чекбоксом Auto Connect
Радиокнока Send using позволяет выбрать метод отправки данных девайсу.
Report: отображает полученный от девайса пакет побайтно, начиная с ReportID.
Щелкая по светодиодам ниже — управляем светодиодами девайса. Их состояние отображает текущее состояние девайса. Считывается из репорта от девайса.
Перемещая ползунок, мы отправляем Report с и значением, соответствующим позиции ползунка. Девайс вернет это значение в 4 байте репорта.
В выпадающем комбобоксе отображаются HID девайсы, найденные в системе и если найден наш девайс, то отображается его название.
Если остались вопросы — пишите в комментариях. Постараюсь ответить. Я постарался не утопить суть в куче мелочей, чтобы сложилось общее понимание. Остальное уже можно понять, изучая проект. Но если вам нужно быстро сделать свое устройство, а лезть в дебри некогда — все, что вам нужно, я описал.
P.S. По умолчанию при уходе хоста в режим энергосбережения, девайс засыпает вместе с ним, а если подключить девайс к спящему ПК, то он тоже уйдет в слип. Поэтому если мы просто воткнем в девайс блок питания или запитаем от батареи, то работать он не будет, считая, что подключен к спящему ПК (пакетов конфигурации то от БП не придет точно). Я изменил библиотеку так, чтобы устройство работало и при подключении просто БП. Поэтому девайс будет работать как при подключениии к ПК так и автономно. (У меня ушло немало времени, чтобы разобраться с этим.)
Здравствуйте! Меня зовут Дмитрий Руднев. В этой публикации я поделюсь своим горьким опытом.
В современной разработке широко используются микроконтроллеры STM32. Они обладают неплохим соотношением цена/производительность, вокруг них сложилась развитая «экосистема». Для прошивки этих микроконтроллеров и внутрисхемной отладки обычно используют интерфейс Serial Wire (SWD).
В процессе отладки бывает всякое. Не беда, если STM32 после прошивки ведёт себя неадекватно. Обидно, если при этом к нему не удаётся подключиться.
На этом месте не надо впадать в отчаяние, т.к. «убить насмерть» STM32 в процессе программирования непросто, и его работоспособность можно восстановить штатными средствами.
После аппаратного сброса микроконтроллер первым делом запускает системный загрузчик. Системный загрузчик проверяет состояние входов BOOT0 и BOOT1 и по их состоянию определяет режим дальнейшей загрузки. В зависимости от состояния BOOT0 подключиться к микроконтроллеру можно, как минимум, двумя разными способами.
Connect Under Reset
Если на входе BOOT0 обнаружен низкий уровень, системный загрузчик передаёт управление пользовательской программе, находящейся в FLASH-памяти. Если при этом к интерфейсу SWD подключен в режиме «Connect Under Reset» внутрисхемный отладчик, ему удаётся управление перехватить.
Рассмотрим, как это сделать с помощью программы STM32 ST-LINK Utility и программатора ST-LINK/V2-1. Программа была получена с официального сайта ST. Программатор пришёл в составе платы NUCLEO-F446ZE.
Запускаем программу, входим в «Settings»:
В окне «Settings» выбираем режим «Connect Under Reset»:
Подключаемся к нашему «кирпичику»:
Производим очистку памяти программ:
Подключение по UART1
Очень часто для прошивки STM32 применяются недорогие китайские клоны ST-LINK/V2. Без аппаратной переделки режим «Connect Under Reset» они не поддерживают. В этом случае стоит попытаться очистить память программ, подключившись к микроконтроллеру по UART.
Если подать на вход BOOT0 высокий уровень, то можно подключиться к микроконтроллеру через интерфейс UART1 с использованием программы Flash Loader Demonstrator. Программу можно получить с официального сайта ST. Преобразователь USB–UART подойдёт любой.
Запускаем программу. Выбираем COM-порт, к которому подключен преобразователь USB–UART:
Убеждаемся, что соединение установлено:
На следующем экране программа показывает области памяти микроконтроллера:
На следующем экране мы должны выбрать действие. Выбираем Erase – All:
Очистка памяти программ успешно завершена:
На этом месте надо вернуть на вход BOOT0 низкий уровень.
От автора
Любое несчастье, которое происходит с Вами, с кем-то другим уже происходило. Всё, что описано в публикации, происходило со мной и моим оборудованием.
Первая часть публикации повествует о том, как я в самом начале самоизоляции «закирпичил» новенькую оригинальную NUCLEO-F446ZE.
Это не стало для меня ударом, т.к. я уже знал, что делать. Наоборот, в процессе восстановления работоспособности платы я даже получил какое-то удовольствие от работы.
Предыдущий опыт был более трагичным. Я использовал совсем бюджетную плату в связке с очень недорогим клоном ST-LINK/V2. В один прекрасный миг, связь с платой по SWD пропала.
Результаты поиска в сети убедили меня использовать режим «Connect Under Reset». Ничтоже сумняшеся, я подключил вывод NRST микроконтроллера к выводу «Reset» программатора. Не знал я тогда, что этот вывод используется только при работе с STM8.
Сигнал сброса не проходил. Связь по интерфейсу SWD не восстанавливалась. Игры с кнопкой «Reset» на плате результата не давали. В самый раз было начинать читать мануалы.
И метод RTFM сработал! Из раздела «2.3.10 Boot modes» datasheet DS5792 rev13 я узнал про загрузку через UART1. Затем я нашёл информацию о Flash Loader Demonstrator. Восстановить работоспособность STM32F103RET6 с этими инструментами было уже несложно, что и вылилось в 113 слов и пять картинок второй части публикации…
После того как я вдоволь наковырялся с STM32 и USB, решил что было бы неплохо поделитсья опытом с окружающими. Тем более, что все делалось аж под три разные платы и две разные линейки процессоров: High-Density (STM32F103RET6, STM32F103VET6) и Connectivity-Line (STM32F107VCT6).
Платы у меня в руках оказались следующие:
1) STM32 Development Board MINI (512K Flash 64K SRAM) 2.4-inch QVGA TFT module
(ссылка 1) (ссылка 2)
На ней стоит микроконтроллер STM32F103VET6
2) Embest EM-STM32C (EM-STM3210C)
(ссылка)
На ней стоит микроконтроллер STM32F107VCT6 — Connectivity Line
3) Встраиваемый модуль TE-STM32F103 — Махаон, от фирмы Terraelectronica.
(ссылка)
Соответственно, на ней стоит контроллер STM32F103RET6
Запустить проект из примеров, который использует USB, на любой из этих плат, задача не такая уж и сложная.
Куда сложнее встроить эти примеры в свои проекты, так как часто они бывают очень запутанно завязаны на конкретных платах. Еще сложнее собрать проект с нуля, используя библиотеки драйверов от STM — все равно без примеров обойтись сложно.
Поэтому я поставил перед собой задачу сделать универсальный проект, работающий со всеми имеющимися у меня в наличии платами, и, при необходимости, легко подстраиваемый под другие платы.
Между первой и третьей платой отличий мало: похожие контроллеры, отличающиеся лишь числом ног, у обоих выведен USART1. А вот второй отличается сильно: это контроллер Connectivity Line, с поддержкой USB On-The-Go, из-за чего работа с USB построена по-другому, а также вместо USART1 выведен USART2, да еще и с ремапом пинов на другие, отличные от дефолтных, ноги.
На всех платах есть светодиоды в разном количестве: 1, 4 и 3 соответственно.
Поэтому было принято решение сделать банальную вещь — устройтво, светодиоды которого управляются с компьютера по USB.
Прежде чем продолжать, рекомендую вкратце ознакомиться с тем, что же из себя представляет USB.
Самая лучшая, на мой взгляд, статья по этому вопросу — «USB in a NutShell». Ее перевод можно найти тут.
- Control. Endpoint такого типа, с номером 0, обязательно должен присутствовать в любом USB-устройстве.
- Interrupt. Название, в принципе, говорит само за себя. Более подробно читайте в статье.
- Isochronous. Гарантированные передачи через равные промежутки времени. Обычно используется для передачи аудио и видео.
- Bulk. Самый простой для реализации вариант. Применяется широко. Подробнее в статье. С ним мы и будем работать.
Проект для Keil
В результате некоторых ковыряний и копипасты с примеров, редактирования, кодинга и прочих мучений, получилось следующее:
USB_SampleSomeDevice_src.rar (зеркало 1)
Структура файлов такая же, как и во многих примерах:
\Libraries\ — папка с библиотеками (CMSIS, Standart Peripheral Driver, USB OTG Full speed Device Driver)
\Project\ — папка для проектов. Их может быть много и все они могут использовать одни и те же библиотеки. Но у нас проект один.
\Project\SampleSomeDevice\ — папка с проектом
\Project\SampleSomeDevice\Doc\ — краткие описания
\Project\SampleSomeDevice\driver\ — драйвер устройства для Windows (подробнее о драйверах и софте в ч.2, когда ее напишу)
\Project\SampleSomeDevice\inc\ — заголовки .h
\Project\SampleSomeDevice\src\ — файлы исходников .c
\Project\SampleSomeDevice\RVMDK\ — файлы проекта и выходные файлы
Распаковываем проект и открываем.
Смотрим на вкладку Project, видим там несколько групп:
User — Основные исходники проекта.
User_headers — Заголовочные файлы. Вынес в отдельную группу для быстрого и удобного доступа к ним.
USB-FS-Device_Driver — файлы библиотеки USB.
StdPeriph_Driver — файлы библиотеки стандарной периферии.
RVMDK — startup-файлы для каждой линейки контроллеров. Обратите внимание, что только один, соответствующий вашему контроллеру должен компилиться.
Doc — Краткие описания.
По умолчанию проект сконфигурирован под плату TE-STM32F103.
Конфигурируем проект
под другой контроллер и плату.
1) Надо знать название контроллера и его линейку. Поддерживаются практически все контроллеры 103 серии (кроме XL-density), а также 105 и 107 серия — Connectivity Line.
Даташиты, предварительно скачанные с сайта ST:
STM32F103x4x6.pdf (зеркало 1) — STM32 Low-density performance line (краткое обозначение LD)
STM32F103x8xB.pdf (зеркало 1) — STM32 Medium-density performance line (краткое обозначение MD)
STM32F103xCxDxE.pdf (зеркало 1) — STM32 High-density performance line (краткое обозначение HD)
STM32F105_F107.pdf (зеркало 1) — STM32 Connectivity line (краткое обозначение CL)
Все, что связано с линейкой контроллера, содержит в себе краткое обозначение.
Например, startup-файл для Medium-density performance line будет называться startup_stm32f10x_md.s
Или глобальный define для Connectivity line — STM32F10X_CL
В Keil правым кликом по Target заходим в опции, выбираем вкладку Device и ищем там свой контроллер.
Следующий шаг — выбираем используемый JTAG для прошивки и отладки.
Я использую TE-ARM-LINK, отечественный клон J-LINK.
Последний шаг в данном пункте — выбрать нужный startup-файл в группе RVMDK, соответствующий линейке контроллера, включить его в сборку проекта, отключив при этом все остальные:
Следующие пункты — настройка платы.
открываем файл platform_config.h, ищем кусок кода:
2) Узнаем куда выведен USART. Для общего развития полезно также знать, используется ли при этом ремап пинов. При включенном дефайне _DEBUG_ на него выводится различная информация, которая может быть полезна.
Открываем схему платы и смотрим. Предположим, выяснили, что выведен USART2, TX — PB5, RX — PB6.
Смотрим комментарии вначале файла platform_config.h:
Выбираем подходящий и заменяем в последнем дефайне. В данном случае это будет так:
USART сконфигурирован на скорость 115200, 8 бит, 1 стоп, No Parity.
4) Проверяем, есть ли на контроллере пин, отвечающий за программный коннект/дисконнект USB и где он расположен. Схема может выглядеть так:
Если пина нету, просто удаляем дефайны, отвечающие за него.
Вот, в принципе и все. Осталось залить прошивку в контроллер. Если есть JTAG — это не проблема.
Если оного нету, не все потеряно:
USB_DfuSe.part1.rar (зеркало 1) — Софт для прошивки STM32 Connectivity line по USB. Часть 1
USB_DfuSe.part2.rar (зеркало 1) — Часть 2
COM_FlashLoader.zip (зеркало 1) — Софт для прошивки STM32 (103 серия) по UART
Не забудьте перед прошивкой этим способом перевести девайс в DFU-Mode, корректно выставив джамперы BOOT0 — BOOT1.
О софте и драйверах я напишу в другой раз, однако уже можно скачать программу, которая общается с любым количеством подключенных девайсов с данной прошивкой:
Ковыряемся в проекте
Поскольку каждую строчку кода расписывать долго, да и исходники полны в том числе и моих комментариев, приведу здесь список основных файлов проекта и их назначение.
User:
— main.c — очевидно.
— hw_config.c — конфигурация контроллера (периферия, прерывания, клоки и так далее)
— stm32f10x_it.c — обработчики прерываний
— usb_. c — конфигурация и работа USB посредством драйвера.
— user_usb.c — пользовательская работа с USB — разбор пакетов с данными и обработка команд.
— led.c — работа со светодиодами. Включение, выключение, непрерывное мигание.
User_headers:
— platform_config.h — конфигурация платы.
Для более удобного поиска я добавил в код комментарии следующего вида:
Проект собран так, что USB-устройство, помимо нулевой контрольной, содержит 4 оконечных точки типа bulk, попарно на прием и передачу.
В проекте используются первые две, по которым при помощи несложного протокола передаются команды управления светодиодами на плате.
Краткое описание протокола можно найти в Doc\protocol.txt
И что дальше?
Ну а дальше — куда приведет фантазия. Ковырять USB рекомендую начинать с файла дескрипторов usb_desc.c, потом поиграться с ендпоинтами.
Если есть желание — можно попробовать реализовать один из стандартных классов USB-устройств, или не париться и сделать свой протокол под свои задачи.
На этом пока все. Если эта статья покажется кому-то интересной и полезной, во второй части немного напишу о драйверах и софте.
Файлы, используемые в статье собраны тут
P.S.: Хоть это и первый блин, конструктивная критика, естественно, принимается.
Читайте также: