На прошлой неделе я на макетке спаял модуль для снятия данных с 26-разрядных абсолютных угловых энкодеров по протоколу BISS-C. Отладил в четверг вечером код, чтобы уж точно оба SPI работали (поначалу не мог понять, что за дичь со вторым SPI, но тут заметил, что я оставил от USB-шаблона работу с USART1, который тот же самый канал DMA использует, что и SPI2); в пятницу установил этот блок (но, судя по всему, опять оторвал один из тонких проводков от энкодера; как только кончатся эти долбаные дожди, надо будет смотаться и перепаять все нормально, чтобы уж точно не рвалось). Напомню, что решение напрямую в USB считывать показания датчиков возникло из-за того, что родная астросибовская "коробочка" читает лишь каждые 50мс, а мне минимум 100 раз в секунду надо (а, может, и тысячу — это уж как покажут эксперименты после соединения всего воедино). В понедельник честно воспользовался выходным, а вчера и сегодня дорабатывал прошивку для работы с энкодерами. Сама макетка:
Взял первое, что было под рукой в огромном количестве: "bluepill". Правда, два SPI, как оказалось, есть лишь начиная с STM32F103C8, а в 6 только один. У меня же большинство "таблеток" именно на 6. Еле нашел одну дома и одну на работе. Правда, домашняя внезапно оказалась китайской копией (узнал, когда пытался openocd для отладки запустить; благо, нашел в интернете конфигурационный файл). Поменял на рабочую, там оказался "более-менее оригинал". А то уж думал перепаять (т.к. наткнулся на "косяк" с SPI2, который, как позже выяснилось, был моим косяком, а не подделки). Вот так было раньше:
А теперь такое безобразие:
Подключил через USB-hub, потому как в компе, купленном для СУ третьим, USB прямо в сильном недостатке. Ну и сразу же подключен st-link. Шнурок +5В я от разъема USB не подпаивал, запитываю внешними 5В от той же "управляемой" розетки, что и телескоп. Так вот, собственно вот этот файл — почти чистое творчество ИИ. Оказывается, в "режиме раздумий" он понемногу все лучше и лучше справляется. Первое, что он выдал, было совсем неюзабельным. Я подкорректировал задачу, получил это. Правда, пришлось всякие bool менять на uint8_t, size_t на uint8_t/uint32_t ну и т.п. Фигню "Store remaining bits if any" закомментировал, как unreacheable (да так и забыл выкинуть). В compute_crc он налажал. Пришлось гуглить, как этот гребаный "полином" вычислять. Вот ненавижу извращенцев, которые вместо тупого суммирования или XOR мутят какой-то бред! В конечном автомате из parse_biss_frame он допустил грубый косяк, пришлось добавить еще одно состояние (SEARCH_ZERO). Ну и добавил параметр enclen, а минимальное/максимальное количество нулей макросом определил (оно зависит лишь от скорости SPI: чем больше, тем длинней должен быть массив данных и больше нулей будет на стадии ожидания). Думаю, нужно будет и максимальную длину сообщения вместе с этими нулями сделать конфигурируемым параметром (вдруг я "на лету" захочу поменять скорость SPI: сейчас она 2МГц, но допустимо до 10МГц). Сама функция поиска битов, конечно, жрет достаточно много ресурсов. Но то, что я поначалу предполагал сделать, не сильно-то лучше. Был бы там little-endian, а не big-endian, было проще. Еще какое-то (хоть и куда меньшее) время отжирает функция преобразования числа в строку. Хотя, совместно с записью в порт USB получается сильное снижение производительности: если за 1 секунду в режиме "бенчмарка" без вывода данных (только анализ и подсчет годных и негодных данных) получаю по 3300 измерений с каждого канала, то как только на один USB начинаю выводить, снижается уже до 2500. Больше двух часов с USB бился: пытался повысить скорость. Но, увы, так и не придумал ничего приличного. Кольцевой буфер достаточно приличный, однако, чтобы не тупил вывод (особенно это нервирует, когда в терминале работаешь), в функции записи данных, если передача по USB в текущий момент не происходит, она запускается по концу строки. В прерывании по готовности отправки пакета проверяется, нет ли в буфере данных. Если есть — отправляются, нет — выставляем флаг. Конечно, размеры буфера небольшие (у меня 3 конечных точки, поэтому пришлось выходные буферы по 64 байта делать, а входные — по 40), но подозреваю, что таки блоки пусть даже по 64 байта прибегали бы в комп быстрей, чем по 10. Очень сложно без мьютексов управляться на МК с тем, что у тебя в одном месте могут в этот буфер писать, а в другом — пытаться из него прочитать. Пришлось делать блокирующие флаги в функциях кольцевого буфера.
Завтра еще подумаю, что нужно, чтобы "добить" код до хотя бы пре-релиза, а потом сяду очередную плату нарисовать. Многоканальный (7 каналов) преобразователь USB-serial с гальваноразвязками на каждый канал уже нарисовал, теперь надо вот это сделать (тоже с гальваноразвязками на энкодеры, чтобы не спалить их в случае чего). Ну и останется еще нарисовать платку для работы с ИК-датчиками (простой преобразователь I2C в RS-485 с развязкой) и датчиками грозы (там развязка не нужна, взял бы "стандартный" преобразователь I2C-USB, но в случае зависания датчика надо сбрасывать питание; удобней это по протоколу делать, а не отрубая USB — тем паче, не у всех компьютеров питание USB можно отключить).