C++
Programming
Programming microcontrollers
Robotics development
February 22 2018

STM32 blink++ или читаем данные инкрементального энкодера

Tutorial

Мотивация


Пару месяцев назад я рассказывал, как работает инкрементальный энкодер и как читать угол при помощи простейшей ардуины. Разумеется, немедленно получил вот такие комментарии:



У меня ардуино головного мозга. Пусть лично я самой средой ардуино и не пользуюсь, но всё же считаю, что это весьма полезная штука. Я слышал много ужасов про то, как начинать с 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<capture_prev ? 65535 : -65535);
      HAL_GPIO_TogglePin(MY_PIN_13_GPIO_Port, MY_PIN_13_Pin);
    }
    capture_prev = capture;
    sprintf(buf,"count: [%ld]\n", encoder);
    CDC_Transmit_FS((uint8_t *)buf, strlen(buf));
    HAL_Delay(100);
  }
}

Единственная тонкость в том, что у синей таблетки все счётчики 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 <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>

#include <linux/usbdevice_fs.h>


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. Но теперь мне совершенно ясно, отчего у подобных синих таблеток существенно меньше коммьюнити. Если вам не нужна головная боль, а нужно просто работающее железо, то не ведитесь на рекламу, мол, оно всё копеечное. Покупайте настоящие программаторы и настоящие платы разработчика. А то и вообще оставайтесь в среде ардуино, в ней много чего вкусного.
+34
16.2k 126
Comments 67
Similar
Top of the day