Популярный пост TOPMO3 Опубликовано 23 июля, 2016 Популярный пост Поделиться Опубликовано 23 июля, 2016 Контроллер предназначен для использования в баттон-боксах, платах на рулях, педалях, для подключения шифтеров, ручников, т.е. для подключения кнопок, энкодеров и аналоговых осей. Возможности устройства (подробнее о спеках еще раскажу ниже): 6х аналоговых осей (12 бит - 4096 дискретных значений) до 36 кнопок до 11 энкодеров 1KHz частота обмена с ПК Со стороны ПК контроллер выглядит как обычный джойстик, установки драйверов не требует. Ну, про всякие кнопки и энкодеры понятно, а к аналоговым входам можно подключать как потенциометры в качестве крутилок (в иР например можно использовать такие оси для некоторых контролов), так и уже готовые педали, т.е любой аналоговый сигнал. Вот например я подключил педали от G27 (разворачивайте на полный экран и смотрите в ХД, иначе ничего не видно): https://www.youtube.com/watch?v=KnnlDYHd0DE Лоад - селлы также можно подключить, но конечно нужен отдельный усилитель. Как его собрать, показано например здесь. После него подключается как обычный аналоговый выход. Для этого проекта я решил использовать не Ардуино, а плату для разработчиков на основе STM32F103C8T6. Вот для сравнения их характеристики: Как видите, STM32F103C8T6 на фоне Ардуино выглядит вполне неплохо, а стоит дешевле. Один из основных минусов состоит в том, что для заливки прошивки в него нужен отдельный программатор, но он тоже недорог. Я покупал все на алиэкспрессе, например вот и вот Выглядят эти штуки так: Схема самой борды ОК, теперь к прошивке. После заливки прошивки, значение пинов борды становится таким (пока это фиксировано): Кнопки нужно подключать матрицей - строки к пинам ROW1 - ROW6 (B4 - B9), столбцы к пинам COL1 - COL6 (C13 - C15, B12, B3, A7). Крайние выводы энкодеров нужно соединить между собой и одну сторону подключить к ROTA (B10), другую - к ROTB (B11). Средние выводы энкодеров - к пинам ROT1 - ROT11. Аналоговые входы - ADC0 - ADC6 (A0 - A6). Последние два входа ADC5 и ADC6 работают в паре - на ось подается бОльшее из двух значений. Неиспользуемые аналоговые входы должны быть соединены с GND! Также я нарисовал картинку, чтобы было более понятно: Ссылка на прошивку Естественно, возникает вопрос - как залить прошивку? Сначала нужно подключить программатор к борде. Четыре провода, все просто - землю к земле, 3V к 3V, DIO - SWDIO, DCLK - SWCLK. Картинка: Затем: Нужна утилита ST-Link Utility, скачать можно отсюда Устанавливаем ее и запускаем. Открываем прошивку File -> Open file, Выбираем Target -> Connect. Внизу в окне статуса утилита должна появится всякая инфа о МК, это значит, что программатор вы подключили правильно и st-link utility определила нашу борду. Картинка: 3. Затем собвственно прошиваем Target -> Program. После прошивки борда "отвалится", это нормально, это значит прошивка залилась корректно и начала работать, т.к. в ней переопределяются пины, используемые программатором и st-link utility больше не может видеть борду. Картинка: Теперь о характеристиках борды, как обещал в начале. Просто приведу сравнение с педалями, которые у меня есть - G27 и Fanatec Elites разрешение осей - 4096 дискретных значений. G27 имеет 256, а Elites - 1024 значений, т.е. по этому параметру этот контроллер не хуже. частота обмена с ПК - 1KHz. Частота обмена данными с ПК - это минимальная latency для педалей. Т.е. она может быть больше, если например АЦП медленно считывает данные или сам МК работает медленнее, но не может быть меньше, т.к. это частота, с которой ПК опрашивает USB - устройство. Если у девайса есть что ответить - он отвечает, если нет - то нет. Ради интереса я посмотрел частоты обмена и оказывается у G27 она - 2мс, а у Elites - 16мс. Фанатек меня тут в очередной раз разочаровал. Затем я вспомнил, что у меня есть ДСД контроллер (12 bit controller with integrated load cell amplifier) и тоже посмотрел частоту обмена. Я просто даже не знаю, что сказать, просто оставлю картинку Т.е. видимо задумывалось, что частота должна быть 20мс, но бывают просадки до 1сек! Только на этом скриншоте их сразу две. И это я собирался поставить в свои педали :facepalm: В целом, вроде бы все. Этот проект получился для меня интересным, поэтому я планирую дальше его развивать. В частности, TODO лист такой: сделать отдельную интегрированную плату со встроенным load-cell усилителем. сделать возможность переопределения пинов, а соответственно и кол-ва кнопок и энкодеров. Т.е. чтобы была возможность сделать например кнопок меньше, а энкодеров больше или наоборот. возможно буду добавлять поддержку других компонент - галетников и т.п., но пока честно говоря, не знаю насколько это нужно 19 Ссылка на комментарий
RomanST Опубликовано 23 июля, 2016 Поделиться Опубликовано 23 июля, 2016 Молодец! ;) Теперь можно подумать насчёт конфигуратора прошивки под определенное количество периферии как в Teensy. Если не лень... Ссылка на комментарий
TOPMO3 Опубликовано 23 июля, 2016 Автор Поделиться Опубликовано 23 июля, 2016 Спасибо ) Да, планирую конфигурятор пинов, посмотрим что в итоге получится ) 1 Ссылка на комментарий
RomanST Опубликовано 23 июля, 2016 Поделиться Опубликовано 23 июля, 2016 Поглядел на код, плохо уже соображаю, поэтому ща буду глупости писать. Вместо неиспользуемых кнопок в статус репорте можно padding использовать, тогда пустые биты не будут отображаться как кнопки. Если SWDIO/SWCLK в кубе повесить на ноги, то connect можно будет делать без ресета, хотя ног доступно будет и меньше. Хотел еще что-нибудь написать, но голова уже выключилась... 2 Ссылка на комментарий
TOPMO3 Опубликовано 24 июля, 2016 Автор Поделиться Опубликовано 24 июля, 2016 Спасибо за комменты по делу ) На самом деле я не завидую любому профессиональному программисту, который набредет на мой код. ))) В свое оправдание скажу, что я там многое собираюсь переписать, например, для конфигурятора пинов всю работу с gpio придется переписать на bare register access, т.е. выкинуть все define. Поэтому я на данном этапе особо к красоте кода не стремился padding, насколько я понимаю, несет чисто эстетическую функцию. Но в дальнейшем при динамически изменяемом кол-ве кнопок он будет мешать. Наоборот, кол-во кнопок в дескрипторе планирую увеличить до 128. SWDIO/SWCLK отключены специально, они полезную работу выполняют 1 Ссылка на комментарий
RomanST Опубликовано 5 августа, 2016 Поделиться Опубликовано 5 августа, 2016 Дима, подскажи, пожалуйста, были какие то проблемы с ADC на 12 МГц? Я вот про это: // PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV8; У меня тут трэш-шапито какое то вылезло, пытаюсь разобраться... И вот это: hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; // hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; Читать по 16 бит не получилось, только по 32? Ссылка на комментарий
TOPMO3 Опубликовано 5 августа, 2016 Автор Поделиться Опубликовано 5 августа, 2016 // PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV8; когда я попытался завести АЦП на макс частоте (типа круто) и ADC_SAMPLETIME_1CYCLE_5, скорость обмена по усб упала до 3Hz. Сложно сказать в чем тут была проблема - в самом АЦП (в принципе это ведь штатные для него частоты) и в переполнении какого-ть усб буфера на передачу, но вот факт. Больше всего я грешу, что не хватало пропускной способности самой шины. В итоге я прикинул, что для 1kHz обмена хватит и 9MHz + ADC_SAMPLETIME_13CYCLES_5 для большей точности. // hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; CubeMx вообще первоначально не хотел 16бит ставить, это я уже пробовал ручками. Но потом внезапно понял, что по 32битной шине что 16 бит, что дефолтные 32 в любом случае пролезут за 1 такт и оставил 32 Ссылка на комментарий
RomanST Опубликовано 5 августа, 2016 Поделиться Опубликовано 5 августа, 2016 когда я попытался завести АЦП на макс частоте (типа круто) и ADC_SAMPLETIME_1CYCLE_5, скорость обмена по усб упала до 3Hz. Сложно сказать в чем тут была проблема - в самом АЦП (в принципе это ведь штатные для него частоты) и в переполнении какого-ть усб буфера на передачу, но вот факт. Больше всего я грешу, что не хватало пропускной способности самой шины. В итоге я прикинул, что для 1kHz обмена хватит и 9MHz + ADC_SAMPLETIME_13CYCLES_5 для большей точности. Там скорее всего слишком много прерываний генерировалось после каждого завершения преобразования, из-за этого и скорость упала... CubeMx вообще первоначально не хотел 16бит ставить, это я уже пробовал ручками. Но потом внезапно понял, что по 32битной шине что 16 бит, что дефолтные 32 в любом случае пролезут за 1 такт и оставил 32 Можно в кубе поставить и 16, даже работало, пока я не увеличил количество преобразований за один цикл... Ссылка на комментарий
TOPMO3 Опубликовано 5 августа, 2016 Автор Поделиться Опубликовано 5 августа, 2016 Там скорее всего слишком много прерываний генерировалось после каждого завершения преобразования, из-за этого и скорость упала... у меня же DMA, от основного цикла развязано. Теоретически на что может повлять более высокая частота АЦП - на объем перекачиваемых данных между памятью и АЦП, поэтому я и грешу на шину. Можно в кубе поставить и 16, даже работало, пока я не увеличил количество преобразований за один цикл... 16бит там можно выбрать и вроде бы все ок, а потом смотришь в код, а там 8 бит ))) Может только у меня такая фигня, я хз. Куб вроде последний был. Вообще я крайне разочарован качеством и куба и всего ХАЛа в целом, буду все переписывать постепенно Ссылка на комментарий
RomanST Опубликовано 5 августа, 2016 Поделиться Опубликовано 5 августа, 2016 (изменено) у меня же DMA, от основного цикла развязано. Теоретически на что может повлять более высокая частота АЦП - на объем перекачиваемых данных между памятью и АЦП, поэтому я и грешу на шину. После завершения цикла преобразования вызывается callback void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) по прерыванию. У тебя непрерывный цикл преобразования, значит, прерывания генерятся тоже непрерывно :) Так как при этом основной цикл прерывается - это может влиять на скорость опроса. 16бит там можно выбрать и вроде бы все ок, а потом смотришь в код, а там 8 бит ))) Может только у меня такая фигня, я хз. Куб вроде последний был.Вообще я крайне разочарован качеством и куба и всего ХАЛа в целом, буду все переписывать постепенно Хуже когда добавляешь в код вызов пустой функции и все виснет нахрен :( На ардуине я такого что-то не припомню... Изменено 5 августа, 2016 пользователем RomanST Ссылка на комментарий
TOPMO3 Опубликовано 5 августа, 2016 Автор Поделиться Опубликовано 5 августа, 2016 Так как при этом основной цикл прерывается - это может влиять на скорость опроса насколько я понимаю эту кухню (я так-то ламо ))) ) - не должен, это же отдельный DMA контроллервот из референсов Direct memory access (DMA) is used in order to provide high-speed data transfer betweenperipherals and memory as well as memory to memory. Data can be quickly moved by DMA without any CPU actions. This keeps CPU resources free for other operations. Хуже когда добавляешь в код вызов пустой функции и все виснет нахрен оптимизатор компилятора не дурит? Если нет, тогда дебаг в руки, благо он тут гораздо лучше, чем на ардуинах Ссылка на комментарий
RomanST Опубликовано 5 августа, 2016 Поделиться Опубликовано 5 августа, 2016 (изменено) насколько я понимаю эту кухню (я так-то ламо ))) ) - не должен, это же отдельный DMA контроллер HAL_ADC_IRQHandler в stm32f1xx_hal_adc.c посмотри. (#) Optionally, in case of usage of DMA: (++) Configure the DMA (DMA channel, mode normal or circular, ...) using function HAL_DMA_Init(). (++) Configure the NVIC for DMA using function HAL_NVIC_EnableIRQ(DMAx_Channelx_IRQn) (++) Insert the ADC interruption handler function HAL_ADC_IRQHandler() into the function of corresponding DMA interruption vector DMAx_Channelx_IRQHandler(). HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); - переопределяем вектор 11 в MX_DMA_Init() в main.c, это куб генерит за тебя. дефолтное значение устанавливается в startup_stm32f103xb.S - DMA1_Channel1_IRQn .weak DMA1_Channel1_IRQHandler .thumb_set DMA1_Channel1_IRQHandler,Default_Handler текст: void DMA1_Channel1_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */ /* USER CODE END DMA1_Channel1_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_adc1); /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */ /* USER CODE END DMA1_Channel1_IRQn 1 */ } Ну а из HAL_DMA_IRQHandler - вызывается HAL_ADC_ConvCpltCallback() вот из референсов Код надо смотреть :) оптимизатор компилятора не дурит? Если нет, тогда дебаг в руки, благо он тут гораздо лучше, чем на ардуинах Дебаг пока не освоил еще, в кукушке он нормально не работает, попробую TrueStudio... Кстати, там еще и half transfer complete callback есть, он на середине буфера вызывается... Изменено 5 августа, 2016 пользователем RomanST Ссылка на комментарий
TOPMO3 Опубликовано 5 августа, 2016 Автор Поделиться Опубликовано 5 августа, 2016 интересно, поковыряюсь вечером. Дебаг в трустудио тоже не совсем айс, ну хоть глобальные переменные показывает Ссылка на комментарий
RomanST Опубликовано 8 августа, 2016 Поделиться Опубликовано 8 августа, 2016 Еще интересная тема нашлась, F103 не имеет заводской поддержки DFU (в отличие от, например, F042), но можно реализовать DFU самому, вот тут можно подглядеть реализацию: https://github.com/devanlai/dap42 Это на случай если делать мелкосерийный продукт на F103 и обновлять прошивку без st-link'а... Ссылка на комментарий
TOPMO3 Опубликовано 8 августа, 2016 Автор Поделиться Опубликовано 8 августа, 2016 да, я в курсе, но поскольку никакой мелкосерийки я не планирую, у меня это где-то очень в дальних планах. Вот здесь гораздо интереснее, читать со слова Вторичный бутлоадер Суть - делается вторичный бутлоадер, который представляется как mass storage device, и прошивка заливается как просто копирование файла в эту "флешку". Именно то, что по ссылке, у меня с наскоку не заработало, но имхо направление идеологически верное, так и буду делать, когда дойдут руки 1 Ссылка на комментарий
RomanST Опубликовано 8 августа, 2016 Поделиться Опубликовано 8 августа, 2016 Вот здесь гораздо интереснее, читать со слова Вторичный бутлоадер Суть - делается вторичный бутлоадер, который представляется как mass storage device, и прошивка заливается как просто копирование файла в эту "флешку". Именно то, что по ссылке, у меня с наскоку не заработало, но имхо направление идеологически верное, так и буду делать, когда дойдут руки Забавный велосипед придумали, DFU наоборот, в "заводской" схеме нормальная прошивка начинается со стандартного адреса, а чтобы первым стартовал загрузчик DFU - меняют таблицу векторов прерываний... Ссылка на комментарий
RomanST Опубликовано 27 сентября, 2016 Поделиться Опубликовано 27 сентября, 2016 Дима, а ты случайно не изучал вопрос, какие контролы поддерживает iR кроме осей и кнопок. Вот прямо если идти по документу HID Usage Tables: http://www.usb.org/developers/hidpage/Hut1_12v2.pdf Ссылка на комментарий
TOPMO3 Опубликовано 10 марта, 2017 Автор Поделиться Опубликовано 10 марта, 2017 Рома, извини, только сейчас увидел твой пост. Не изучал, вроде больше ничего и не поддерживает. Не прошло и года, набыдлокодил я прогу-конфигурялку режима работы пинов Not_Used - нога не используется AnalogNoSmooth AnalogLowSmooth AnalogMedSmooth AnalogHighSmooth - различные варианты сглаживания для оси, можно выбрать более подходящий в зависимости от качества потов, всяких эми от осв и т.п. Rotary_PINA Rotary_PINB - крайние (боковые) пины энкодеров Rotary_Enc - средний пин энкодеров Button_ROW - строка матрицы кнопок Button_COLUMN - столбец матрицы кнопок Button - просто одиночная кнопка (вторая нога на +3.3В) Кроме этого, еще сделал калибровку осей. Аналог обычной калибровки через DXTweak2 (например), но ее значения хранятся в самом МК - не надо на каждой новой винде делать калибровку заново. Ну и ось, вне зависимости насколько сильно она порезана калибровкой, всегда выдает 4096 шагов. По кнопкам: Get config from device Save config to device прочитать/сохранить сохраненный конфиг с/в МК Load config to file Save config to file - загрузить/сохранить конфиг из/в файла, если вдруг такое вообще понадобится Соответственно, обновлена и прошивка для стм Прошивка Прога-конфигурялка 2 Ссылка на комментарий
RomanST Опубликовано 11 марта, 2017 Поделиться Опубликовано 11 марта, 2017 (изменено) Дима, как в DirectX через реестр ось инвертировать? Есть детальное описание полей Attributes и FFAttributes? Должно быть где то тут https://msdn.microso...4(v=vs.85).aspx https://msdn.microso...1(v=vs.85).aspx Изменено 11 марта, 2017 пользователем RomanST Ссылка на комментарий
_rar Опубликовано 11 марта, 2017 Поделиться Опубликовано 11 марта, 2017 Счастливые вы люди! Вроде все есть (для симрейсинга), а продолжаете что-то свое выдумывать :good: Ссылка на комментарий
TOPMO3 Опубликовано 11 марта, 2017 Автор Поделиться Опубликовано 11 марта, 2017 Дима, как в DirectX через реестр ось инвертировать? Есть детальное описание полей Attributes и FFAttributes? Я наверно проблему не очень понимаю... Если мы говорим о потах и он выдает инвертированную ось, то достаточно поменять местами у него питание и землю на ногах, так? Если о усилителе для LC, то такой фокус наверно не пройдет, я в этом случае использовал бы маппинг значений для их инвертирования (т.к. я маппинг все равно использую для вытягивания оси после калибровки) long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } 1 Ссылка на комментарий
RomanST Опубликовано 11 марта, 2017 Поделиться Опубликовано 11 марта, 2017 Если о усилителе для LC, то такой фокус наверно не пройдет, я в этом случае использовал бы маппинг значений для их инвертирования (т.к. я маппинг все равно использую для вытягивания оси после калибровки) long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } Да, в своем контроллере я бы так и сделал, речь о G27, там поты в минимуме имеют значение 255, в максимуме - 0. Когда втыкаешь LC, получается инвертированная ось. Конечно, игры чаще всего позволяют поставить галку "инвертировать ось", но я не уверен, что эта галка есть в каждой игре. Ссылка на комментарий
TOPMO3 Опубликовано 11 марта, 2017 Автор Поделиться Опубликовано 11 марта, 2017 Рома, понятно, но имхо править реестр тоже как-то слишком в лоб решение, выйдет какой-ть очередной виндовый апдейт и оно перестанет работать.. может лучше через логитековский профайлер сделать? типа такого правда, насколько я понял, для этого придется делать профиль под конкретную игру, но тут уж надо выбирать меньшее из двух зол... Счастливые вы люди! Вроде все есть (для симрейсинга), а продолжаете что-то свое выдумывать Присоединяйся, это интересно ;) 1 Ссылка на комментарий
TOPMO3 Опубликовано 27 марта, 2017 Автор Поделиться Опубликовано 27 марта, 2017 Стандартным виндовым средством аля "Свойства игрового контроллера" можно протестировать работу только 32 кнопок. Если больше, то обычно приходится запускать какую-ть игру, чтобы проверить остальные - неудобно. Поэтому к OSHStudio добавил третью вкладку, где можно протестить все возможные 64 кнопки Ссылка на комментарий
Schweigsam Опубликовано 27 марта, 2017 Поделиться Опубликовано 27 марта, 2017 Впечатляет. А столько кнопок действительно нужно? Это уже рояль какой-то. 1 Ссылка на комментарий
Рекомендуемые сообщения