STM32 blink++ или читаем данные инкрементального энкодера
Мотивация
Пару месяцев назад я рассказывал, как работает инкрементальный энкодер и как читать угол при помощи простейшей ардуины. Разумеется, немедленно получил вот такие комментарии:
У меня ардуино головного мозга. Пусть лично я самой средой ардуино и не пользуюсь, но всё же считаю, что это весьма полезная штука. Я слышал много ужасов про то, как начинать с stm32, и не хотел в это влезать. С другой стороны, в последнее время всё чаще стали слышны комментарии о том, что инструментарий допилили и вообще всё в шоколаде. Решил попробовать, сколько времени у меня займёт сделать простейший проект типа помигать светодидом. Купил синюю таблетку, купил китайский аналог отладчика st-link v2, и сел с этим всем разбираться.
Забегая вперёд, вот так выглядит железка, о которой идёт речь:
Поехали: настройка проекта
В качестве среды разработки я выбрал System Workbench for STM32, это эклипс с предустановленными плагинами для работы с stm32. Вторая софтина, которой очень удобно пользоваться, это STM32CubeMX. В идеальном случае больше ничего не нужно. Достаточно зарегистироваться на этих двух сайтах, скачать софт, покликать на кнопочки «ок».
А дальше начинается самое интересное. Интернет очень беден на туториалы, которые работают. Посему покажу целиком весь кликодром, который позволил запустить мой код. Я чувствую, что сам буду возвращаться в этот пост.
Запускаем STM32CubeMX, вбиваем наш процессор и жмём на кнопку start project:
STM32CubeMX — это софтина, в которой мы конфигурируем ноги процессора, а потом получаем готовый шаблон кода, в котором уже всё сконфигурировано, нужно лишь использовать.
У большинства синих таблеток на пине PC13 висит светодиод, как же мы без него, конфигурируем его в GPIO_OUTPUT:
Мы хотим, чтобы работал процесс отладки, поэтому ставим serial wire в SYS:
Я решил повесить энкодер на таймер TIM4, ставлю его в этот режим. Обратите внимание, что НЕКОТОРЫЕ входы процессора терпимы к 5 вольтам (five volt tolerant, FT), и конкретно PB6/PB7 позволяют подключить пятивольтовый энкодер.
Я люблю выводить данные в старый добрый виртуальный последовательный порт, прямо как в ардуине, поэтому кликаем ещё пару раз:
Процессор будет получать клок от внешнего резонатора:
Теперь ноги более-менее расставлены, самое время расставить клоки. Идём в закладку clock configuration, и отказываемся от автоматического помощника:
После чего выставляем всякие делители следующим образом:
Дальше configuration→GPIO настраиваем ногу GPIO:
и в configuration→TIM4 настраиваем таймер так, чтобы он считал в режиме 4x (см. мою предыдующую статью, там объясняется, что это такое)
После чего в настройках проекта выставляем директории и то, что код должен сгенерироваться под System Workbench for STM32:
После чего генерируем код, и открываем эклипс. Первым делом кликаем сюда:
И дальше мы готовы писать код.
Непосредственно код и отладка
Вот так выглядит единственный код, который я написал руками, в нём всё довольно прозрачно:
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM4_Init();
MX_USB_DEVICE_Init();
HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_ALL);
char buf[25];
int32_t capture=0, capture_prev=0, encoder=0;
while (1) {
capture = TIM4->CNT;
encoder += capture - capture_prev;
if (abs(capture-capture_prev)>32767) {
encoder += (capture
Единственная тонкость в том, что у синей таблетки все счётчики 16-битные, а у меня энкодер генерирует 10000 событий на оборот. Поэтому я руками отслеживаю переполнение значения счётчика, мой код предполагает, что между двумя чтениями счётчика энкодер не сгенерирует 32к импульсов, писать прерывания-обработчики события overflow/underflow мне было откровенно лень. Светодиод у меня изменяет своё состояние при каждом переполнении, у нас блинк или нет?
Всё вроде готово, поэтому компилируем проект и запускаем отладчик:
Сама синяя таблетка воткнута в usb, от неё идут 3 провода к китайскому stlink, который тоже в свою очередь воткнут в usb. Энкодер получает питание 5В от USB. Если всё прошло хорошо, то запустится отладчик и у нас в системе появится виртуальный порт /dev/ttyACM0.
Вращаю вал энкодера пальцами, делаю cat /dev/ttyACM0 и наслаждаюсь правильным чтением энкодера:
Если хочется сделать просто блинк/подобное, то минимальное подключение синей таблетки выглядит вот так:
А если не всё хорошо?
USB
Чтобы дойти до этого момента, мне понадобилось полных три дня. Что же заняло столько времени? Например, если я повторно залью код в синюю таблетку, то она будет хорошо работать, отладка тоже, последовательный порт будет присутствовать в системе, но ничего из него не будет поступать. Если переткнуть usb шнурок, то всё будет прекрасно.
Длительное гугление приводит к тому, что в разводке платы есть проблемы, и более того, чаще всего в ней стоит неправильный резистор:
Замена этого резистора у мне помогла на половине компьютеров. Более внимательное гугление показывает вот это. Вот так выглядит предложенный фикс:
Я же удовольствовался программным резетом усб устройства. Вот код, ему достаточно сделать cc usbreset.c:
/* usbreset -- send a USB port reset to a USB device */
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
const char *filename;
int fd;
int rc;
if (argc != 2) {
fprintf(stderr, "Usage: usbreset device-filename\n");
return 1;
}
filename = argv[1];
fd = open(filename, O_WRONLY);
if (fd < 0) {
perror("Error opening output file");
return 1;
}
printf("Resetting USB device %s\n", filename);
rc = ioctl(fd, USBDEVFS_RESET, 0);
if (rc < 0) {
perror("Error in ioctl");
return 1;
}
printf("Reset successful\n");
close(fd);
return 0;
}
А вот так его работа:
Обратите внимание, что сначала из порта ничего не поступало, после софтерного резета всё починилось.
SWD
Какие ещё могут быть проблемы? Например, неработающий отладчик:
Я очень долго не мог залить код, а когда смог, то сначала мне приходилось ставить джамперы в boot0=1, boot1=0, заливать код, а потом переставлять джамперы обратно. При том, что нормальное положение джамперов — это boot0=boot1=0. Это из-за того, что в процессоре был отключен SWD, обратите внимание, что мы его специально включали в STM32CubeMX. Но мы-то включили, а плата могла прийти с отключенным SWD, откуда свистопляска.
Бутлоадер
Если вдруг кто-то решит, что ардуино-среду уже допилили под стм, то имейте в виду, что бутлоадер скорее всего предпрошит не будет.
Защита от записи
В одной из купленных мною плат был просто защищён от записи флеш. Единственно известный мне способ это починить — это под виндой установить STM32 ST-LINK Utility и полностью затереть память. Линуксовые приблуды не помогают.
Просто дохлые платы
А бывает и так. Причём оно как-то шевелится, но частично дохлое. Как это отличать от своих кривых рук — не очень ясно.
SWO: Serial wire output
У вас есть официальная демо-плата и вы привыкли делать вывод информации через SWO? С китайским клоном напрямую такой фикус не пройдёт, не теряйте время, вот фикс:
Вывод
И много-много других проблем, каждая из которых в принципе может быть решена. Например, то, что у stm32 errata (если существует) зачастую длиннее самого даташита…
Нигде нет системизированной информации для новичков, простейшая мигалка светодиодом моментально превращается в головную боль. Да, теперь я чуточку разобрался, и очень надеюсь, что смогу продолжить разработку с меньшими проблемами, у меня хотя бы точно работает отладчик.
В целом я не жалею потраченного времени, и следующий проект буду пилить на stm32. Но теперь мне совершенно ясно, отчего у подобных синих таблеток существенно меньше коммьюнити. Если вам не нужна головная боль, а нужно просто работающее железо, то не ведитесь на рекламу, мол, оно всё копеечное. Покупайте настоящие программаторы и настоящие платы разработчика. А то и вообще оставайтесь в среде ардуино, в ней много чего вкусного.