Pull to refresh

Comments 31

Stm32 для ленты это сильно, это как из пушки по воробьям, esp8266 или esp32 последняя избыточна даже, можно использовать attiny даже.

STM32 использовать удобно, потому что для того, чтобы микроконтроллер мог делать что-то ещё, очень желательно иметь DMA, иначе понадобятся прерывания с частотой 312,5кГц и максимальной задержкой около 6 мкс, а реализовать это - нетривиальная задача, и такой подход даёт большую загрузку микроконтроллера обработкой этих прерываний. Или нужно запрещать прерывания на время обновления данных в ленте, а это далеко не всегда приемлемо. Другое дело, что STM32F411RE для такой задачи избыточен, вполне подойдёт любой самый мелкий и дешевый STM32 серий C0, G0, L0 или F0 стоимостью от $0,21/шт, но это больше зависит от того, что ещё должен делать этот микроконтроллер.

максимальной задержкой около 6 мкс, а реализовать это - нетривиальная задача, и такой подход даёт большую загрузку микроконтроллера обработкой этих прерываний

Более чем. Делал протокол WS2812b руками на nopах, забил всю память STM32 Discovery. На таймерах/SPI получилось бы сильно проще и меньше.

Здесь важен принцип, а не конкретный контроллер. А также время реализации и удобство. Сейчас процов аля Cortex-M0 как грязи и стоят многие как грязь. Зачем тогда заниматься самоистязанием и пытаться "эффективно" использовать ресурсы железа? Если это только не самоцель и попытка придраться "к столбу".

Смотря сколько лент надо контролировать, сколько диодов на них и с какой частотой их переключать. Если их несколько тысяч, простые контроллеры могут не переварить.

и как вашим attiny через wifi управлять?

Я делал точно так же, но кодировал по два бита в одном байте.

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

typedef struct {
  uint8_t red;
  uint8_t green;
  uint8_t blue;
} led_t;

led_t led_string[LED_NUM];

При желании можно сюда же добавить поле для управления яркостью.

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

Я вот не любитель жёстких извращений с NOPами, HAL_Delay, и тем более переключением скорости налету. Я беру 7-битный UART, по таблице LUT пихаю в него 3x3 бита для WS2812, натравливаю DMA на подготовленный фрейм-буфер, и получаю нужную скорость без танцев с бубном. Не забываю инвертировать сигнал UARTа при преобразовании из 3V в 5V.

С 1-wire и через USB-UART это всё тоже работает.

Про переключение скоростей это я ляпнул, да, спутал с чем то другим :)

Там ещё много недопереведенного. Например:

  • " CPOL имеет низкий уровень, а CPHA — 1 ребро ". Edge ошибочно переведено как "ребро" вместо "по фронту"

  • "сигнал сброса подается путем снижения уровня сети передачи данных более чем на 50 мкс" вместо "установки низкого уровня на линии данных на 50мкс".

В статье по ссылке в конце поста есть видео с оригинальным английским текстом.

Печально, что люди выдают чужой труд за свой, даже не понимая о чём пишут...

я в конце написал откуда я инфу брал, часть сам писал а большую часть перевел просто в ру комьюнити, в самом конце ссылку оставил на первый источник

Я десяток опечаток в стиле "трудности перевода" автору отправил. Пока нет реакции.

Привет.Я брал информацию с английского сайта, просто перевёл для комьюнити СНГ,это моя 1 статья я пока не особо разбираюсь, в конце там ссылка на этот сайт есть

А без hal уже все разучились писать?

Ну напишет с CMSIS и выиграет что? Я понимаю когда в память сильно упираемся или надо пик производительности выжать.

С HAL переносимость лучше. Это ведь макет, и скорее всего на другом контроллере, чем в целевом устройстве. Потом если надо можно оптимизировать.

А в чём смысл игнорировать hal?

Смысл в том, что HAL использует в разы больше ресурсов, чем программа, написанная на прямом обращении к регистрам - флэша, RAM, и процессорного времени, в том числе и в прерываниях. При этом существуют и эффективные библиотеки на шаблонах C++, которые делают пользовательский код даже проще, чем с использованием HAL, и он при этом сохраняет максимальную эффективность. Это может быть важно, если микроконтроллер имеет мало памяти, и занят ещё какими-то ресурсоёмкими или критичными по времени отклика задачами. В статье ведь ничего не говорится о том, сколько всего будет светодиодов в ленте - 8, 200, или 1000, с какой частотой предполагается обновлять видеоинформацию, что это вообще за устройство, основная ли его функция управление светодиодами или побочная, и макет ли это, или конечный вариант электроники, и если макет, то какой контроллер будет использоваться в конечном варианте. Но HAL имеет преимущество по сравнению с библиотеками C++ и тем более по сравнению с ручным кодированием управления регистрами в переносимости. С HAL пользовательский код можно переносить с минимальными изменениями между вообще всеми микроконтроллерами STM32, включая самые новые, которые постоянно появляются десятками в год, и использовать в проектах с RTOS и без неё.

Ну вот вы по сути сами написали суть. HAL имеет смысл, когда идёт борьба за ресурсы. Но по факту, всем нужна быстрая разработка, переносимость кода и ... возможность поддержки уже существующих проектов. Поэтому, выбирают hal, вместо того, чтобы забыть на месяц-другой про разработчиков, что бы те разобрались с дадашитом. Это дорого, и ничем не оправдано. Не хватает ресурсов у 3 серии, просто переходим на 4-ю. Клиент оплатит. Тоже самое и проекты на асме. Для удовлетворения личного эго (смотрите, как я могу!) - пожалуйста, но не в проект.

В данном случае задача совсем не такая сложная, чтобы нужно было месяц-другой разбираться с даташитом, даже если писать на регистрах без библиотек. Это легко можно написать за день, пользуясь только даташитом и референс мануалом, и ещё быстрее - используя LLM, и тот же HAL как пример проверенного кода при неоднозначности документации. А с библиотеками на С++ это вообще несколько строк кода, к тому же обычно переносимого в рамках по крайней мере одной серии микроконтроллеров. С HAL может быть и ещё быстрее, но в чём тогда смысл статьи на Хабре - ведь здесь гораздо более уместны статьи, разбирающие сложные темы, а не то, что любой, кто в теме, может сам сделать за полчаса.

Думаю, смысл данной статьи - просто поднять себе карму. Но, как уже выяснили, статья - кривой перевод, а автор даже не понимает о чём пишет.

Так он и не заморачивался - он просто тупо скопировал бОльшую часть статьи из https://controllerstech.com/ws2812-leds-using-spi/ причём прямо с кривым тамошним автопереводом с английского. Картинки и видео оттуда же

Всё так )

Можно, я тоже отвечу вопросом на вопрос к предыдущему вопросу?

У вас были реальные случаи, когда STмовский HAL помог перенести прошивку с одного мк на другой? С STM1x на STM0x хотя-бы? C STM на другой 32-битный ARM, LPC например? На не 32-битный, а на AVR или хотя-бы их же STM8 может быть?

Если нет, то я продолжу считать этот HAL тупой обёртокой над железом. И чтобы ей воспользоваться, приходится не только доку на железные регистры читать, но ещё и на этот HAL. А действительно хардварной абстракцией продолжу считать уровень Linux (и других известных ОС, наверное) и Arduino.

Когда то тоже добрался реализовывать протокол для них на STM32, и тогда приглянулся именно SPI. Но мне показалось логичным организовать это управление бит в бит (бит SPI -> бит в интерфейсе WS2812). Тогда цветовой буфер это именно массив структуры GRB с атрибутом {packet*} - представлялся в памяти непрерывным массивом байт для передачи по SPI. Оставалось только затактировать SPI (включен он режиме slave) от одного из таймеров. Таймер настраивался на время передачи одного бита SmartLED и выходы пары его регистров CCRx были настроены один на время длительности H-уровня протокола, другой L-уровня. (один из них выдавался инвертированым, т.к. подключплся к внешней комбинаторной схемке (2И-НЕ или 2ИЛИ-НЕ). Один из импульсов генератора тактировал SPI и оба они вместе с выходом SPI (MISO) подключались к комбинаторке на выходе которой формировался непосредственно протокол управления SmartLED.
Тогда даже применил последовательно соединение таймеров. - Тоесть этот таймер тактироваЛ другой по событию обновления соответственно тот считал количество отправляемых бит протокола
и генерил прерывание как только нужное количество бит(по длине ленты ) отсчитает. - Устанавливал в первом счётчике значение счёта на продолжительность RET и прерывание по окончанию фиксило завершение обновление ленты и взводило DMA на следующий запуск. Обновление ленты инициировалосс только в случае изменений в цветовом буфере.

Sign up to leave a comment.

Articles