вторник, 1 августа 2017 г.

Программирование и отладка NRF52 под ST-LinkV2

  NRF52 - ARM v7 микроконтроллеры от Nordic Semiconductor со встроенным радио (bluetooth, кастомные протоколы, 2.4 GHz).

  Официально программирование/отладка поддерживается хорошо лишь с J-Link, но он стоит в районе 500$, а прям ощутимого профита от его использования я особо не заметил ) Так зачем платить больше? По крайней мере для домашних проектов...

  На текущий момент в OpenOCD 0.10 нет драйвера флеш-памяти для NRF52, потому "из коробки" будет доступна только отладка, а стирание/прошивание чипа - нет.

  К счастью имеется уже готовый патч для OpenOCD, а так же инструкция как что собирать, которую я нашёл вот в этом обсуждении.

На всякий пожарный повторю здесь инструкции + дополню своими:

  Для начала при сборке в Windows придётся поставить кросс компилер, например, из msys или cygwin. Я предпочитаю mingw-w64 для x64 системы из msys, скачать можно тут.

  Запускаем mingw64.exe, ставим зависимости и инструменты, необходимые для сборки. Точный список уже не помню, но как минимум это я ставил:

pacman -S git
pacman -S curl
pacman -S make
pacman -S automake
pacman -S autoconf
pacman -S libtool
pacman -S pkg-config
pacman -S texinfo
pacman -S mingw-w64-x86_64-toolchain
pacman -S mingw64/mingw-w64-x86_64-dlfcn
pacman -S mingw64/mingw-w64-x86_64-libusb
pacman -S mingw64/mingw-w64-x86_64-libusb-usbdk
pacman -S mingw64/mingw-w64-x86_64-hidapi
pacman -S mingw64/mingw-w64-x86_64-libftdi

  Клонируем репозиторий:

git clone git://git.code.sf.net/p/openocd/code openocd-code
cd openocd-code

  Теперь необходимо применить патч, добавляющий поддержку NRF52. Однако я бы порекомендовал файл src/flash/nor/Makefile.am предварительно забэкапить )

git pull http://openocd.zylin.com/openocd refs/changes/15/3215/2

  Патч приводит к конфликтам в двух файлах, конфликты можно просто поправить вручную.       Суть конфликта - в каждом из файлов добавляется инклуд NRF52 сорцов, однако порядок строк инклудов изменён и получается странный конфликт.

gedit src/flash/nor/drivers.c
gedit src/flash/nor/Makefile.am
  Во втором файле ещё и формат путей инклудов поменялся, потому там вообще ад, и как раз для этого я выше рекомендовал src/flash/nor/Makefile.am забэкапить, после чего его восстановить и вручную прописать инклуд NRF52. То есть к NOR_DRIVERS добавить файл %D%/nrf52.c \ и это всё, что там надо поменять.

Следующий шаг:
./bootstrap
После чего настраиваем сборку:
./configure \
    --prefix=/Your-path/openocd-git_install \  //Заменить на свой путь утановки
    --enable-aice \
    --enable-amtjtagaccel \
    --enable-armjtagew \
    --enable-cmsis-dap \
    --enable-dummy \
    --enable-ftdi \
    --enable-gw16012 \
    --enable-jlink \
    --enable-jtag_vpi \
    --enable-opendous \
    --enable-openjtag_ftdi \
    --enable-osbdm \
    --enable-legacy-ft2232_libftdi \
    --enable-parport \
    --disable-parport-ppdev \
    --enable-parport-giveio \
    --enable-presto_libftdi \
    --enable-remote-bitbang \
    --enable-rlink \
    --enable-stlink \
    --enable-ti-icdi \
    --enable-ulink \
    --enable-usb-blaster-2 \
    --enable-usb_blaster_libftdi \
    --enable-usbprog \
    --enable-vsllink
И собираем проект:
make
make install 
 Готово, OpenOCD собран. Теперь, для запуска его без предварительного добавления mingw директорий в PATH, необходимо рядом с OpenOCD.exe положить dll, от которых он зависит:
libftdi1.dll
libhidapi-0.dll
libusb-0-1-4.dll
libusb-1.0.dll
  Найти их все можно в папке msys64\mingw64\bin

  И казалось бы всё, готово, можно пользоваться. Да, но почти ) OpenOCD запускается и прекрасно себя чувствует, однако при попытке отладки любого st-link устройства каждый раз получаю ошибку:

stlink_usb_open(): stlink_usb_open
stlink_usb_open(): transport: 1 vid: 0x0483 pid: 0x374b serial: 
stlink_usb_open(): open failed

  Долго я думал что не так! И сорцы OpenOCD пытался править и очередные баги в исходниках libusb искать, но решил в итоге проблему намного проще )) Качаем бинарники libusb  https://sourceforge.net/projects/libusb/files/libusb-1.0/

  Заменяем корявую libusb-1.0.dll, взятую из mingw64, на нормальную из архива MinGW64\dll\libusb-1.0.dll и всё, программатор открывается.

  Пример *.cfg файла для OpenOCD

source [find interface/stlink-v2.cfg] 
transport select "hla_swd"
source [find target/nrf52.cfg]

Новая железка

  Прикупил вот в Китае для всяческих экспериментов поворотную платформу с 2 степенями свободы. https://ru.aliexpress.com/item/Official-smarian-2-DOF-All-Metal-Rotation-Base-Platform-for-Robot-Arm-with-2pcs-High-Torque/32793398433.html Интересная и относительно недорогая штука.

  Основной подшипник не люфтит (по ощущениям, замерить нечем), редукторы сервоприводов сделаны из металлических шестерёнок (выбрал по ссылке самые простые движки), вся конструкция металлическая (кроме нижней здоровой площадки, к счастью).

  Занятно, что ни у одного продавца на aliexpress, а также на сайте производителя http://makerobotix.com  я так и не нашёл мануала по сборке и в итоге потратил час на скручивание всех деталей вместе.

  Болтов и гаек продавец не пожалел, видимо в курсе канона, что после сборки просто обязаны остаться "лишние детали" )



  Два диска хватаются за внутреннее кольцо подшипника с двух сторон и два металлических кольца за внешнюю оболочку.






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

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

  Ну и "лишние детали" после сборки:




суббота, 11 марта 2017 г.

Как убить материнскую плату за полчаса (перепаивание AMD GPU)

Дано:
1. Материнская плата ноутбука HP Pavilion DV6 6179er со сгоревшим GPU чипом.

2. Свежекупленный GPU чип на aliexpress

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

Задача: перепаять GPU чип.

Приступим:

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


2. Потихоньку прогреваем паяльным феном видео чип до 330 градусов.
3. Что-то не так, 330 градусов "как обычно", но чип недвижим.
4. Греем до 400 градусов - ноль реакции
5. Греем с ужасом до 430 градусов - начинает плавиться термоскотч и жутко вонять, чип недвижим о_О
6. Греем до 450 градусов - чип начинает двигаться. Здесь очень важно не прекращать ни в коем случае нагрев и не прикладывать ощутимых усилий в попытках сдвинуть чип. Лучше всего его поднимать вакуумным пинцетом, что я понял гораздо позже (. Если в процессе снятия чипа немного снизится температура, то он тут же обратно припаивается, да ещё и очень криво. Обратное припаивание в процессе снятия чипа может привести к тому, что можно сорвать площадки, к которым чип припаян. Они ОЧЕНЬ легко отрываются, тем более когда так жутко перегрета плата.
7. Снимаем чип (аккуратно, без усилий!!!). Тут ещё один важный момент есть: вокруг чипа напаяна куча SMD компонентов и снимая его пинцетом можно случайно толкнув сдвинуть эти самые SMD компоненты, потому куда приятнее поднимать его вакуумным пинцетом сразу вертикально.



8. На падах осталось много олова (или стали, WTF, почему у этого сплава температура плавления 450 градусов???), необходимо удалить всё аккуратно (о, да :(( ) и качественно, иначе чип плохо припаяется. Берём специальную оплётку, паяльник (и как я тупим дико и убираем подогрев феном, надеясь на паяльник), обильно смазываем флюсом и чистим пады.

9. Ну вот и всё, осталось впасть в уныние и печалиться с того, что не подумал вовремя, убрал подогрев (мешался), попытался при помощи оплётки и паяльника снять олово и оторвал несколько падов. Оплётка довольно большая, паяльник не очень мощный и часто во время движения оплётки по площадкам паяльник не догревает, олово резко остывает и по инерции лёгким движением руки срываются с платы тоненькие площадки.

Если приглядеться, можно заметить на фото оторванные площадки по краям (те, что поменьше)

вторник, 29 ноября 2016 г.

Проблемы с File URI SVN в Linux после Windows

Ситуация такова: в локальной сети имеется компьютер с именем, например, server. На нём расшарена папка с именем svn в которой я храню свои SVN репозитории. На том компе нет реального "SVN сервера", просто расшареная виндовая (samba) сетевая папка, в которой вручную создаются репозитории  (каждый в своей подпапке).

Как чекаютятся репозитоии в windows в таком случае: используется file схема пути, т.е. например  file://server/svn/MyProject и всё работает отлично.

И вот настал тот час, когда мне стало необходимо зачекаутить этот репозиторий и из под Linux-а. Тут ждёт первая проблема: file схема на линуксе работает только с локальными путями! Все остальные требуют сервера на удалённом компьютере (что у меня сейчас не возможно). Первое решение очевидное - просто монтируем сетевую папку например в /mnt/svn и оттуда чекаутим file:///mnt/svn/MyProject  и это действительно отлично работает! Кроме одного косяка... Работая под Windows-ом в репозиторий MyProject я добавил внешний (external) репозиторий MyProject2! И конечно же до него путь сохранился такой: file://server/svn/MyProject2  и при чекауте MyProject SVN не может слить его зависимость по пути file://server/svn/MyProject2.

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

Первое действие - создал в корне файловой системы папку /svn и примонтировал в неё сетевую папку server/svn. Всё ок, я могу чекаутить мой проект по пути file:///svn/MyProject  Теперь на хватает в пути всего-то слова server. К счастью в svn есть один альтернативный вариант написания пути: file://localhost/svn/MyProject.  Однако проблема  в том, что на линуксе SVN просто удаляет слово localhost из пути! И если оно написано не верно, то выводит ошибку и ни чего не делает. Плохо, что нет резолва IP и чекаута по сети и слово localhost - просто затычка, однако в моём простом случае это и было решением )

Так как localhost просто заглушка и ни чего не значит, то его можно заменить и на другое слово, например...  на слово "server" )  Беда только в том, что внешних конфигов нет, это слово зашито в коде SVN. Но разве ж это настоящая проблема?

Решение:
1. Чекаут исходников subversion svn co http://svn.apache.org/repos/asf/subversion/trunk subversion
2. Идём в папку subversion/subversion/libsvn_subr, открываем файл dirent_uri.c
3. Находим функцию svn_uri_get_dirent_from_file_url
4. Ищем код
if (strcmp(hostname, "localhost") == 0)
    hostname = NULL;
5. меняем на такой код
if (strcmp(hostname, "localhost") == 0 || strcmp(hostname, "server") == 0)
    hostname = NULL;
6. Билдим SVN
 
   sudo apt-get install autoconf
   sudo apt-get install libtool-bin
   sudo apt-get install apache2-dev libapr1-dev libaprutil1-dev
   sudo apt-get install zlib1g-dev

   ./get-deps.sh
   cd apr/
   ./buildconf
   cd ../apr-util/
   ./buildconf
   cd ../apr-util/xml/expat/
   ./buildconf.sh
   cd ../../..
   ./autogen.sh
   ./configure
   make //в папке subversion
7. Устанавливаем в систему В папке subversion/subversion/svn лежит бинарник с именем svn Я его просто копировал в /usr/bin Но может ещё понадобиться сделать
    sudo make install
Иначе некоторые зависимости не находит! Почему make install не ставит сам бинарник (у меня) - не ясно, курить скрипты лень )

суббота, 10 сентября 2016 г.

D3D12

Решил поломать код движка, да перевести на DX12. На удивление туго пошло осознание нового АПИ, пришлось потратить 4 вечера на минимальный порт. А вот и свежие восхитительные пиксели, отрендеренные на D3D12:



воскресенье, 12 июня 2016 г.

Работа с EEPROM 24C16 на STM32 контроллере

Понадобилось по-быстрому запилить простой "программатор" EEPROM микросхемы, да чтоб читать/писать память её можно было через юзерское приложение в Windows. И что-то я подзатупил изначально с адресацией памяти.

Для работы с EEPROM (и не только) в STM32CubeF4 библиотеке есть функции HAL_I2C_Mem_Read и HAL_I2C_Mem_Write, инициализацию I2C генерит приложение STM32CubeMX, в общем-то халява, осталось использовать функции, передать данные из/в компьютер и девайс готов. Однако меня сбил с толка параметр функций uint16_t MemAddSize, который может быть равен I2C_MEMADD_SIZE_8BIT или I2C_MEMADD_SIZE_16BIT.  В моей микросхеме 2048 байт памяти и логично предположить, что мне нужен вариант I2C_MEMADD_SIZE_16BIT,  т.е. 16 бит на адрес,ибо 8 бит хватит только на адресацию 256 байт.


А вот и нет. Память "побита" на блоки по 256 байт, выбор ID блока происходит через запись соответствующего ID в биты 1,2,3 байта адреса устройства:









Их можно трактовать как ID 256-байтного блока или просто как старшие дополнительные 3 бита адреса памяти (как в таблице и указано). То есть адресация здесь 11 битная.

Собственно, адрес _устройства_ получаем таким образом:  0xA0 | ((memory_address >> 7) & 0xE).  Нулевой бит по идее контроллируется библиотекой и делать операцию битового чтения & 0xF по идее не нужно. Но опыт подсказывает, что доверять библиотеке Cube от ST не стоит )

Вдруг кому сэкономит время )

суббота, 9 апреля 2016 г.

HDMI на FPGA Cyclone II

Запилил на своём борде с Cyclone II генерацию HDMI сигнала. Всё сделано так же как и в проекте HDMI для платы Марсоход3, только у меня разрешение картинки 800x600x60Hz


Для генерации разрешения 800x600 необходимо во-первых заменить параметры таймингов в файле HDMI_1280.v на эти

always @(posedge pixclk) DrawArea <= (CounterX<800) && (CounterY<600); 
always @(posedge pixclk) CounterX <= (CounterX==1055) ? 0 : CounterX+1; 
always @(posedge pixclk) if(CounterX==1055) CounterY <= (CounterY==627) ? 0 : CounterY+1;
always @(posedge pixclk) hSync <= (CounterX>=840) && (CounterX<968);
always @(posedge pixclk) vSync <= (CounterY>=601) && (CounterY<605);

А так же сгенерить свою PLL с 2 выходами клоков на 40MHz и на 200MHz. 40MHz - частота тактования пикселей, с ней всё ясно, а вот 200 MHz это частота тактования TMDS энкодеров (в HDMI применяется TMDS 10 битное кодирование), они тактоваться должны на частоте в 10 раз быстрее пиксельклоков, однако т.к. используются DDR выходы ПЛИС-а, частота тактования TMDS делится на 2, итого (40*10)/2 = 200MHz

четверг, 7 января 2016 г.

Симулятор квадрокоптера: симуляция щёточных DC моторов

Решил немного поразвлечься и запилить симуляцию щёточных моторов постоянного тока в Unity для виртуального квадрокоптера и не только.

Не думал о подобном ранее, но чуток покопавшись понял, что всё достаточно просто )
(Я далеко не физик/электронщик и могу что-то сам не так понимать или описывать, но тем не менее)

Щёточный DC схематически можно представить так:




R - сопротивление обмотки ротора.
L - индуктивность обмотки ротора
e - обратная ЭДС обмоток ротора.
J - момент инерции ротора

Из за вращения ротора в статичном магнитном поле в его обмотках появляется обратная ЭДС, создающая обратное напряжение в обмотках, которое ограничивает максимальные обороты движка (но не только оно ограничивает). Зависит линейно от угловой скорости ротора.

Так же есть ЭДС самоиндукции, появляющаяся при изменении тока, проходящего по обмоткам.
E = - L* (dI/dt)
- как видно тут участвует производная тока и самоиндукция будет влиять на работу мотора только когда ток меняется, КЭП.

e - величина линейная, зависит от угловой скорости ротора, равна k_e * w. k_e - константа обратной ЭДС.

Пользуясь вторым правилом Кирхгофа можно записать уравнение напряжения в моторе:

Vs = R*I + L*(dI/dt) + e;

тут Vs - напряжение питания мотора.

Не сложно переписать уравнение так, что бы выразить производную тока:

dI/dt = (Vs - (R*I) - e) / L;

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

Me = Mm + Mf + Ml

Me = электрический крутящий момент, т.е. момент, сгенеренный обмотками ротора.
Mm - механический момент ротора,  J* (dw/dt) где J - момент инерции ротора, кг*м^2
Mf - момент трения ротора, линейно зависит от угловой скорости, k_f * w,
Ml - момент внешней нагрузки на ротор.

w - угловая скорость ротора [рад/с]

т.е. Me = J*(dw/dt) + k_f*w + Ml;

Тут есть важная штука: "электрический" момент линейно зависит от тока на обмотках якоря и его коэффициент является одной из важнейших характеристик моторов. То есть "электрический" момент (Me) = k_t * I;

k_t * I = J*(dw/dt) + k_f*w + Ml;

Выразим производную угловой скорости ротора:

dw/dt = (k_t*I - k_f*w - Ml) / J

Теперь у нас есть 2 дифференциальных уравнения, которые можно проинтегрировать и получить графики работы движка.

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

Изначально ничего не сошлось, т.к. я не корректно вбил коэффициенты. Плюс к тому не ясно для какого точно напряжения построен график и какое точно сопротивление было у движка, для которого он строился.  Коэффициенты то есть в даташите, но они немного отличаются от того, что на графике!

Что бы график сошёлся идеально, необходимо было крутить несколько коэффициентов. Это достаточно геморно и потому я использовал алгоритм оптимизации Левенберга-Марквардта для автоматической подстройки параметров ))) Критериями ошибок стали максимумы и производные графиков тока и оборотов мотора, а так же разница между идеальными и реальными экстремумами графиков мощности и эффективности, вот что получилось:




Тут gizmo используется для отрисовки графиков, под ними подложка с текстурой реальных графиков. Всё вполне совпадает )

А вот график по времени. Сначала включается питание мотора и потом по достижению максимальных оборотов питание отключается. Видны 2 всплеска на графиках - большой пусковой ток и выброс в отрицательную сторону при выключении.  Синий график - обороты, красный - ток.