Платформа драйверов USB-гаджетов
Платформа драйверов USB-гаджетов

1. Как понять структуру гаджета

Протокол USB представляет собой структуру «ведущий-подчиненный»:

Левый — хост, правый — ведомый; USB имеет хост-контроллер UHC и ведомый контроллер UDC. На стороне хоста имеется драйвер устройства USB, а на ведомой стороне — функциональный драйвер USB.

Это означает, что макетная плата может использоваться в качестве USB-хоста и подключаться к мыши, клавиатуре и другим подчиненным машинам. Макетная плата также может использоваться в качестве USB-накопителя и подключаться к ПК, и в этом случае макетная плата является макетной платой; рабская машина. Поэтому нам необходимо освоить два набора драйверных фреймворков. Здесь USB под Linux сложнее, чем I2C и I2C и т.п. вообще не будут считать главный Soc подчиненным, а вот USB нужно учитывать.

В этой статье основное внимание уделяется ситуации, когда главный Soc действует как подчиненный USB-устройство, а Linux предоставляет для него платформу гаджетов.

При написании драйвера USB-устройства необходимо выполнить следующие основные действия:

  • читать принимает различные дескрипторы оборудованияиз,Например, дескриптор конечной точки,Получить номер конечной точки
  • Используйте базовый USB Host Controller водить машинупрограммапоставлятьиз API функция,от endpoint начальствочитать Писатьданные

При моделировании USB-устройства на основе платформы драйверов гаджетов возможности передачи данных конечной точки обеспечиваются базовым драйвером контроллера USB-устройства. Все, что нам нужно сделать, это:

  • Предоставление различных дескрипторов устройств
  • Используйте базовый USB Device Controller водить машинупрограммапоставлятьиз API функция,от endpoint придетсяприезжатьданные、обратная связьданные

Гаджет означает «маленькое устройство». В USB-системе Linux это означает «USB-устройство». Драйвер гаджета используется для имитации USB-устройства. Настоящее USB-устройство состоит из двух основных элементов:

  • Как выразить себя?
    • каждый USB Device Все 1 дескриптор устройства
    • Все 1 или несколько дескрипторов конфигурации
    • Дескриптор каждой конфигурации содержит 1 илинесколькодескриптор интерфейса
    • каждыйдескриптор интерфейс Есть 0 несколько дескрипторов конечных точек
  • как действоватьданныепередача инфекции?
    • Передача через конечную точку
    • Есть конечные точкииздействоватьфункция

В процессе обучения очень полезно помнить следующие несколько моментов:

  • Различные структуры дескрипторов
  • USB-хост получает гаджет различные дескрипторы процесса
  • Передача данных из процесса

2. Понять структуру гаджета с точки зрения аппаратного и программного обеспечения.

Ядром передачи USB является конечная точка, которую можно использовать для отправки и получения данных. В верхней части конечной точки вы можете имитировать последовательный порт USB, сенсорный экран USB и камеру USB. С этой точки зрения структуру гаджета можно разделить на два уровня:

  • Операции на конечных точках низкого уровня
  • Верхний слой имитирует различные USB-устройства.

2.1 Аппаратная работа низкого уровня_драйвер UDC

На разных платформах используются разные модели USB-контроллера. Метод подтверждения модели состоит в том, чтобы декомпилировать из dtb, найти узел, содержащий символ otg, и выполнить поиск совместимого узла dts в коде Linux, чтобы найти соответствующий драйвер подчиненного USB-контроллера.

Код базовой конечной точки нужно начать анализировать с драйвера UDC:

  • IMX6ULL изкод:Linux-4.9.88\drivers\usb\chipidea\ci_hdrc_imx.c
Язык кода:javascript
копировать
  ci_hdrc_imx_probe
      ci_hdrc_add_device
       pdev = platform_device_alloc("ci_hdrc", id);
  
  
  // Linux-4.9.88\drivers\usb\chipidea\core.c
  static struct platform_driver ci_hdrc_driver = {
   .probe = ci_hdrc_probe,
   .remove = ci_hdrc_remove,
   .driver = {
    .name = "ci_hdrc",
    .pm = &ci_pm_ops,
   },
  };
  
  ci_hdrc_probe
       ret = ci_hdrc_gadget_init(ci);
         udc_start      
  • STM32MP157 изкод:Linux-5.4\drivers\usb\dwc2\platform.c
Язык кода:javascript
копировать
  dwc2_driver_probe
      retval = dwc2_gadget_init(hsotg);    

2.2 Работа программного обеспечения верхнего уровня

Как работает программное обеспечение при моделировании различных USB-устройств? В качестве примера рассмотрим доступ к устройству и получение дескриптора:

  • Host Чтобы назначить адрес и отправить его на устройство: независимо от того, какое устройство вы хотите эмулировать, Gadget Все должны получить адрес, эта часть состоит из usb_gadget (Изведение, связанное с аппаратным обеспечением программа для машины) реализация
  • Host Для получения различных дескрипторов эти дескрипторы предоставляются верхним уровнем вывода. машинупрограммапоставлятьиз
  • Как Пучок прошел верхний уровень дескриптора Первый этажиз usb_gadget передал обратно в Хозяин? Также необходим средний слой. Хозяин При получении дескриптора,Метод фиксированный и универсальный.,Эти методы могут быть унифицированы ядром с помощью,Это: usb_gadget_driver.

Поэтому с точки зрения получения дескрипторов программное обеспечение верхнего уровня делится как минимум на 2 уровня:

  • usb_gadget_driver: реализовать некоторые общие цели USB Методы доступа, такие как Host При доступе к дескриптору usb_gadget_driver поставлять
  • существует Вышеуказанное приводит к различным дескрипторам,на самом деле,дескрипторизпоставлять ХОРОШОкразделен на две частислой:
    • дескриптор оборудования, дескриптор конфигурации: решается программистом, usb_composite_driver поставлять
    • Дескриптор интерфейса, конечная точка Дескриптор: заранее реализован ядром, обычно используется function driver поставлять

Уровень программного обеспечения можно доработать, как показано ниже:

Здесь задействованы 2 структуры:

  • usb_composite_dev: собирает различные дескрипторы и имеет usb_funciton связанный список(выполнитьданныепередача инфекции)
Язык кода:javascript
копировать
  struct usb_composite_dev {
   struct usb_gadget  *gadget;
   struct usb_request  *req;
   struct usb_request  *os_desc_req;
  
   struct usb_configuration *config;
  
   /* OS String is a custom (yet popular) extension to the USB standard. */
   u8    qw_sign[OS_STRING_QW_SIGN_LEN];
   u8    b_vendor_code;
   struct usb_configuration *os_desc_config;
   unsigned int   use_os_string:1;
  
   /* private: */
   /* internals */
   unsigned int   suspended:1;
   struct usb_device_descriptor desc;
   struct list_head  configs;
   struct list_head  gstrings;
   struct usb_composite_driver *driver;
   u8    next_string_id;
   char    *def_manufacturer;
  
   /* the gadget driver won't enable the data pullup
    * while the deactivation count is nonzero.
    */
   unsigned   deactivations;
  
   /* the composite driver won't complete the control transfer's
    * data/status stages till delayed_status is zero.
    */
   int    delayed_status;
  
   /* protects deactivations and delayed_status counts*/
   spinlock_t   lock;
  
   /* public: */
   unsigned int   setup_pending:1;
   unsigned int   os_desc_pending:1;
  };
  • usb_udc:UDC изоригинально означает «usb device controller",usb_udc Есть в структуре usb_gadget (выражать UDC сам), usb_gadget_driver()
Язык кода:javascript
копировать
  struct usb_udc {
   struct usb_gadget_driver *driver;
   struct usb_gadget  *gadget;
   struct device   dev;
   struct list_head  list;
   bool    vbus;
  };

3. Понимание структуры гаджета с точки зрения дескрипторов построения.

Предположим, вы хотите [эмулировать] USB-устройство:

  • Данное USB-оборудование содержит информацию о производителе: она записана в дескрипторе существующего оборудования.,Все дескрипторы коборудования должны использоваться вами для предоставления
  • эти чипы могут быть разных видов.,Это также зависит от вас,Все дескрипторы к Конфигурация должны использоваться вами для создания
  • Определенная Конфигурация Вниз нескольких интерфейсов,Интерфейс — это функция,Linux В ядро ​​заранее встроено множество функций. машинупрограмма,Месток:дескриптор интерфейсаэто ядропоставлятьиз
  • Какие конечные точки необходимы для определенного интерфейса?,Это также различные функции ядра, которые позволяют запускать программу машины.

Возьмем, к примеру, ноль.c:

  • Конфигурация 1:loopback,Host Писанные Дайте, можете выйти как изданные
  • Конфигурация 2:sourcesink,Host Писатьданные дают (он просто записывает Внизданные), Ведущий ХОРОШОкчитатьданные(читатьприезжатьиз Вседа0)

Эти файлы задействованы снизу вверх:

При чтении читайте исходный код,Входфункциядаusb_composite_probe(&zero_driver)

Основные функции в процессе вызова функции следующие. Обратите внимание на функцию «xxx_bind», которая означает инициализацию:

  • usb_composite_probe
  • composite_bind
  • zero_bind
  • sourcesink_bind/loopback_bind

Углубленное объяснение процесса построения дескриптора можно привести к следующему рисунку:

  • Создайте структуру usb_composite_dev.
  • Его слои соединены последовательно.,Внутри есть конструкцииоборудованиедескриптор、Конфигурациядескриптор、дескриптор интерфейса、дескриптор конечной точки

4. Понять структуру гаджета с точки зрения получения дескрипторов.

После установки драйвера гаджета (например, modprobe g_zero) он просто конструирует различные дескрипторы. Дескриптор считывается во время перечисления устройств.

При использовании кабеля OTG для подключения компьютера и макетной платы программное обеспечение компьютера выполняет следующие операции:

  • использовать передачу управления,чтение извлечения информации (дескриптор оснащения): первое чтение извлекает,это Просто нужнопридетсяприезжать 8 Байты данных, поскольку первый 8 Данные представляют конечную точку 0 Может передавать максимальную длину из.
  • Хост назначает адрес устройству, а затем отправляет новый адрес устройству.
  • использоватьновый адрес,Перечитать описание оборудования,длина дескриптора оборудования равна 18
  • чтение принимает дескриптор конфигурации: он передает длину 255,хочу один раз Пучоккогдавперед Конфигурациядескриптор、это Внизлапшаиздескриптор интерфейса、дескриптор конечной точкивсечитатьпублично заявить。
  • read принимает дескриптор символа.

В описанном выше процессе устройство получает данные, отправленные хостом в конечную точку 0, а затем отвечает. Разные устройства-гаджеты выполняют одни и те же операции при возврате дескрипторов хосту, но данные, на которые они отвечают, различны. Отправной точкой анализа исходного кода всегда является функция прерывания:

  • IMX6ULL:ci_irq(drivers/usb/chipidea/core.c)
  • STM32MP157: dwc2_hsotg_irq(drivers/usb/dwc2/gadget.c)

4.1 Основные функции IMX6ULL

IMX6ULL в чипе USB Модель контроллера chipidea,существоватьLinux-4.9.88\drivers\usb\chipidea\core.cпрерывание зарегистрировано вфункция:

Язык кода:javascript
копировать
ci_hdrc_probe
 ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED,
   ci->platdata->name, ci);    

После возникновения прерывания поток обработки данных для конечной точки 0 выглядит следующим образом:

Язык кода:javascript
копировать
// Linux-4.9.88\drivers\usb\chipidea\core.c
ci_irq
 /* Handle device/host interrupt */
 if (ci->role != CI_ROLE_END)
  ret = ci_role(ci)->irq(ci);  // udc_irq
   
   // Linux-4.9.88\drivers\usb\chipidea\udc.c
   udc_irq
                if (USBi_UI  & intr)
                 // Linux-4.9.88\drivers\usb\chipidea\udc.c
                    isr_tr_complete_handler(ci);
                        /* Only handle setup packet below */
                        if (i == 0 &&
                            hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(0)))
                            // Linux-4.9.88\drivers\usb\chipidea\udc.c
                            isr_setup_packet_handler(ci);

функцияisr_setup_packet_handlerСразудаиметь дело с endpoint 0 Получен ключ для управления передачей.

4.2 Основные функции STM32MP157

STM32MP157 в чипе USB Модель контроллера dwc2,существоватьLinux-5.4\drivers\usb\dwc2\gadget.cпрерывание зарегистрировано вфункция:

Язык кода:javascript
копировать
dwc2_gadget_init
 ret = devm_request_irq(hsotg->dev, hsotg->irq, dwc2_hsotg_irq,
          IRQF_SHARED, dev_name(hsotg->dev), hsotg); 

После перерыва,функцияdwc2_hsotg_irqназывается,этоиметь дело с endpoint Есть два способа прервать:

  • использовать DMA час:вызовdwc2_hsotg_epintсправиться
  • Нетиспользовать DMA час:вызовdwc2_hsotg_handle_rxсправиться

кdwc2_hsotg_epintВозьмем в качестве примераанализировать,для endpoint 0 Порядок обработки данных следующий:

Язык кода:javascript
копировать
// Linux-5.4\drivers\usb\dwc2\gadget.c
dwc2_hsotg_irq
  // Обработка прерываний конечной точки
  for (ep = 0; ep < hsotg->num_of_eps && daint_out; ep++, daint_out >>= 1) {
   if (daint_out & 1)
    dwc2_hsotg_epint(hsotg, ep, 0);
  }

  for (ep = 0; ep < hsotg->num_of_eps  && daint_in; ep++, daint_in >>= 1) {
   if (daint_in & 1)
    dwc2_hsotg_epint(hsotg, ep, 1);
  } 

функцияdwc2_hsotg_epintсередина,для endpoint 0 Обработка заключается в следующем:

Язык кода:javascript
копировать
// Linux-5.4\drivers\usb\dwc2\gadget.c
dwc2_hsotg_epint
    if (idx == 0 && !hs_ep->req)
     dwc2_hsotg_enqueue_setup(hsotg); 

функцияdwc2_hsotg_enqueue_setupназываетсячас,Gadget Устройство получено. SETUP Пакет токенов, но еще не получил его DATA0 пакет токенов。dwc2_hsotg_enqueue_setupизэффектда,настраивать、начать запрос, суть заключается в настройке request из complete функция (когда SETTUP Эта функция вызывается после завершения транзакции):

при передаче управления из "наладочной транзакции"Заканчивать,функцияdwc2_hsotg_complete_setupназывается。

4.3 Как обрабатывать передачу управления

Или MX6ULL изфункцияisr_setup_packet_handler,возвращатьсяда STM32M157 изфункцияdwc2_hsotg_complete_setup,этоих Вседасуществовать Gadget Он вызывается после того, как устройство получает «транзакцию SETUP». После получения «транзакции SETUP» вы можете узнать, что хочет сделать эта передача управления (req.bRequest что есть) и тогда с этим можно разобраться.

Как с этим справиться? Можно разделить на 3 слоя:

UDC водить программа машины: аналогична программе «Установить адрес» из управления передачей, в Первый этажиз UDC Это можно решить в драйвере.

  • К таким запросам относятся: USB_REQ_SET_ADDRESS USB_REQ_SET_FEATURE // Есть некоторые запросы, о которых, возможно, потребуется сообщить для исправления. gadget driver USB_REQ_CLEAR_FEATURE // Есть некоторые запросы, о которых, возможно, потребуется сообщить для исправления. gadget driver USB_REQ_GET_STATUS // Есть некоторые запросы, о которых, возможно, потребуется сообщить для исправления. gadget driver
  • водить расположение программы для машины IMX6ULL: Linux-4.9.88\drivers\usb\chipidea\udc.c, функция isr_setup_packet_handler STM32MP157: Linux-5.4\drivers\usb\dwc2\gadget.c, функция dwc2_hsotg_complete_setup

драйвер гаджета: включает дескриптор издействовать

  • К таким запросам относятся: USB_REQ_GET_DESCRIPTOR USB_REQ_SET_CONFIGURATION USB_REQ_GET_CONFIGURATION USB_REQ_SET_INTERFACE USB_REQ_GET_INTERFACE USB_REQ_GET_STATUS // Первый этаж UDC водить машина не может справиться со словами, gadget driver справиться USB_REQ_CLEAR_FEATURE // Первый этаж UDC водить машина не может справиться со словами, gadget driver справиться USB_REQ_SET_FEATURE // Первый этаж UDC водить машина не может справиться со словами, gadget driver справиться
  • водить расположение программы для машины Файл: driver\usb\gadget\composite.c функция:composite_setup

usb_configuration или usb_function из лечения: Это альтернатива из. Большинство передач управления оборудованиемиспользовать соответствуют стандартам USB запрос, но передача управления также может использоваться для реализации связанных запросов. Для этих нестандартных запросов требуется верхний уровень. машинусправиться。

5. Понять структуру гаджета с точки зрения передачи данных.

5.1 Процесс использования

В протоколе USB передачу всегда инициирует хост. В качестве драйвера гаджета это всегда выглядит так:

  • Хотите получитьданные:
    • Сначала построй usb_request: распределение буфер, настройкафункция обратного вызова
    • Поместите usb_request в очередь
    • UDC и Host Заканчивать USB передача, в usb_request Заполните данные и вызовите прерывание usb_request изфункция обратного вызова
  • хочу отправитьданные:
    • Сначала построй usb_request: распределение буфер, в buffer Заполните данные, установите функцию обратного вызова
    • Поместите usb_request в очередь
    • UDC и Host Заканчивать USB передать, поставить usb_request изданныевыдано Хост и запускает вызов прерывания usb_request изфункция обратного вызова

Конечная точка 5.2 — это ядро

USB Объект передачи – это конечную точку, процесс использования выглядит следующим образом:

  • Функцияводить машинури, через endpoint Дескриптор указывает, каким образом требуется конечная точка, например (примечание: bEndpointAddress Там указано направление, но адреса в нем нет, driver\usb\gadget\function\f_loopback.c):
  • Функцияводить машинувнутри,этоиз bind Функция На основе endpoint Дескриптор Первого этаж Применятьраспространять конечная точка, например:
  • Функцияводить машинури, включи конечная точка, например:
  • Функцияводить машинури, дай endpoint распространять буфер, настройка usb_request, отправить usb_request, например:

5.3 Функция обратного вызова

Функцияводить структура машиныиз usb_request,можно получить Host Отправлятьизданные,Также возможнокда К Host Отправить данные. Когда передача будет завершена, usb_request изфункция обратного вызов называется.

В функции обратного вызова usb_request можно отправить еще раз.

Как вызвать функцию обратного вызова? Источник UDC изсерединаперерывфункция。

5.3.1 IMX6ULL

Отношения вызова следующие:

Язык кода:javascript
копировать
// Linux-4.9.88\drivers\usb\chipidea\core.c
ci_irq
 /* Handle device/host interrupt */
 if (ci->role != CI_ROLE_END)
  ret = ci_role(ci)->irq(ci);  // udc_irq
   udc_irq
                if (USBi_UI  & intr)
                    isr_tr_complete_handler(ci);
                     err = isr_tr_complete_low(hwep);
                        usb_gadget_giveback_request(&hweptemp->ep, &hwreq->req);
                         req->complete(ep, req);    
5.3.2 STM32MP157

Отношения вызова следующие:

Язык кода:javascript
копировать
// Linux-5.4\drivers\usb\dwc2\gadget.c
dwc2_hsotg_irq
  // Обработка прерываний конечной точки
  for (ep = 0; ep < hsotg->num_of_eps && daint_out;
      ep++, daint_out >>= 1) {
   if (daint_out & 1)
    dwc2_hsotg_epint(hsotg, ep, 0);
     dwc2_hsotg_handle_outdone(hsotg, idx);
      dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
       usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req);
        req->complete(ep, req);
  }

  for (ep = 0; ep < hsotg->num_of_eps  && daint_in;
      ep++, daint_in >>= 1) {
   if (daint_in & 1)
    dwc2_hsotg_epint(hsotg, ep, 1);
     dwc2_hsotg_complete_in(hsotg, hs_ep);
      dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
       usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req);
        req->complete(ep, req);
  } 

5.4 анализ f_loopback

loopback Это петля, Хост Отправить данные на Гаджет, то читай Gadget Толькокпридетсяприезжать Как естьизданные。

5.4.1 Гаджет получает данные

Host При выборе определенного интерфейса будет выбран интерфейс по умолчанию. 0 настройки (альтсеттинг);

Когда хост Отрегулировать USB_REQ_SET_INTERFACE к При необходимости укажите настройку по запросу.

Итак, начнем с f_loopback.c изфункцияloopback_set_altначинатьанализировать。

Вызывающие отношения:

Язык кода:javascript
копировать
loopback_set_alt
 enable_loopback
  result = enable_endpoint(cdev, loop, loop->in_ep);
  
  result = enable_endpoint(cdev, loop, loop->out_ep);
  
  result = alloc_requests(cdev, loop);

Как показано на рисунке выше, сначала отправьте сообщение out_req, он ждет Host Отправлятьданные。

Предположим, точка останова loop->out_ep из out_req получать Понятноданные,этоизфункция обратного вызоваloopback_completeназывается,Такие как Вниз:

5.4.2 Данные шлейфа гаджета

5.5 анализ f_sourcesink

фронт из f_loopback Также реализована передача в обе стороны: Хост приезжать Gadget、Gadget приезжать Хост, но между ними существуют отношения зависимости: Хост Данные необходимо сначала отправить, а затем прочитать.

f_sourcesink.c Также реализована передача в обе стороны: Хост приезжать Gadget、Gadget приезжать Хозяин, они независимы.

  • Host читать Gadget:водить данные создаются в программе машины Host Доступно читатьприезжать,Gadget как источник
  • Host Писать Gadget:водить программа машины, чтобы добраться до места Host Отправлятьизданные,Gadget какглазиз(sink)
5.5.1 Хост записывает гаджет

Host При выборе определенного интерфейса будет выбран интерфейс по умолчанию. 0 настройки (альтсеттинг);

Когда хост Отрегулировать USB_REQ_SET_INTERFACE к При необходимости укажите настройку по запросу.

То, что мы делаем, мы начинаем с f_sourcesink.c изфункцияsourcesink_set_altначинатьанализировать。

Язык кода:javascript
копировать
sourcesink_set_alt
 enable_source_sink(cdev, ss, alt);  

как"source",функцияsource_sink_start_epПостроюданные、Отправьте usb_request:

когда Host читать Выбиратьприезжатьданныеназад,usb_request изфункция обратного вызывается вызов, и он просто снова отправляется USB попросить, дать Host Продолжайте подавать как в прошлый раз изданные:

5.5.2 Хост читает гаджет

еще из f_sourcesink.c изфункцияsourcesink_set_altначинатьанализировать。

Язык кода:javascript
копировать
sourcesink_set_alt
 enable_source_sink(cdev, ss, alt);  

как"sink",функцияsource_sink_start_epСделаю это намеренно Пучокданныенастраиватьдля 0x55 (Это для отладки, вы можете увидеть приезжать, когда читатьприезжатые 0x55 перезаписано), отправить usb_request:

когда Host Отправлятьданные,usb_request изфункция обратного вызывается вызов, он проверяет получение выездных и отправляет снова usb_request:

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose