Неприємності з програмуванням порта USB в контролері STM32F103C8T6

Вместо рекламы

Россиянин, ты захотел скачать файл ? Или почитать чего интересного ?
Останови свою войну в Украине !

—————————

Реклама від Google



Анонс статті: порт USB в контролері STM32F103C8T6 буде працювати добре, навіть якщо раніше не працював.
Традиційна задача для інженера-електронщика, що розробляє нову техніку: передавати інформацію через порт USB в “якийсь свій пристрій” і приймати інформацію з “якогось свого пристрою” через порт USB в керуючу програму. Інженер-електронщик думає, що для цього доведеться добре вивчити протокол обміну з USB-пристроями, і цей процес навчання можна коротко охарактеризувати одним словом: БІДА. Автори протоколів обміну через порт USB, а це група компаній Compaq, DEC, IBM, Intel, Microsoft, NEC та Nortel, добре нагнули всіх, хто вивчає цей протокол, бо протокол непристойно універсальний, а значить, складний. На щастя, є прості кроки, як уникнути цієї навчальної біди.

Я не знаю, з якими контролерами любить працювати читач цієї статті, але для всіх є простенький вихід: на щастя, автори USB передбачили такий клас пристроїв, який називається “комунікаційний пристрій” (CDC, Communications Device Class). Наступне покращення ситуації – готові, вже написані драйвери, які створюють “віртуальні COM-порти” (VCP). Керуюча програма на комп’ютері, незалежно від того, в якому програмному середовищі вона розробляється, без проблеми передає дані в умовний “COM-порт” і приймає дані з цього “COM-порта”. Також програма без проблеми прочитує стан цього COM-порта, щоб знати, чи він взагалі працює, чи він відкритий, чи не зайнятий, чи справний. Але доведеться також запрограмувати якийсь використовуваний контролер, який через свій USB-порт буде обмінюватись даними з комп’ютером, і тут трохи складніше.

Ми не хочемо зробити оптимально, ми хочемо зробити швидко і дешево, і тут на думку приходить використання дешевенької і непоганої плати на основі мікроконтролера STM32F103C8T6. Власне, ось вона:


В Інтернеті цю плату можуть називати “blue pill” (блакитна пігулка). Її основні характеристики:
– вона анекдотично дешева.
– вона доступна в продажу.
– вона має аж три послідовні порти USART, порт MicroUSB, деяку кількість виводів, які можуть бути чи цифровими логічними виходами, чи цифровими логічними входами, є навіть власний АЦП, і ще має багато корисних для програміста приправ.
– сама мікросхема контролера випускається компанією “STMicroelectronics” (ну, насправді китайцями), яка надає до своєї продукції потужні, непогані засоби розробки програм, і безкоштовно, це я згадав про програму STM32CubeIDE.
Коротко: купуєш дешево, програмуєш безкоштовно. А чому, власне, обов’язково брати саме цей контролер ? Ні, варіантів насправді багато, ми обговорюємо лише один з прикладів, популярний, і з багатьма заскоками і дрібними недоробками.

На етапі освоєння програмування контролерів із сімейства “STMicroelectronics” я мусив прочитати немало довідкового матеріалу, і тепер можу поділитись з вами деякими корисними знаннями. Ми з вами спрощуємо нашу роботу.
З усіх могутніх можливостей USB ми вибираємо комунікаційний клас пристроїв CDC.
Ми не пробуємо конструювати велосипед, а використовуємо готові програмні засоби, люб’язно надані нам компанією “STMicroelectronics“. Щоб не мати зайвих проблем із налагоджуванням порта USB, ми для написання базової частини нашої програми використовуємо, наприклад, STM32CubeIDE, чи STM32CubeMX, це вже хто що завантажив з Інтернета.
Використовуємо якусь із цих програм для написання “серцевини” програми контролера, і з правильно налаштованою створеною нами програмою для контролера цей контролер буде нормально працювати через USB, і не буде нас мучити традиційними “не працює” чи “працює якось не так”. А саме приємне – нам не доведеться вчити весь той кошмар, щоб самому, без готових зразків, програмувати в контролері порт USB. Хто освоїть програму  STM32CubeIDE, той тою самою програмою буде також налагоджувати роботу контролера, хоча можна і “платною” EWARM, вона “ковтає” також контролери інших виробників.
Починаємо створювати серцевину майбутньої програми контролера. Запустили середовище для початкового програмування контролера, STM32CubeIDE, чи STM32CubeMX (потім буде наладка програми, її можна робити тим самим STM32CubeIDE), вказали, що нам треба STM32F103C8T6, а далі вибрали в меню:


Зрозуміло, що вибрали (відмічено галочкою) порт USB, а також, може, програміст додатково захоче послідовний порт, то вибрано ще й USART2. Якийсь із таймерів також корисно вибрати, без таймерів в програмі для контролера – ну, ніяк. А ще в групі RCC обов’язково треба вказати, що використовується кварц, для параметра High Speed Clock ставимо Crystal/Ceramic Resonator. Також в групі GPIO дуже корисно поставити на логічний вихід (OUT) лінію PC13,, адже на платі до вивода PC13 підключено корисний діагностичний світлодіод. Ось, на малюнку видно, що ми вибрали PC13, поставили на логічний вивід, та ще й з відкритим колектором (Output Open Drain). Ним будемо засвічувати чи гасити діагностичний світлодіод, який вже є на платі.


Ще треба дуже уважно поставити ВСІ ПОТРІБНІ параметри для USB. Не забудемо поставити галочку на Device (FS) (тобто нехай працює на повній швидкості, Full Speed).


Наступне, в підгрупі MiddleWare виберемо USB Device. і далі вибираємо Communication Device Class, і нам дозволено змінити текстовий рядок, відмічений стрілочкою. Більше нічого із цих параметрів міняти не варто, бо операційна система може неправильно впізнати наш USB-пристрій. Нам дозволено використовувати ідентифікатори VID і PID, які належать компанії “STMicroelectronics“, і не платити 5000$ за свій ідентифікатор.


Переходимо до групи “Clock Configuration” для встановлення лічильників, подільників, перемножувачів, і всього іншого добра для нормальної роботи контролера. По-перше, для USB має бути частота 48 MHz, бо не запрацює. По-друге, ця частота має синхронізуватись точним кварцом, на платі впаяний кварцевий резонатор на 8 MHz, ми його вкрутили в попередніх установках параметрів. Словом, якщо зробити, як на малюнку, то буде добре.


Далі трохи легше. В групі параметрів Project Manager вказуємо, в якій саме папці буде створено наш проєкт, але більш важливо не забути вказати, якою програмою ми будемо користуватись для створення самої програми контролера. Варіантів у нас небагато, або платний EWARM, або безкоштовний STM32CubeIDE. EWARM, звісно, козирніший, але за гроші, а його конкурент безкоштовний.

Натиснувши Generate code, отримаємо початковий “проєкт” програми контролера. Не дуже радійте, роботи ще багато.
Запустимо вибране нами середовище, в якому будемо працювати з програмою контролера. Я так собі уявляю, що ви добре (чи майже добре) освоїли роботу з вибраним середовищем, тому переходимо безпосередньо до корекції програми контролера.

uint32_t dow=0;         // це ми додали, тут буде довжина прийнятого із USB
uint8_t Bufrea[64];     // це ми додали, це наш буфер для прийому із USB

int main(void)            // починається програма
{
int i1=0;                     // щоб моргати світлодіодом на платі
HAL_Init();                // далі – штатні ініціалізації
SystemClock_Config();
MX_GPIO_Init();
// Дуже цікаво. Дехто в Інтернеті рекомендує на старті програми на короткий час (наприклад, від 10 мілісекунд до 100 мілісекунд) поставити лінію PA12 в “0“, а же потім “відпустити” її в стан, придатний для роботи USB. Лінії PA11 і PA12 – це саме ті лінії, які в контролері призначені для роботи з USB. Але (чомусь) у мене завжди чудово працює і без цього фокуса, тому я в програмі поставив коментування.
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);// лінію PA12 в нуль
// GPIO_InitStruct.Pin = GPIO_PIN_12;                         // номер лінії 12
// GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;// логічний вихід
// GPIO_InitStruct.Pull = GPIO_NOPULL;                     // обійдеться без резисторів
// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;// тактування низькою частотою
// HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);             // ініціалізували лінію PA12 (група GPIOA)
// HAL_Delay(100);                                                         // почекали
// HAL_GPIO_DeInit(GPIOA, GPIO_PIN_12);               // відпустили лінію PA12
//
// а тут вже ініціалізація порта USB.
MX_USB_DEVICE_Init();
Аналізуємо програму далі. Тут, наприклад, ще якісь наші ініціалізації.
MX_TIM2_Init();
MX_USART2_UART_Init();
//   ще можуть бути додаткові ініціалізації, потрібні програмісту
//  
і далі починається нескінченний робочий цикл контролера.
//
//   Ой, ні. Ще одна можлива рекомендація. Для тих, у кого комп’ютер
//    не хоче впізнавати підключений через USB контролер, є ще одна
//    рекомендація: перед нескінченним циклом while поставити затримку.
//    Може, секунду, а може, дві.
// HAL_Delay(1000);
//   (хоча в мене завжди нормально працювало і без затримки).
//   Нарешті, нескінченний цикл.

while (1)
{
// Що робити для передачі даних із контролера в USB комп’ютера:
// Просто, коли потрібно, звертаємось до підпрограми CDC_Transmit_FS
// (наприклад, CDC_Transmit_FS(“proba”,5);) // (вказали буфер і довжину)
//
// Що робити для прийому даних через USB в контролер:
// В функцію static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
// яка знаходиться в модулі usbd_cdc_if.c треба на початку функції
// додати пару рядків, які при виконанні функції скопіюють
// прийняту інформацію в буфер, потрібний безпосередньо програмісту,
// заодно вкажуть довжину прийнятого (кількість прийнятих байт).
// Наприклад, ми додали в цю функцію (на початку самої функції):
    memcpy(Bufrea, Buf, *Len);// прийняту інформацію – в наш буфер
    dow=*Len;                             // це довжина прийнятого
//
// І буфер, і змінна для його довжини оголошується в головному тілі
// програми (це ми бачимо на початку програми):
   uint32_t dow;
   uint8_t Bufrea[64]; (довжина буфера, можливо, може бути і більша,
//  але навіщо ? Великий буфер даних, які програміст захоче передати
//  по USB на контролер, буде порізаний на “макарони” довжиною по 64 байти)

//
// Перед функцією CDC_Receive_FS не забути вказати, що потрібне зовнішнє звертання
// до буфера Bufrea і до довжини прийнятого, змінної dow,
//  бо нас запитають: а де лежить dow і Bufrea.

   extern uint32_t dow;
   extern uint8_t Bufrea[];
//
//      Отже, що далі в нескінченному циклі ?
  if(dow!=0)         // Ця змінна покаже, чи щось прийняли через USB
   {CDC_Transmit_FS(“proba”,5);// для тесту. Коли прийняли щось із USB, видаємо у відповідь щось тестове, щоб бачити, що вивід на USB також працює. Програма на комп’ютері, наприклад, щось періодично видає на наш контролер, а потім перевіряє, що відповів контролер, все робиться через віртуальний COM-порт.
//   Якщо щось прийняли, то або засвітимо, або погасимо контрольний світлодіод.
   if(i1==0)HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
   else HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
   i1=1-i1;
   dow=0;};  // признак, що цей блок вхідної інформації ми обробили

Отже, зробили примітивний тест. Звісно, в нормальній зробленій вами програми замість тупого копіювання прийнятої інформації в якийсь інший буфер, ви можете організувати запис в кільцевий буфер значного розміру, щоб у вас не губилась інформація, якщо комп’ютер буде гнати дані в USB занадто швидко. Крім того, в компанії “STMicroelectronics” не дуже заморочувались, щоб зробити бібліотеку до контролера справді хорошою, там вирішили, що достатньо, якщо бібліотека працює. Тому з виводом інформації із контролера через USB на комп’ютер є незначне обмеження: передасть лише перші 64 байти. Значить, вивід більшого буфера пам’яті організовуєте “по кусках” довжиною 64 байти.
А в нашому простому тесті, якщо комп’ютер щось корисне передасть на USB-порт контролера, то зміниться свічення контрольного світлодіода, він або засвітиться, або погасне, і після кожного прийому інформації контролер передає через USB в комп’ютер тестову відповідь. Тест простий. Тепер треба подумати, як зашити програму в контролер.
Що тут думати ? Треба придбати дешевенький програматор ST-LINK V2, ось такий:


Цим програматором можна не лише зашити програму в контролер, а також налагоджувати її. Програматор підключається до контролера через роз’єм SWD, а також до комп’ютера через окремий порт USB.
(вибачте, що нагадую. Працюєте з ввімкненим контролером і ввімкненим комп’ютером, а значить, корпус комп’ютера і “земля” на контролері мають бути ЗАВЖДИ з’єднані між собою. Відключите потім, коли все налагодите.)
В меню програм, придатних для розробки програм для контролера, чудово передбачена робота з таким програматором. І навіть не думайте, що будете шити контролер через порт контролера USB, бо зараз ми його використовуємо для інших цілей.
Розібрались, зашили. І це все ? Ні, головне зараз почнеться.
Ми кабелем “MicroUSB – USB” з’єднали запрограмований контролер із комп’ютером. Зараз щось має змінитись. Що має змінитись ?
На комп’ютері в розділі “Диспетчер пристроїв” є список різного обладнання комп’ютера, і серед цього списку – COM-порти. Ви вставляєте в USB-порт комп’ютера кабель, підключений до MicroUSB контролера, через кілька секунд виймаєте. Щось змінилось в списку Диспетчера пристроїв ?
Погано, якщо нічого не змінилось.Виходить, що операційна система комп’ютера не бачить підключеного контролера і не підганяє драйвер для нього, не створює додатковий віртуальний COM-порт. Почнемо розбиратись з причинами.
Кабель. У вас в руках може бути кабель, призначений не для обміну даними, а для зарядки чого-небудь від блока живлення. Характерний признак: лінії D+ і D- в такому кабелі закорочені між собою резистором з номіналом приблизно 50 Ом, а буває, повністю накоротко закорочені. Значить, треба попробувати з іншим кабелем, а на цьому написати “лише для зарядки”.
Дехто вражено дивується: навіщо китайці закоротили між собою виводи D+ і D- ? Дивно, але це корисна штука. Деякі телефони, побачивши закоротку між цими лініями, починають вірити, що їх підключили до досить потужної зарядної станції, і дозволяють собі заряджатись ЗНАЧНО швидше. Дрібниця, а приємно.
Живлення. Відключіть програматор від вашого контролера, і знову перевірте, чи бачить комп’ютер, що до нього через USB підключають контролер.
Резистор. Є рекомендації, щоб в контролері шина D+ (це лінія PA12) була підключена до 5 Вольт резистором приблизно на 1.5 кОм. Хоча у мене ніколи не хотіло резистора, але попробувати треба.
Чи працює ? Якщо ви дочитали до цього місця, значить, ви програміст. Трошки змініть програму, щоб світлодіод моргав, незалежно від обміну через USB. Це контроль, чи програма контролера взагалі працює.
Наладка до ваших послуг. Поставте отладчиком контрольну точку зупинки після всіх ініціалізацій. Чи перейшла програма на свій нескінченний цикл ? Чи зупинилась ще раніше ?

А якщо Диспетчер пристроїв показує якусь реакцію на вставляння і виймання USB-кабеля, підключеного до контролера ? Це значно краще. Які тут варіанти ?
З’являється “невідомий пристрій”. Це добре, треба ще в комп’ютер завантажити потрібний драйвер.
З’являється пристрій з признаком “щось не так”. Це добре, також треба драйвер.
Зараз буде драйвер.
Ось вам один із варіантів потрібного драйвера, він також наданий компанією “STMicroelectronics“. Не чіпляйтесь до версії, це не важливо. Якщо натиснути на надпис Драйвер, цей драйвер завантажиться, і тепер справді з’являється “віртуальний COM-порт”, і без признаків, що з ним щось не так.

Отримали обмін з комп’ютером (ну, з хостом) через USB, але обмін не ідельний:
– максимальна швидкість обміну буде менша, ніж заявлені 12 Мбіт/сек.
– тепер, працюючи з таймерами і портами USART, ставте для них найвищий рівень переривань, бо активований порт USB майте третину тактів контролера відкушує собі на переривання, а в точці переривання працює дуже неефективно, майже стоїть. Щоб зробити краще, треба мати хороший досвід і хороші знання про програмування USB, а не лише “щоб працювало”. Стандартна бібліотека, я мушу повторюватись, трохи неефективна, хоча і працююча.
– драйвером в комп’ютері не передбачено передачі в контролер формальних характеристик віртуального COM-порта (швидкість, контроль парності). Добре, що це не завжди потрібно.

Це все, що можу порадити. Надіюсь, що допоможе.

—————————————-

В Україні війна ! Адміністрація сайту допомагає нашим ЗСУ, регулярно донатить на необхідні військові потреби. І ви не забувайте це робити ! Це наша країна, і нам її відстоювати.
Схема мануал телевизора шасси, схему скачать бесплатно, ищу схему модулей, ищу шасси телевизора, схемы телевизоров, мануалы

Залишити відповідь (Leave a Reply)