LINUX.ORG.RU

Заюзать изохронный USB дата стрим, используя libopencm3

 , ,


0

2

Здарова, народ.

Решил смастерить на STM32F103x некую простецкую USB аудио карту. Для этого заюзал библиотеку libopencm3.

Но, кажется, что ее создатели решили не реализовывать полную поддержку USB стека, и ограничились только эндпойнтами bulk и interrupt типов.

Оказалось что isochronous ендпойнты не работают вообще там.

Блин, знал бы заранее - то не брал бы эту игрушечную поделку libopencm3, взял бы родной HAL и не парился.

Это называется: начитался много лестных отзывов об libopencm3, но оказалось, что все не так радужно.

Есть на форуме люди, которые ее юзали? Мож у кого есть «патченная версия» с работой этих USB?

★★

Последнее исправление: kuzulis (всего исправлений: 1)

Советую выбросить опенцм3 и пользоваться исключительно CMSIS. Я себе запилил CDC и HID, мне большего не нужно. Но там и другие классы легко сделать. Без всего этого оверхеда.

взял бы родной HAL и не парился

Ты - абдуринщик что ли? Ни один уважающий себя человек не будет этими калокубами пользоваться!!!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Ты - абдуринщик что ли? Ни один уважающий себя человек не будет этими калокубами пользоваться!!!

Не все вокруг бородатые холостые ноулайферы, которые будут годы и десятилетия тратить на подготовку ради одноразовой задачки.

anonymous
()
Ответ на: комментарий от anonymous

Ты забываешь главный принцип разработчика: лучше день потерять, зато потом за два часа долететь! Я могу потратить полдня на написание скрипта, который зато потом сильно облегчит мне жизнь. Так и здесь: постепенно накапливаю сниппеты, в результате чего каждая следующая разработка становится все проще и проще.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Так и здесь: постепенно накапливаю сниппеты, в результате чего каждая следующая разработка становится все проще и проще.

Ну а топикстартеру как от этого нарциссизма легче?

anonymous
()
Ответ на: комментарий от anonymous

Почитает спецификации, даташит и мануал. За неделю сделает. Без говна и палок!

Eddy_Em ☆☆☆☆☆
()

Плюсую CMSIS, затраты в 1-2 дня на освоение USB-стека на low-level считаю более чем оправданными.

Libopencm3 вещь, в принципе, неплохая, но бывают грабли типа этих. На любой софт от ST рекомендую не тратить время.

Minoru ★★★
()

Спасибо, парни, но, блин, мне бы лучше на libopencm3 бы.. Неужели никто не использовал изохронный УСБ там?

kuzulis ★★
() автор топика
Ответ на: комментарий от kuzulis

Я когда-то писал с использованием opencm3 (у меня на гитхабе даже некоторое количество кода под него осталось), но когда разработчики opencm3 в очередной раз угробили нафиг апи, но при этом ничего радикально нового не дали взамен, я послал их лесом и полностью зарекся когда-либо чужие говнолибы использовать!

Хотя, конечно, если сравнить с калом от ST, opencm3 просто персик! Уж если хочешь увидеть образчик быдлокода с диким оверхедом, загляни в сгенерированное калокубом.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от CYB3R

А зачем вообще для этой задачи isochronous?

Потому что см. USB UAC1 спецификацию. Миди - это другое.

kuzulis ★★
() автор топика
Ответ на: комментарий от CYB3R

А зачем вообще для этой задачи isochronous? Загляни в usbmidi в examples, и делай, как там.

у тебя «аудиокарта» — это только миди что ли? изохронус для того и сделан, чтобы передавать данные, критичные ко времени доставки, навроде аудио.

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

anonymous
()
Ответ на: комментарий от anonymous

изохронный дескриптор для аудио — это сложно

Да не очень то и сложно, я раньше это делал, только на Cypress FX-2 (только давно, забыл уже).

На крайняк, можно подсмотреть дескриптор на реальном девайсе.

Например, как оно сделано на какой нить УСБ веб. камере, прочитав ее дескриптор (там же функция микрофона или спикера обычно идет).

что можно самому вручную всё настроить,

не, ну это то понятно, просто не хотелось даташитится по уши.. :(

kuzulis ★★
() автор топика
Последнее исправление: kuzulis (всего исправлений: 1)
Ответ на: комментарий от kuzulis

Можно из того же opencm3 выдрать, можно взять с сайта ST или даже напрямую с сайта ARM (но в последнем случае все равно с сайта ST нужно будет выдрать заголовочные файлы с определением регистров). Посмотри, как это у меня выглядит (в этой директории собрано все, необходимое для разработки под STM32F103, кроме Makefile).

Естественно, ничего там жирного нет, т.к. это — просто набор заголовочных файлов.

Eddy_Em ☆☆☆☆☆
()
Последнее исправление: Eddy_Em (всего исправлений: 1)

Всем спасибо, покурил даташит и пофиксил libopencm3.

Теперь мой фейковый микрофончик генерит чистую синусойду (два канала с семплированием 16 кГц), и я ее слышу.

Ура, товарищи.

Теперь бы найти где нить не ХАЛовскую реализацию для :

  1. Неблокирующей работы с I2C, на прерываниях.

  2. Неблокирующейи работы с SPI на прерываниях, или лучше с ДМА, с эмуляцией аудио шины I2S.

Никто не встречал?

kuzulis ★★
() автор топика
Последнее исправление: kuzulis (всего исправлений: 2)
Ответ на: комментарий от kuzulis

Неблокирующей работы с I2C, на прерываниях.

На STM32F103 это будет очень сложно, на других сериях — вполне. Только внимательно читай RM и errata.

Неблокирующейи работы с SPI на прерываниях

Я заводил SPI на DMA (кажись, экранчик по I2C тоже подключал — и тоже с DMA). См. у меня в stm32samples на гитхабе.

с эмуляцией аудио шины I2S

Чего нет — того нет, этим не занимался. Сейчас, кстати, по вечерам тетрис дорисовываю для цветной светодиодной панели 64×32 пикселя. Передача данных посредством DMA (1 канал таймера 3 в режиме ШИМ генерирует строб, этот же таймер по UEV пинает DMA и отправляет очередные 6 бит цвета).

Eddy_Em ☆☆☆☆☆
()

Ты абдуринщик, что-ли? Изохронный режим написать - максимум на полчаса делов, вместе с чтением документации и всем таким. Читаешь/пишешь/DMA из/в endpoint’а по прерыванию от принятого/переданного пакета, синхронизацию своей кухни по прерыванию от SOF делаешь. Всё. Я вообще сомневаюсь что для этого вообще какие-то специальные доп.функции в библиотеке нужны. Для девайса изохронный режим почти не отличается от bulk, вся магия в хосте. Единственное отличие - разумно синхронизировать подготовку/обработку данных с SOF, чтобы не было overrun/underrun, но библиотека тут совсем не при чём - это юзерское дело.

Stanson ★★★★★
()
Последнее исправление: Stanson (всего исправлений: 1)
Ответ на: комментарий от Eddy_Em

а STM32F103 это будет очень сложно,

Почему сложно?

Я заводил SPI на DMA

Ага, спс, гляну.

экранчик по I2C тоже подключал

Аха, спс. А то я подключил на проверку почитать флешку at24c128 по I2C, а оно почему то в бузи висит всегда..

То ли потому что подтягивающие резисторы нужны (вроде они есть), то ли еще что, я хз.

Сейчас, кстати, по вечерам тетрис дорисовываю для цветной светодиодной панели 64×32 пикселя.

Прикольненько, а я хочу прикрутить радио-модуль SI4730 к STM32F103, чтобы:

  • по I2C управлять радио-модулем
  • выход аудио (L/R) подрубить на ADC STM-ки (ну, или через внешний кодек, склоняюсь пока к кодеку, тогда надо I2S городить).
  • а саму STM-ку врубать по USB к компу, и чтобы на компе появилось некое композитное у-во с HID - для управления радиомодулем (HID->I2C), а также аудио устройство.
kuzulis ★★
() автор топика
Последнее исправление: kuzulis (всего исправлений: 1)
Ответ на: комментарий от Stanson

Ты абдуринщик, что-ли?

Я хз о чем ты.

Изохронный режим написать - максимум на полчаса делов, вместе с чтением документации и всем таким.

О доооо… документация - кряк кряк.

А почему тогда в случае с STM-кой, хост получает изохронные пакеты через один? Где это в документации написано?

Вот смотрю в вайршарке - реально то данные есть в запросе, то нет, то есть то нет..

Также смотрю в коде - что буффера триггерятся по очереди (дам же дабл буфер с изохронкой), и в каждый из них я даныне копирую.

Так что не надо ляля про пол-часа, шустрый какой. Нюансов много, не все в документации очевидно.

Для девайса изохронный режим почти не отличается от bulk, вся магия в хосте.

Не надо мне втирать про все это, я и сам могу втереть много чего про это.

Вопрос не в этом был, кроме того, вопрос с USB вроде как решен (только маленькая непонятка с пустыми запросами).

kuzulis ★★
() автор топика
Ответ на: комментарий от kuzulis

О доооо… документация - кряк кряк.

Чукча не читатель?

А почему тогда в случае с STM-кой, хост получает изохронные пакеты через один? Где это в документации написано?

Открываешь стандарт USB и читаешь почему. DTS инвертируешь после каждого пакета?

Так что не надо ляля про пол-часа, шустрый какой. Нюансов много, не все в документации очевидно.

Какой бы лютым говнищем ни был USB, документация у него абсолютно очевидная.

Не надо мне втирать про все это, я и сам могу втереть много чего про это.

Судя по столь глупому вопросу в твоём посте - втереть ты можешь только мазь от геморроя, причём только себе.

Вопрос не в этом был,

Вопрос идиотский. Потому что какая-то особая поддержка isochronous transfer в библиотеке для USB device просто нафиг не нужна.

кроме того, вопрос с USB вроде как решен (только маленькая непонятка с пустыми запросами).

Вроде в огороде. Вот так всё нычне и модно «решать», вместо чтения документации и работы головой. В итоге веб-странички по 10Мб сжирающие все доступные ресурсы и всякое говнище типа SSD с ограниченным количеством циклов записи. «Только маленькие непонятки», ага. Киберпанк который мы заслужили, сцуко.

Stanson ★★★★★
()
Ответ на: комментарий от kuzulis

Почему сложно?

Errata там шибко толстая. 103 - самая неудачная серия, особенно в области I2C и SPI.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Stanson

Открываешь стандарт USB и читаешь почему. DTS инвертируешь после каждого пакета?

Да ты шо? Умник что-ли? Ну-ка проинвертируй-ка а я посмотрю. Или ты думаешь, что я не пробовал хаки типа этого, и не гуглил?

Этого говнища даже в STM32 HAL-е нету для usbd. Это только для режима OTG хоста юзается.

PS: По сравнению с Cypress FX2 - STM лютейшее говно в части работы с USB (да и не только с USB по ходу).

kuzulis ★★
() автор топика
Ответ на: комментарий от Stanson

Открываешь стандарт USB и читаешь почему. DTS инвертируешь после каждого пакета?

А можно подробнее? DTS я не припоминаю ни в стандарте USB, ни в регистрах контроллера. Может, имелось в виду DATA0 / DATA1, но как раз в изохронном режиме они не меняются.

COKPOWEHEU
()
Ответ на: комментарий от kuzulis

Всем спасибо, покурил даташит и пофиксил libopencm3.

Теперь мой фейковый микрофончик генерит чистую синусойду (два канала с семплированием 16 кГц), и я ее слышу.

Тоже сейчас вожусь с аудиоустройством, только не на opencm и тем более не на HAL, а прямо на регистрах. Насколько я понял, при отправке надо читать DTOG_TX и если оно равно 1, то писать в 0-й банк, а если 0, то в 1-й.

Вроде бы оно так даже работает, синусоиду 1 кГц при 16000 сэмплах в секунду видно и слышно. Странно только что при скоростях выше 30 ksps контроллер перестает успевать передавать данные и сигнал «рвется»

COKPOWEHEU
()
Ответ на: комментарий от COKPOWEHEU

Насколько я понял, при отправке надо читать DTOG_TX и если оно равно 1, то писать в 0-й банк, а если 0, то в 1-й.

Да, именно так. Я пробовал уже все комбинации (менять очередность буферов, менять очередность инициализации), но результат один - при буфере 128 байт (это 2 канала х 2 байта каждый на 32 kHz) получаю какое-то говно.

Вроде бы оно так даже работает, синусоиду 1 кГц при 16000

Дада, именно так, такая же дичь!

У меня тоже два канала (L/R) с частотой семплирования 16 kHz, где каждый семпл есть Обычный PCM размером 2 байта.

На 16-ти килогерцах - фейковая синусойда отличная.. Но как только увеличиваю частоту семплирования до 32 kHz - то всЁ, ппц. приплыли.

Вот тут хреновая картинка для 32 kHz : https://paste.pics/aecfdde611b14c32a6ac1c94c0e9bc27

Вот тут нормальная для 16 kHz: https://paste.pics/8f8af7d9d98378a2803ec53f6e98c738

PS: Я уже и ХАЛ проштудировал, и кучу других либ в инете - пофиг всё (делал по аналогии). ппц какой-то.

kuzulis ★★
() автор топика
Последнее исправление: kuzulis (всего исправлений: 3)
Ответ на: комментарий от kuzulis

Не, на 32 или 48 ksps у меня скорее пропуск сэмплов случается, чем подобные мельтешения.

И это странно, потому что 32 ksps на одном канале (как у меня) или двух (как у вас) это всего 64 или 128 kB/s при пределе ~600 kB/s. Может там какие-то дополнительные ограничения на изохронный обмен. Или просто предполагается точки побольше делать. Хотя как-то это не особо помогает

COKPOWEHEU
()
Ответ на: комментарий от COKPOWEHEU

А можно глянуть твой код инициализации ендпойнта, и записи в него?

И еще, можешь в вайршарке глянуть, на каждый ли изохронный IN запрос девайс передает данные?

Потому что у меня оно почему то через раз передается, не в каждом запросе. Я без понятия почему так.

kuzulis ★★
() автор топика
Последнее исправление: kuzulis (всего исправлений: 1)
Ответ на: комментарий от kuzulis

Для примера взял, и прошил прошивку от этого товарища с ютуба, который прицепил микрофон к STM32 и результат по пропускам изохронных запросов тот-же - они чередуются:

У него там вроде 1 канал, вроде на 32000 Hz, но работает глючненько конечно (в диспетчере устройств периодически отваливается).

kuzulis ★★
() автор топика
Последнее исправление: kuzulis (всего исправлений: 2)
Ответ на: комментарий от kuzulis

А можно глянуть твой код инициализации ендпойнта, и записи в него?

И еще, можешь в вайршарке глянуть, на каждый ли изохронный IN запрос девайс передает данные?

Каждый. Я даже проверял правильно ли переключаю банки. Если перед копированием следующего пакета забить нулями предыдущий, то при правильном переключении сигнал должен искажаться, ведь железо оттуда еще читает.

Код сейчас чутка приведу к вменяемому состоянию и выложу. Но еще раз говорю: у меня все на регистрах, самодельное.

Потому что у меня оно почему то через раз передается, не в каждом запросе. Я без понятия почему так.

Может, не включен двухбанковый режим точки? То есть контроллер считает что включен (а для изохронной он по-другому не умеет), а софт - что нет.

COKPOWEHEU
()
Ответ на: комментарий от COKPOWEHEU

Хмм.. спасибо... Посмотрел, и вижу, что у меня то же самое в принципе делается:

настройка ендпойнта:

static void st_usbfs_ep_setup_double(usbd_device *dev, uint8_t addr, uint8_t type,
        uint16_t max_size,
        void (*callback) (usbd_device *usbd_dev,
        uint8_t ep))
{
    uint8_t dir = addr & 0x80;
    addr &= 0x7f;

    /* Assign address. */
    USB_SET_EP_ADDR(addr, addr);
    USB_SET_EP_TYPE(addr, typelookup[type]);
    USB_SET_EP_KIND(addr);

    if (dir || (addr == 0)) {
        USB_SET_EP_TX_ADDR(addr, dev->pm_top); // TX0
        dev->pm_top += max_size;
        USB_SET_EP_RX_ADDR(addr, dev->pm_top); // TX1
        dev->pm_top += max_size;
        if (callback) {
            dev->user_callback_ctr[addr][USB_TRANSACTION_IN] =
                (void *)callback;
        }
        USB_CLR_EP_TX_DTOG(addr); // TX0
        USB_CLR_EP_RX_DTOG(addr); // TX1
        USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_VALID);
    }

    if (!dir) {
        struct st_usbfs_bufsize bufsize = st_usbfs_calculate_bufsize(max_size);
        USB_SET_EP_TX_ADDR(addr, dev->pm_top); // RX0
        USB_SET_EP_TX_COUNT(addr, bufsize.bufsize);
        dev->pm_top += bufsize.realsize;
        USB_SET_EP_RX_ADDR(addr, dev->pm_top); // RX1
        USB_SET_EP_RX_COUNT(addr, bufsize.bufsize);
        dev->pm_top += bufsize.realsize;
        if (callback) {
            dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] =
                (void *)callback;
        }
        USB_CLR_EP_TX_DTOG(addr); // RX0
        USB_CLR_EP_RX_DTOG(addr); // RX1
        USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
    }

запись в эндпойнт:

static uint16_t st_usbfs_ep_write_packet_isoch(uint8_t addr, const void *buf, uint16_t len)
{
    addr &= 0x7F;
    const bool dtog_tx = (GET_REG(USB_EP_REG(addr)) & USB_EP_TX_DTOG);
    if (dtog_tx) {
        st_usbfs_copy_to_pm(USB_GET_EP_TX_BUFF(addr), buf, len);
        USB_SET_EP_TX_COUNT(addr, len);
    } else {
        st_usbfs_copy_to_pm(USB_GET_EP_RX_BUFF(addr), buf, len);
        USB_SET_EP_RX_COUNT(addr, len);
    }
    USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_VALID);
    return len;
}

поллинг интерраптов:

...
	if (istr & USB_ISTR_CTR) {
		uint8_t ep = istr & USB_ISTR_EP_ID;
		uint8_t type;

		if (istr & USB_ISTR_DIR) {
			/* OUT or SETUP? */
			if (*USB_EP_REG(ep) & USB_EP_SETUP) {
				type = USB_TRANSACTION_SETUP;
				st_usbfs_ep_read_packet(dev, ep, &dev->control_state.req, 8);
			} else {
				type = USB_TRANSACTION_OUT;
			}
		} else {
			type = USB_TRANSACTION_IN;
			USB_CLR_EP_TX_CTR(ep);
		}

		if (dev->user_callback_ctr[ep][type]) {
			dev->user_callback_ctr[ep][type] (dev, ep);
		} else {
			USB_CLR_EP_RX_CTR(ep);
		}
	}
...

где коллбек [b]user_callback_ctr[/b] - это будет [b]data-in[/b] коллбек в котором я пишу в эндпойнт.

ЗЫ: А ты можешь и для STM32F103 аудио класс сделать? Я так понимаю, что ты тестил на 'Low Power' серии STM32Lxx?
kuzulis ★★
() автор топика
Ответ на: комментарий от kuzulis

ЗЫ: А ты можешь и для STM32F103 аудио класс сделать? Я так понимаю, что ты тестил на ‘Low Power’ серии STM32Lxx?

А у них USB одинаковый. Там на гитхабе можно взять 1.Core_F1, скопировать в src нужные файлы и помейкать.

COKPOWEHEU
()
Ответ на: комментарий от kuzulis

Потому что я его только сейчас тестирую. Доведу до ума, тогда и в F серию скопирую. Еще раз говорю, там разницы почти никакой. Единственное что у L серии есть подтягивающий резистор, а у F - нет, без этого вообще можно было бы общим usb_lib обойтись.

Или вы хотите мой вариант протестировать и хотите чтобы я побыстрее это перенес?

COKPOWEHEU
()
Ответ на: комментарий от kuzulis

if (dir || (addr == 0)) {

А это зачем? addr==0 это настройка ep0? Но зачем его делать двойным?

USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_VALID);

Это точно правильно? Если данных в TX нет, там же должно быть NAK, нет?

USB_SET_EP_RX_COUNT(addr, len);

Здесь учитывается, что надо записывать напрямую, а не через хитрую RX-ную структуру?

if (dev->user_callback_ctr[ep][type]) {

Это можно сделать проще: у вас же явным образом проверяется NULL при присвоении колбэка. Вместо проверки и вызова можно написать фейковую функцию и вызывать безусловно.

COKPOWEHEU
()
Ответ на: комментарий от kuzulis

Странным образом запустилось на одном канале 96 ksps. Правда, у меня формирование синусоиды вырвиглазное, а синхронизация еще хуже, но как-то работает и не переполняется.

Размер точки по 200 байт сделал плюс 8 байт на ep0. Он по 190 байт за раз и посылает.

Видимо, есть у него какое-то ограничение на интервал запросов. Ну да ладно, с этим возиться уже не буду. Допилю двусторонний обмен («микрофон» плюс «динамик»), немного свистелок и сойдет. В конце концов для stm’ки и 16 ksps достаточно.

Ах да, еще надо на F-ку скопировать не забыть.

COKPOWEHEU
()
Ответ на: комментарий от COKPOWEHEU

Или вы хотите мой вариант протестировать и хотите чтобы я побыстрее это перенес?

Не (давай на ты), лучше уж та доделай и запуш в гит.. А я подтяну и проверю у себя как-нить. ))

А это зачем? addr==0 это настройка ep0? Но зачем его делать двойным?

Упс, да, это ошибка копи-пасты. В любом случае ep0 тут не используется.

Это точно правильно? Если данных в TX нет, там же должно быть NAK, нет?

Как я понимаю, NAK невозможен для изохронных. По хорошему надо ставить в disabled, но тогда автоматически не вызовется коллбек при запуске устройства (например при активации вкладочки с устройствами записи в винде).

Хотя, да, скорее всего надо делать disabled и стартовать запись в эндпойнт (стартовать стрим) только когда приходит установка альтернативных сеттингов ненулевых.

Здесь учитывается, что надо записывать напрямую, а не через хитрую RX-ную структуру?

Да, этот макрос раскрывается в:

...
#define SET_REG(REG, VAL)	(*(REG) = (uint16_t)(VAL))
...
...
#define USB_EP_RX_COUNT(EP) \
	((uint32_t *)(USB_PMA_BASE + (USB_GET_BTABLE + EP * 8 + 6) * 2))
...
...
#define USB_SET_EP_RX_COUNT(EP, COUNT)	SET_REG(USB_EP_RX_COUNT(EP), COUNT)
...

Это все как-бы библиотечные макросы, не мои.

Это можно сделать проще: у вас же явным образом проверяется NULL при присвоении колбэка. Вместо проверки и вызова можно написать фейковую функцию и вызывать безусловно.

Ну, это библиотечное всё, суть не в том.

===

ЗЫ: Еще непонятно в даташите описание работы с дабл - буферами.

kuzulis ★★
() автор топика
Ответ на: комментарий от kuzulis

Не (давай на ты), лучше уж та доделай и запуш в гит.. А я подтяну и проверю у себя как-нить. ))

Нет, я имел в виду что вы хотите проверить у себя, для чего мне нужно сначала скопировать эту настройку на F1 и проверить. Я это собирался делать в любом случае, вопрос насколько срочно.

Как я понимаю, NAK невозможен для изохронных.

Но двойной буфер возможен не только для изохронных, но и для бульков. А им как раз NAK норм. Впрочем, чего мы тут извращаемся: можно же добавить еще один if и все.

Это все как-бы библиотечные макросы, не мои.

У меня чуть по-другому используется, вот и спросил.

ЗЫ: Еще непонятно в даташите описание работы с дабл - буферами.

О да. Хоть бы пример кода дали. Хотя учитывая что они наворотили в HAL, да и в EPnR, уже всякого от этих наркоманов ожидаешь…

COKPOWEHEU
()

Я тут посмотрел wireshark’ом на прием и на передачу. Похоже, что на передачу хост иногда посылает несколько пакетов подряд, а вот на прием - нет. Может, если добавить точку синхронизации, лучше будет? Правда, я понятия не имею как это делается, да и желания нет

COKPOWEHEU
()
Ответ на: комментарий от kuzulis

В одной из таблиц написано:

Buffer flag‘Transmission’ endpoint‘Reception’ endpoint
DTOGDTOG_TX (USB_EPnRbit 6)DTOG_RX (USB_EPnRbit 14)
SW_BUFUSB_EPnR bit 14USB_EPnR bit 6

The memory buffer which is currently being used by the USB peripheral is defined by DTOG buffer flag, while the buffer currently in use by application software is identified by SW_BUF buffer flag.

а в другой:

EP typeDTOGSW_BUFUsed by HWUsed by SW
IN01ADDRn_TX_0 / COUNTn_TX_0Buffer description table locations.ADDRn_TX_1 / COUNTn_TX_1Buffer description table locations.
IN10ADDRn_TX_1 / COUNTn_TX_1Buffer description table locations.ADDRn_TX_0 / COUNTn_TX_0Buffer description table locations.

Т.е. Если я проверяю на флаг DTOG_TX, то в какой буфер я могу писать данные, а в какой нет?

Это неочевидно как-то (да и не имеет значения на практике, я пробовал менять местами).

kuzulis ★★
() автор топика
Ответ на: комментарий от COKPOWEHEU

несколько пакетов подряд, а вот на прием - нет.

Имеешь ввиду - несколько OUT пакетов, а на IN - только один?

Допилю двусторонний обмен («микрофон» плюс «динамик»),

Не уверен что тут просто будет, да и зачем спикер нужен, если ничем его не прослушаешь.

Лучше сделай микрофон с охренительным семпл-рейтом под 192 кГц (и лучше на два канала), для проверки возможностей СТМ-ки.

Может, если добавить точку синхронизации, лучше будет?

Хз, в принципе, она нужна чисто для «подстройки» кол-ва семплов в спикер (как я понимаю, для микрофона она необязательна).

Но там же еще гимморой с ее настройкой: ее можно привязать как к частоте прихода семплов от микрофона, к SOF, и прочим источникам (по спецификации, если я правильно помню).

kuzulis ★★
() автор топика
Последнее исправление: kuzulis (всего исправлений: 1)
Ответ на: комментарий от COKPOWEHEU

Я это собирался делать в любом случае, вопрос насколько срочно.

В принципе не горит, т.к. пока обойдусь частотами до 22050 Гц.

Но двойной буфер возможен не только для изохронных, но и для бульков. А им как раз NAK норм

Да, но у нас не бульки. :)

У меня чуть по-другому используется, вот и спросил.

Не, это то понятно… В итоге все-равно все приводится к записи в регистры по каким-то адресам. :)

О да. Хоть бы пример кода дали. Хотя учитывая что они наворотили в HAL, да и в EPnR, уже всякого от этих наркоманов ожидаешь…

В ХАЛ - там вообще хер пойми.. Там два раза что-ли дописывается в эндпойнт (проверяется на возмодность мультипакетов, типа если размер пакета больше чем размер эндпойнта)..

И там то при DTOG_TX пишут в BUF0, то в BUF1…

В других либах вообще каждый пишет как хочет. ;)

kuzulis ★★
() автор топика
Последнее исправление: kuzulis (всего исправлений: 1)
Ответ на: комментарий от kuzulis

Т.е. Если я проверяю на флаг DTOG_TX, то в какой буфер я могу писать данные, а в какой нет?

Это неочевидно как-то (да и не имеет значения на практике, я пробовал менять местами).

Насколько я понял, первая таблица это про то, какой из DTOG’ов использовать. А вторая как раз про буферы. Нас, очевидно, интересует тот, с которым должен общаться софт SW.

Имеешь ввиду - несколько OUT пакетов, а на IN - только один?

Да, похоже на то. Анализатор говорит что в одной посылке нулевой, первый, второй и т.д. пакеты

Не уверен что тут просто будет, да и зачем спикер нужен, если ничем его не прослушаешь.

Уже сделал. Грабли, конечно, были, но решились. Так оно хотя бы формально может считаться аудиокартой. Да и вообще, у меня сейчас под это дело нет конкретной задачи, просто смотрю что и как делается.

Лучше сделай микрофон с охренительным семпл-рейтом под 192 кГц (и лучше на два канала), для проверки возможностей СТМ-ки.

Если мое предположение про синхронизацию окажется верным, увеличение сэмпл-рейта окажется делом сложным. Плюс совершенно неочевидно зачем. Ведь для «охренительного сэмпл-рейта» мало написать прошивку, надо и аналоговую часть качественную сделать, и сам микрофон непозорный найти, и акустику к нему. Я же сейчас пытаюсь обойтись вообще без навесных элементов на отладочной плате. А уж городить аудиотракты ну никакого желания

Хз, в принципе, она нужна чисто для «подстройки» кол-ва семплов в спикер (как я понимаю, для микрофона она необязательна).

Насколько я понял из других устройств, точки на прерывание иногда просто индицируют хосту «там на устройстве чего-то произошло, ты бы сделал запрос»

В итоге все-равно все приводится к записи в регистры по каким-то адресам. :)

Угу, основное различие в том сколько слоев надо пройти пока до регистров доберешься. К слову, в HAL’е я это так и не осилил: посмотрел как они пять раз пересылают одни и те же данные между функциями без какой-либо обработки и плюнул.

проверяется на возмодность мультипакетов, типа если размер пакета больше чем размер эндпойнта

Хм, а нам-то какая разница, это же поток? Ну то есть вот у нас 65 байт данных накопилось, мы их передадим как 64 + 1.

Хотя стоп! Может если именно как 64+1 передавать, хост сделает еще запрос? Надо проверить.

COKPOWEHEU
()
Ответ на: комментарий от COKPOWEHEU

Хотя стоп! Может если именно как 64+1 передавать, хост сделает еще запрос? Надо проверить.

Нет, это не работает. Интересным образом не работает если выставить bInterval у точки в 0 (хотя стандарт говорит что должно быть всегда 1). Оно принимает 48 байт и ругается что много. При этом данные вроде учитываются.

Магия какая-то…

COKPOWEHEU
()
Ответ на: комментарий от COKPOWEHEU

Я же сейчас пытаюсь обойтись вообще без навесных элементов на отладочной плате.

Ну так я и говорю про фейковый микрофон, где семплы генерятся программно, например синус.

В этом случае хотя бы можно проверить что оно передает, записав данные, например при помощи audacious или чем то таким.

kuzulis ★★
() автор топика
Ответ на: комментарий от kuzulis

А сейчас я как тестирую микрофон? Там в репозитории есть sfml_audio, это я утилитку набросал чтобы смотреть в реальном времени. Оттуда же можно на stdout выводить.

Как ни странно, штатного способа вывести микрофон на stdout я не нашел.

COKPOWEHEU
()
Ответ на: комментарий от COKPOWEHEU

DTS я не припоминаю ни в стандарте USB, ни в регистрах контроллера

Data Toggle Synchronization - в стандарте оно так называется.

но как раз в изохронном режиме они не меняются.

Поэтому и спрашиваю - не переключает ли он его вручную из-за этого. DTS бит в STM32 (DTOG) ещё и рулит переключением буферов. В изохронном режиме приезжают только пакеты c DATA0, но бит всё равно автоматически переключается железом после каждого пакета, и если ТС его ещё раз переключает самостоятельно, полагая что раз всегда DATA0, то буфера не будут переключаться как в других режимах, то STM32 будет писать в один и тот же буфер, что и будет приводить к описанной ТСом проблеме - воспроизводит он из двух буферов, а USB peripheral пишет только в один. Каждый второй пакет будет «пропадать».

Stanson ★★★★★
()
Последнее исправление: Stanson (всего исправлений: 2)
Ответ на: комментарий от Stanson

Нет, я не устанавливаю бит DTOG.

Хотя, в ХАЛе этот бит (DTOG_RX) вроде постоянно принудительно тогглится после каждой записи в эндпойнт.

Еще в даташите как то мутно написано про использование дабл буфферинга.

Например, для булков, там написано что после того как юзер запишет данные в доступный ему буффер, определяемый битом SW_BUF (там как я понял, это биты или DTOG_RX, или DTOG_TX, в зависимости от очередности), то нужно взвести этот бит SW_BUF в 1, тем самым показав хардварю, что теперь этот буфер доступен для передачи.

Но в описании к изохронкам, ничего подобного не упоминается. Там написано, что бит тоглится аппаратно, и юзер должен его только читать.

Тем более, с какого хрена в хале принудительно тогглится этот бит, и почему только DTOG_RX, почему не тоглится тогда и DTOG_TX, т.к. SW_BUF это или тот или тот биты.

Я хз, кароч.

kuzulis ★★
() автор топика
Последнее исправление: kuzulis (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.