STM32 и USB (практика)

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: STM32 и USB (практика)

Сообщение Eddy_Em »

[uquote="VladislavS",url="/forum/viewtopic.php?p=4004250#p4004250"]чем отличается SET_FEAUTRE от SET_REPORT наверняка даже не подозревает.[/uquote]
Не подозреваю. Я не использую ненужные хрени. Только то, что нужно для нормальной работы! CDC я тоже сначала, как идиот, насмотревшись чужих решений, сделал, выделяя физическую EP на INTERRUPT, но ее обработчик ничего не делал (как и у всех). Тогда я подумал: а на кой мне черт выделять полезную EP на ничто? И перестал это делать: в конфигурации INTERRUPT EP указана, а фактически ее нет (т.к. она не нужна). И прекрасно все работает. Проверял и на компьютере, и на андроиде. На игровых приставках не проверял, т.к. бессмысленно.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Реклама
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: STM32 и USB (практика)

Сообщение COKPOWEHEU »

сделал, выделяя физическую EP на INTERRUPT, но ее обработчик ничего не делал
А как вы без нее посылаете всякие RTS, CTS и прочие? Я так понял, что она нужна чтобы экстренно предупредить хост что данные больше не помещаются, что потеряна несущая или что-то в этом роде.
Реклама
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: STM32 и USB (практика)

Сообщение Eddy_Em »

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4004330#p4004330"]А как вы без нее посылаете всякие RTS, CTS и прочие?[/uquote]
Никак. Я ими не пользуюсь. Даже на честном RS-232 никогда не пользовался аппаратным контролем.
А вообще, у меня есть weak-обработчик clstate_handler, который вызывается при получении от хоста SET_CONTROL_LINE_STATE. А GET_CONTROL_LINE_STATE я не использую.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: STM32 и USB (практика)

Сообщение COKPOWEHEU »

Никак. Я ими не пользуюсь.
Ну вот и ответ :)
Но иногда они все же нужны, пусть и для связи с антикварным оборудованием. Вы видели, наверное, на Хабре статью, где какой-то парень изобретал USB - 3xUART со всеми управляющими линиями. Значит, иногда необходимость возникает.
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: STM32 и USB (практика)

Сообщение VladislavS »

Мои реализации CDC и Custom HID (работает с USB HID Demonstrator). Работать должно на STM32F0, STM32L0, STM32F1, STM32F3, STM32G4. Разделено на уровни Hardware <-> USB Device <-> USB Class. Проекты IAR, Keil, VisualGDB, makefile GCC linux и win. Кто не любит плюсы, можете не смотреть.
F072-HID.7z
(207.32 КБ) 168 скачиваний
F072-CDC.7z
(217.03 КБ) 171 скачивание
F303-HID.7z
(224.28 КБ) 164 скачивания
F303-CDC.7z
(225.96 КБ) 157 скачиваний
Реклама
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: STM32 и USB (практика)

Сообщение Eddy_Em »

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4004361#p4004361"]Но иногда они все же нужны, пусть и для связи с антикварным оборудованием.[/uquote]
Ну так мой CDC предназначен для организации "общения" с МК. Я не преследую цели из дорогущего МК сделать элементарный преобразователь USB<>UART или USB<>RS-232!!! Такие преобразователи можно недорого на али купить (правда, в случае с RS-232 дешевле сделать самому из PL2303 и MAX3232, готовые адово дорогие ­- от 400р за штучку на али).

Я даже не CDC использую, т.к. мне не нравится /dev/ttyACMx в именовании + на мастдайках вроде бубунты по дефолту запущен modemd, который ACM пытается перехватить на себя и занимает порт. Я эмулирую PL2303, благодаря чему девайс именуется как нормальный /dev/ttyUSBx и никакой modemd в мастдайках его не пытается заблокировать.
Что до HID, сделал его развлекухи ради, т.к. у меня вообще нет задач, требующих эмуляции мыши или клавиатуры. Вообще не представляю себе, зачем кому-то может понадобится HID, если только он не изготавливает кастомные клавы-мыши-джойстики.

P.S. COKPOWEHEU, за уход от калокуба - однозначный плюс. Теперь остается вам еще вместо игровой прошивки поставить себе операционную систему (хотя бы мастдайку вроде бубунты или красношапки).
Последний раз редактировалось Eddy_Em Пт мар 26, 2021 12:29:21, всего редактировалось 3 раза.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Реклама
Аватара пользователя
azhel12
Встал на лапы
Сообщения: 145
Зарегистрирован: Пн апр 02, 2012 15:56:23

Re: STM32 и USB (практика)

Сообщение azhel12 »

Мои реализации CDC и Custom HID (работает с USB HID Demonstrator)
Круто, спасибо, буду вдохновляться. Очень удобно что-то делать, если есть под рукой рабочий пример.

Я же за ночь добился того, что можно с хоста (через HID Demonstrator пробовал) управлять светодиодом. Код получается вполне компактным, как и прошивка (2116 Кб). Теперь надо переходить к CDC.
Спойлер

Код: Выделить всё

#include <clock.h>
#include <exti.h>
#include <iopins.h>
#include <pinlist.h>
#include <usb.h>

using namespace Zhele;
using namespace Zhele::Clock;
using namespace Zhele::IO;
using namespace Zhele::Usb;

using Report = HidReport<
        0x06, 0x00, 0xff,              // USAGE_PAGE (Generic Desktop)
        0x09, 0x01,                    // USAGE (Vendor Usage 1)
        0xa1, 0x01,                    // COLLECTION (Application)
        0x85, 0x01,                    //   REPORT_ID (1)
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
        0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
        0x75, 0x08,                    //   REPORT_SIZE (8)
        0x95, 0x01,                    //   REPORT_COUNT (1)
        0xb1, 0x82,                    //   FEATURE (Data,Var,Abs,Vol)
        0x85, 0x01,                    //   REPORT_ID (1)
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x91, 0x82,                    //   OUTPUT (Data,Var,Abs,Vol)
        0xc0                           // END_COLLECTION
    >;

using HidDesc = HidDescriptor<0x1001, Report>;

using LedsControlEpBase = OutEndpointBase<1, EndpointType::Interrupt, 4, 32>;
using EpInitializer = EndpointsInitializer<DefaultEp0, LedsControlEpBase>;

using Ep0 = EpInitializer::ExtendEndpoint<DefaultEp0>;
using LedsControlEp = EpInitializer::ExtendEndpoint<LedsControlEpBase>;

using Hid = HidInterface<0, 0, 0, 0, HidDesc, LedsControlEp>;
using Config = HidConfiguration<0, 250, false, false, Report, Hid>;
using MyDevice = Device<0x0200, DeviceClass::InterfaceSpecified, 0, 0, 0x0483, 0x5711, 0, Ep0, Config>;

using Led = IO::Pc6; // Use Pc13 for BluePill.

void ConfigureClock();
void ConfigureLeds();

int main()
{
    ConfigureClock();
    ConfigureLeds();

    Zhele::IO::Porta::Enable();
    MyDevice::Enable();

    for(;;)
    {
    }
}

void ConfigureClock()
{
    PllClock::SelectClockSource(PllClock::ClockSource::Internal);
    PllClock::SetMultiplier(12);
    PllClock::SetDivider(2);
    ApbClock::SetPrescaler(ApbClock::Div1);
    SysClock::SelectClockSource(SysClock::Pll);

    Zhele::Clock::Hsi48Clock::Enable();
    Zhele::Clock::SysCfgCompClock::Enable();
}

void ConfigureLeds()
{
    Led::Port::Enable();
    Led::SetConfiguration<Led::Configuration::Out>();
    Led::SetDriverType<Led::DriverType::PushPull>();
    Led::Set();
}

template<>
void LedsControlEp::Handler()
{
    LedsControlEp::ClearCtrRx();
    uint8_t* buffer = reinterpret_cast<uint8_t*>(LedsControlEp::Buffer);
    bool needSet = buffer[1] != 0;

    switch(buffer[0])
    {
    case 1:
        needSet ? Led::Set() : Led::Clear();
        break;
    }

    LedsControlEp::SetRxStatus(EndpointStatus::Valid);
}

extern "C" void USB_IRQHandler()
{
    // Sorry, but you must write device`s CommonHandler call by yourself.
    MyDevice::CommonHandler();
}
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: STM32 и USB (практика)

Сообщение VladislavS »

[uquote="azhel12",url="/forum/viewtopic.php?p=4004394#p4004394"]Код получается вполне компактным, как и прошивка (2116 Кб).[/uquote]У меня HID на один диод и кнопку на F072 получается вот так

Код: Выделить всё

C:/CPP/GNU Tools ARM Embedded/10-2020-q4-major/bin/arm-none-eabi-size Bin\Release/F072-HID.elf
   text    data     bss     dec     hex filename
   2072       8      96    2176     880 Bin\Release/F072-HID.elf
Это с полной реализацией USB Device, строковыми дескрипторами, HID_REPORT на 5 REPORT_ID. Задача ужиматься не стояла. В принципе, ещё поджать есть куда.
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: STM32 и USB (практика)

Сообщение COKPOWEHEU »

Ну так мой CDC предназначен для организации "общения" с МК.
В таком случае вам ни RTS/CTS/DTR биты не нужны, ни interrupt endpoint. Но они не нужны ВАМ. Не надо говорить, что они не нужны никому и никогда.
Ну и опять же переходник на COM-порт может быть побочной фичей типа "ноги свободные остались, почему бы и нет".
Я даже не CDC использую, т.к. мне не нравится /dev/ttyACMx в именовании + на мастдайках вроде бубунты по дефолту запущен modemd, который ACM пытается перехватить на себя и занимает порт.
На Debian тоже какая-то гадость его занимает. Но я вылечил это проще: выставил class/subclass/protocol в 2/2/0 вместо 2/2/1. Оно все равно отображается как /dev/ttyACM, но посторонние программы не лезут.
Хотя ваш вариант тоже интересный, надо будет его поковырять.
Вообще не представляю себе, зачем кому-то может понадобится HID, если только он не изготавливает кастомные клавы-мыши-джойстики.
Я тут недавно читал на него документацию, так там чего только нет! Ладно клавомыши, это все привыкли. Но там есть джойстик для танка и подводной лодки, есть индикатор активности жесткого диска и фиг поймешь чего еще. В общем-то всем рекомендую ознакомиться если не для практического использования, то хотя бы для поднятия настроения.
Ну и не стоит забывать про совсем нестандартные устройства, которым много данных не надо, но и писать ядерный драйвер лень. Я, например, пару лет назад делал таким способом переходник с научного вольтметра е-24 (он по COM-порту работает, да еще довольно заковыристым способом) на USB. Правда, делал на ATmega8. Почему бы и нет: скорости там нулевые, а кроссплатформенный драйвер писать все еще лень. А так оно работает себе потихоньку, никому не мешает.
Я же за ночь добился того, что можно с хоста (через HID Demonstrator пробовал) управлять светодиодом. Код получается вполне компактным, как и прошивка (2116Кб).
Хм, а у меня 2308 кБ для f103 и 2792 кБ для L151. Отсюда два вопроса: что в моем коде занимает столько места? И почему в коде для L151 оно занимает места еще больше? Хотя, конечно, сейчас я это ковырять не буду.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: STM32 и USB (практика)

Сообщение VladislavS »

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4004412#p4004412"]что в моем коде занимает столько места?[/uquote]

Код: Выделить всё

C_FLAGS := -ffunction-sections -fdata-sections -fno-exceptions -Wall
CPP_FLAGS := -ffunction-sections -fdata-sections -fno-exceptions -fno-rtti -Wall
AS_FLAGS = $(C_FLAGS)
LD_FLAGS := -Wl,--gc-sections -nostartfiles -specs=nano.specs -specs=nosys.specs
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: STM32 и USB (практика)

Сообщение COKPOWEHEU »

VladislavS, если добавить ваши флаги бездумно, прошивка вырастает на 52 байта. Если немного пошаманить - уменьшается на 20 байт.
Так что, скорее код причесывать надо.
Но лень. Надо еще с прерываниями и изохронными точками разобраться.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: STM32 и USB (практика)

Сообщение VladislavS »

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4004465#p4004465"]Так что, скорее код причесывать надо.[/uquote]Смотрел ваш код. И как-то само придумалось. Даже не знаю, почему раньше не пришло в голову. Было

Код: Выделить всё

// По SetAddres
USB_Addr = setup_packet.wValue;


// По EP0 CTR_TX
if( (USB->DADDR & USB_DADDR_ADD) != USB_Addr )
{
  USB->DADDR = USB_DADDR_EF | USB_Addr;
}
Можно сделать вот так

Код: Выделить всё

// По SetAddres
USB_Addr = USB_DADDR_EF | setup_packet.wValue;

// По EP0 CTR_TX
USB->DADDR = USB_Addr;
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: STM32 и USB (практика)

Сообщение Eddy_Em »

COKPOWEHEU, так ведь если сравнивать "чистый код", то функционала он никакого нести не будет. А для его проверки идет всякая обвязка (хоть даже просто эхо введенного), что уже немного раздувает код.
Я вот тоже когда почистил свой сниппет для PL2303 от всякого ненужного (типа UART и т.п.), бинарник на пару килобайт уменьшился.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: STM32 и USB (практика)

Сообщение VladislavS »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4004476#p4004476"]так ведь если сравнивать "чистый код"[/uquote]У меня в примерах для HID управление светодиодами и опрос кнопки. Для CDC эхо, управление светодиодом и отправка тестового слова по кнопке. Так что, не совсем голяк.
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: STM32 и USB (практика)

Сообщение COKPOWEHEU »

Можно сделать вот так
Вы имеете в виду писать USB->DADDR при каждом вызове ep0 IN? Не нравится мне эта идея. Не могу точно сформулировать почему, но не нравится.
COKPOWEHEU, так ведь если сравнивать "чистый код", то функционала он никакого нести не будет.
Я сравниваю свой код из статьи, который зажигает два светодиода и отсылает состояние кнопки.
Кстати, это одна из причин почему разница объема меня не пугает. Чтобы аргументированно издеваться над сторонниками Куба достаточно, что разница объема более чем пятикратная, а остальное можно списать на погрешность функционала, на забытые отладочные куски и прочее.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: STM32 и USB (практика)

Сообщение VladislavS »

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4004491#p4004491"]Не нравится мне эта идея. Не могу точно сформулировать почему, но не нравится.[/uquote]Читать каждый раз вам нравится, значит? А записать то же значение, которое там уже есть, нет? Проверено, работает хорошо. Получается быстрее и меньше кода

Код: Выделить всё

//case 0x00: // EP0 CTR_TX
//  STM32_USB_DEVICE::ApplyAdr();
        LDR      R2,??USB_IRQHandler_0+0x8
        LDR      R1,[R2, #+28]  
        STRH     R1,[R0, #+12]
Так как от базы R2 потом и остальные переменные адресуются, то получаются расходы только одна LDR и одна STRH. Не забываем, что это прерывание, ту всё должно быть как выстрел.
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: STM32 и USB (практика)

Сообщение COKPOWEHEU »

Так оперативку же читать, а не регистр периферии. Мало ли что они там навесили на операцию записи. Быстрее было бы сделать для этой штуки отдельный обработчик, но это хуже по объему кода, я проверял.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: STM32 и USB (практика)

Сообщение VladislavS »

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4004561#p4004561"]Так оперативку же читать, а не регистр периферии.[/uquote]Это в моей реализации было оперативку, а в вашей как раз и оперативку, и периферию. Плюс битовые операции и сравнение.

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4004561#p4004561"]Мало ли что они там навесили на операцию записи.[/uquote]Ничего, я же говорю, проверено. Да и вызывается это только из ep0.

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4004561#p4004561"]Быстрее было бы сделать для этой штуки отдельный обработчик, но это хуже по объему кода, я проверял.[/uquote]Это как?

Я вообще не настаиваю, не хотите пользоваться, ваше дело. В моём коде это поселилось. :)
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: STM32 и USB (практика)

Сообщение COKPOWEHEU »

Это как?
Колбэк на ep0_in после ресета выставить в функцию, которая будет настраивать адрес и подменять себя на "нормальный" колбэк.

Код: Выделить всё

void ep0_addr(){
  if( (USB->DADDR & USB_DADDR_ADD) != USB_Addr ){
    USB->DADDR = USB_DADDR_EF | USB_Addr;
    ep0_in_handler = ep0_in;
  }
}

void ep0_in(){
...
}
Это в моей реализации было оперативку, а в вашей как раз и оперативку, и периферию. Плюс битовые операции и сравнение.
Да, вы правы, это надо исправить. Посмотрю сработает ли мой вариант с колбэками и не слишком ли он раздует код. Вроде бы терпимо получалось.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: STM32 и USB (практика)

Сообщение VladislavS »

Да, с подменой понятно. Но вызов колбэка по скорости скорее всего проиграет проверке значения USB_Addr. Да и лишнее это, тут нет узкого места. Вопрос чисто спортивный, ценой в 8 байт размера прошивки в моём случае.
Ответить

Вернуться в «ARM»