Управление адресной светодиодной лентой без использования библиотек
- Войдите на сайт для отправки комментариев
Втр, 04/06/2019 - 13:29
Здравствуйте.
(Заранее извиняюсь за возможно неправильный выбор раздела)
Как понятно из названия темы мне нужно управлять Адресной Светодиодной Лентой без использования библиотек.
В даташите на ленту изображён побитовый способ передачи цвета (а именно временные задержки и порядок передачи).
Вопрос:
Как с помощью ардуино соблюдать временные задержки при передаче данных о цвете.
Примечание:
АСЛ (сокращение от Адресная Светодиодная Лента) имеет чипы WS2812b.
Даташит на них.
Какой длительности задержки?
Почитайте здесь: http://arduino.ru/forum/proekty/pokhvalimsya-khudozhestvennoi-samodeyatelnostyu-na-ws2812
работает неплохо, и без библиотек. Правда немного критично к версии IDE. Под 1.6.5 работает точно под 1.6.9 - нет.
Исходный код:
#ifndef cbi #define cbi(sfr, bit) (sfr &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif #define ARDUINO_PORT(a) ((a<8)?PORTD:(a<14?PORTB:PORTC)) #define ARDUINO_PIN(a) ((a<8)?PIND:(a<14?PINB:PINC)) #define ARDUINO_DDR(a) ((a<8)?DDRD:(a<14?DDRB:DDRC)) #define ARDUINO_PIN_NUM(a) ((a<8)?a:(a<14?(a-8):(a-14))) #define LED_PIN A5 #define LED_PIN_NUM ARDUINO_PIN_NUM(LED_PIN) #define LED_PORT ARDUINO_PORT(LED_PIN) #define NumberLED 30 byte arr[NumberLED*3]; // the setup routine runs once when you press reset: void setup() { pinMode(LED_PIN, OUTPUT); } extern "C" { __attribute__ ((noinline)) void OutFrame_(void* buf, byte len) { cli(); asm volatile ( "movw r28, %[ptr] \n\t" //загрузка Y "mov r26, %[L] \n\t" //загрузка Y младшего+длинна масива "add r26,r28 \n\t" "ld r24, Y+ \n\t" //инициализация отправки первого байта "ldi r25, 8 \n\t" "rjmp a2_ \n\t" "a1_:" //инициализация отправки не первого байта "sbi %[PP], %[pin] \n\t" // 1 цикл "nop \n\t" "ld r24, Y+ \n\t" //2 цикла "sbrs r24, 7 \n\t" //1 цикл при 0 и 2 цикла при скачке проверка бита и скачек на +2 "cbi %[PP], %[pin] \n\t" //0,375us линию в низкий уровень "lsl r24 \n\t" //1 цикл сдвиг в лево "ldi r25, 7 \n\t" // 1 цикл "nop \n\t" "nop \n\t" "cbi %[PP], %[pin] \n\t" //1 цикл 0,75us линию в низкий уровень "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" /* вывод бита следующего байта*/ "a2_: nop \n\t" "sbi %[PP], %[pin] \n\t" //1 цикл линию в высокий уровень "nop \n\t" "nop \n\t" "sbrs r24, 7 \n\t" //проверка бита и скачек на +2 "cbi %[PP], %[pin] \n\t" //0,375us линию в низкий уровень "lsl r24 \n\t" //1 цикл сдвиг в лево "dec r25 \n\t" //1 цикл "nop \n\t" "nop \n\t" "cbi %[PP], %[pin] \n\t" //1 цикл 0,75us линию в низкий уровень "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "brne a2_ \n\t" // 1 цикл без перехода и 2 с переходом //после этого слишком долго 0.625 вместо 0.45 и 1 вместо 0.85 "cpse r28, r26 \n\t" //1 цикл проверка Y на конец массива "rjmp a1_ \n\t" //2 цикла : : [ptr] "r" (buf) , [L] "r" (len), [PP] "I" (_SFR_IO_ADDR(LED_PORT)), [pin] "I" (LED_PIN_NUM) ); sei(); } } void loop() { sss: memset(arr,0,sizeof(arr)); arr[0]=0x8; arr[4]=0x8; arr[8]=0x8; OutFrame(arr,sizeof(arr)); delay(1000); arr[0]=0x28; arr[4]=0x28; arr[8]=0x28; arr[80]=0xff; OutFrame(arr,sizeof(arr)); delay(1000); goto sss; memset(arr,0,sizeof(arr)); for(byte i=0;i<20;i++) { arr[i]=0x1; OutFrame(arr,30); arr[i]=0; // delay(200); // arr[i]=0xff; // OutFrame(arr,sizeof(arr)); // arr[i]=0; delay(200); } // delay(1000); }Мой экспериментальный код:
#ifndef cbi #define cbi(sfr, bit) (sfr &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif #define ARDUINO_PORT(a) ((a<8)?PORTD:(a<14?PORTB:PORTC)) #define ARDUINO_PIN(a) ((a<8)?PIND:(a<14?PINB:PINC)) #define ARDUINO_DDR(a) ((a<8)?DDRD:(a<14?DDRB:DDRC)) #define ARDUINO_PIN_NUM(a) ((a<8)?a:(a<14?(a-8):(a-14))) #define LED_PIN 13 #define LED_PIN_NUM ARDUINO_PIN_NUM(LED_PIN) #define LED_PORT ARDUINO_PORT(LED_PIN) #define NumberLED 144 byte arr[NumberLED*3]; // the setup routine runs once when you press reset: void setup() { // Serial.begin(2000000); pinMode(LED_PIN, OUTPUT); randomSeed(analogRead(A5)); } extern "C" { __attribute__ ((noinline)) void OutFrame (void* buf, byte len) { cli(); asm volatile ( "movw r28, %[ptr] \n\t" //загрузка Y "mov r26, %[L] \n\t" //загрузка Y младшего+длинна масива "add r26,r28 \n\t" "ld r24, Y+ \n\t" //инициализация отправки первого байта "ldi r25, 8 \n\t" "rjmp a2_ \n\t" "a1_:" //инициализация отправки не первого байта "sbi %[PP], %[pin] \n\t" // 1 цикл "nop \n\t" "ld r24, Y+ \n\t" //2 цикла "sbrs r24, 7 \n\t" //1 цикл при 0 и 2 цикла при скачке проверка бита и скачек на +2 "cbi %[PP], %[pin] \n\t" //0,375us линию в низкий уровень "lsl r24 \n\t" //1 цикл сдвиг в лево "ldi r25, 7 \n\t" // 1 цикл "nop \n\t" "nop \n\t" "cbi %[PP], %[pin] \n\t" //1 цикл 0,75us линию в низкий уровень "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" /* вывод бита следующего байта*/ "a2_: nop \n\t" "sbi %[PP], %[pin] \n\t" //1 цикл линию в высокий уровень "nop \n\t" "nop \n\t" "sbrs r24, 7 \n\t" //проверка бита и скачек на +2 "cbi %[PP], %[pin] \n\t" //0,375us линию в низкий уровень "lsl r24 \n\t" //1 цикл сдвиг в лево "dec r25 \n\t" //1 цикл "nop \n\t" "nop \n\t" "cbi %[PP], %[pin] \n\t" //1 цикл 0,75us линию в низкий уровень "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "brne a2_ \n\t" // 1 цикл без перехода и 2 с переходом //после этого слишком долго 0.625 вместо 0.45 и 1 вместо 0.85 "cpse r28, r26 \n\t" //1 цикл проверка Y на конец массива "rjmp a1_ \n\t" //2 цикла : : [ptr] "r" (buf) , [L] "r" (len), [PP] "I" (_SFR_IO_ADDR(LED_PORT)), [pin] "I" (LED_PIN_NUM) ); sei(); } } void loop(){ memset(arr,0,sizeof(arr)); for (int i = 0; i < NumberLED * 3; i++) { arr[i] = random(255); } OutFrame(arr,sizeof(arr)); delay(1000); }Как энтомолог-любитель хочу поинтересоваться:
1. А чем, собственно.ю тот же fastled не устраивает?
2. Какова конечная цель исследований?
----------------------------------
Что до твоего вопроса, то умнож 144 на 3, сравни с 256 и жди постижения дзена... Если дойдет, к чему это, то постижение близко.
Вы и вправду думаете, что сумеете отладить чужой код на ассемблере, при том, что задаёте вопросы типа: "Как с помощью ардуино соблюдать временные задержки"?
Может лучше и впрямь,
слушать "Валенки"пользоваться библиотекой и не выпендриваться?1. FastLED занимает достаточно много памяти и вычислительной мощности.
2. Узнать как можно ускорить отображение цвета на ленту. А также для общего развития.
----------------------------------
Проблему вроде как понял (
В строке:
стоит переменная типа byte но число (144 * 3) которое должно занять его место больше по этому и не работает (однако пробовал менять на int/word, не работает))
Вопрос тот-же:
Как заставить работать больше, чем 85 светодиодов.
1. FastLED занимает достаточно много памяти и вычислительной мощности.
А вы ее открывали? фастлед занимает ровно столько же памяти, сколько ваш код - 3 байта на кадый диод.
Что касается неведомой "мощности" - то опять же совет - откройте Фастлед и посмотрите, как она работает с лентой. Что-то мне сдается. что код внутри куда более простой и эффективный. чем та поделка. что вы пытаетесь править. И в любом случае, вам полезно будет подсмотреть в Фастледе, как она обходит "проблему байта" - то есть когда число элементов массива становится более 256 :)
Или вы не в курсе, что код внутри библиотек можно открывать и просматривать и даже (о Боже!) - иногда править
Не знаю, поможет или нет, но можно притырить 30 строчек на ассемблере из Adafruit Neopixel. Там счёт идёт в переменной размерности word.
Правда, Ложик может обидеться и начать пузыри пускать...
1. FastLED занимает достаточно много памяти и вычислительной мощности.
2. Узнать как можно ускорить отображение цвета на ленту. А также для общего развития.
Фастлед писали профессионалы. А ты не знаешь, что с байтом делать. И ты так уверен, что сможешь написать нечто, занимающее меньше памяти и отъедающее меньше мощности, чем у них?
Самому не смешно?
Как заставить работать больше, чем 85 светодиодов.
У меня есть кусок кода ровно на 144 светодиода с обновлением 50 раз в секунду. Только зачем он тебе? А вдруг потребуется 143 или 145? Снова "памагити" кричать будешь?
--------------
Запомни, работать с этой лентой очень непросто. Это задача не для "начинающих ардуинщиков". Сто пудов не для них.
Запомни, работать с этой лентой очень непросто. Это задача не для "начинающих ардуинщиков". Сто пудов не для них.
Щас гайвера приплетут как контрпример :)))))
Так гайвер-то ГУРУ!!! Тоже мне, начинающего нашли! :)))
1. FastLED занимает достаточно много памяти и вычислительной мощности.
WS2812b работают на фиксированной скорости передачи. Ускорить нельзя. С вычислительной мощьностью тоже особо ничего поделать нельзя, поскольку в АВР нету хардверных блоков которые можно было бы задействовать для обмена с WS2812b без участия CPU.
Управление адресной светодиодной лентой без использования библиотек
Вот здесь
http://forum.cxem.net/index.php?/blogs/entry/580-ws2812-%D0%B8%D0%BB%D0%...
//Вот здесь
Не. SPI там без толку юзать. Слишком импульсы короткие. Ни прерывания ни "подключить буферы в SPI" непоможит. На длительностях 350-800нсек имеем считаные такты. И они посчитаны что у меня, что в Фастледе. Тут только асм, только хард ;) А SPI только откусит аппаратную часть под то, что и без неё работает с теми же свойствами - блокирующий вызов на все время записи в ленту.
Однако путь к поддержке дохрена светодиодов никак не закрыт. В http://arduino.ru/forum/proekty/pokhvalimsya-khudozhestvennoi-samodeyatelnostyu-na-ws2812?page=1#comment-327386 рабочий пример. Основывается на идее определения цвета каждого светодиода в паузе после записи в предыдущий. Соответственно буфер становится не нужен, нет и ограничения на кол-во светодиодов. В примере определение цвета в
voidGetColor(word n, word t)делается. Надо только помнить о ограничении времени её выполнения. В даташите пишут "RES low voltage time Above 50µs" это время превышать нельзя. На самом деле даже хуже, моя лента не дает делать паузу более 10мксек, но я и в 2мксек успеваю делать GetColor. Получается чтоб поддерживать 100500 светодиодов надо: 1. Немного перевернуть мозги, чтоб уметь кодить эффекты ленты как функцию от номера светодиода и времени 2. Уметь писать быстрый код, который до 10мксек (а может и быстрей) реализовывал бы п.1ПС. Хочу свою поделку на WS2812 из той темы переписать на новый подход, но времени нет руки не доходят. А сейчас - так вобще. Каникулы, бля! Отогнать малого от компа - нереально. Да и куча других забот. Вобщем дерзайте сами! Пока ;)