Управление адресной светодиодной лентой без использования библиотек

начинающий ардуинщик
Offline
Зарегистрирован: 04.06.2019
Здравствуйте. 
(Заранее извиняюсь за  возможно неправильный выбор раздела)
 
Как понятно из названия темы мне нужно управлять Адресной Светодиодной Лентой без использования библиотек.
 
В даташите на ленту изображён побитовый способ передачи цвета (а именно временные задержки и порядок передачи).
 
Вопрос: 
Как с помощью ардуино соблюдать временные задержки при передаче данных о цвете.
начинающий ардуинщик
Offline
Зарегистрирован: 04.06.2019

Примечание:

АСЛ (сокращение от Адресная Светодиодная Лента) имеет чипы  WS2812b.

Даташит на них.

sadman41
Offline
Зарегистрирован: 19.10.2016

Какой длительности задержки?

svm
Онлайн
Зарегистрирован: 06.11.2016

начинающий ардуинщик пишет:

Здравствуйте. 
(Заранее извиняюсь за  возможно неправильный выбор раздела)
 
Как понятно из названия темы мне нужно управлять Адресной Светодиодной Лентой без использования библиотек.
 
В даташите на ленту изображён побитовый способ передачи цвета (а именно временные задержки и порядок передачи).
 
Вопрос: 
Как с помощью ардуино соблюдать временные задержки при передаче данных о цвете.

Почитайте здесь: http://arduino.ru/forum/proekty/pokhvalimsya-khudozhestvennoi-samodeyatelnostyu-na-ws2812

работает неплохо, и без библиотек. Правда немного критично к версии IDE. Под 1.6.5 работает точно под 1.6.9 - нет. 

начинающий ардуинщик
Offline
Зарегистрирован: 04.06.2019


Спасибо за информацию.
 
Однако после некоторых экспериментов выяснилось, что не работают светодиоды следующие за 80 (NumberLED увеличил до 144).
Помогите пожалуйста разобраться с это проблемой. 

Исходный код:

 

#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);
}

 

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Как энтомолог-любитель хочу поинтересоваться:

1. А чем, собственно.ю тот же fastled не устраивает?

2. Какова конечная цель исследований?

----------------------------------

Что до твоего вопроса, то умнож 144 на 3, сравни с 256 и жди постижения дзена... Если дойдет, к чему это, то постижение близко.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы и вправду думаете, что сумеете отладить чужой код на ассемблере, при том, что задаёте вопросы типа: "Как с помощью ардуино соблюдать временные задержки"?

Может лучше и впрямь, слушать "Валенки" пользоваться библиотекой и не выпендриваться?

начинающий ардуинщик
Offline
Зарегистрирован: 04.06.2019

1.  FastLED занимает достаточно много памяти и вычислительной мощности.

2.  Узнать как можно ускорить отображение цвета на ленту. А также для общего развития.

----------------------------------

Проблему вроде как понял (

В строке:

...
__attribute__ ((noinline)) void OutFrame (void* buf, byte len)
...

стоит переменная типа byte но число (144 * 3)  которое должно занять его место больше по этому и не работает (однако пробовал менять на int/word, не работает))

Вопрос тот-же:

Как заставить работать больше, чем 85 светодиодов.

b707
Offline
Зарегистрирован: 26.05.2017

начинающий ардуинщик пишет:

1.  FastLED занимает достаточно много памяти и вычислительной мощности.

А вы ее открывали? фастлед занимает ровно столько же памяти, сколько ваш код  - 3 байта на кадый диод.

Что касается неведомой "мощности" - то опять же совет - откройте Фастлед и посмотрите, как она работает с лентой. Что-то мне сдается. что код внутри куда более простой и эффективный. чем та поделка. что вы пытаетесь править. И в любом случае, вам полезно будет подсмотреть в Фастледе, как она обходит "проблему байта" - то есть когда число элементов массива становится более 256 :)

Или вы не в курсе, что код внутри библиотек можно открывать и просматривать и даже (о Боже!) - иногда править

sadman41
Offline
Зарегистрирован: 19.10.2016

Не знаю, поможет или нет, но можно притырить 30 строчек на ассемблере из Adafruit Neopixel. Там счёт идёт в переменной размерности word. 

Правда, Ложик может обидеться и начать пузыри пускать...

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

начинающий ардуинщик пишет:

1.  FastLED занимает достаточно много памяти и вычислительной мощности.

2.  Узнать как можно ускорить отображение цвета на ленту. А также для общего развития.

Фастлед писали профессионалы. А ты не знаешь, что с байтом делать. И ты так уверен, что сможешь написать нечто, занимающее меньше памяти и отъедающее меньше мощности, чем у них?

Самому не смешно?

начинающий ардуинщик пишет:

Как заставить работать больше, чем 85 светодиодов.

У меня есть кусок кода ровно на 144 светодиода с обновлением 50 раз в секунду. Только зачем он тебе? А вдруг потребуется 143 или 145? Снова "памагити" кричать будешь?

--------------

Запомни, работать с этой лентой очень непросто. Это задача не для "начинающих ардуинщиков". Сто пудов не для них.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Ворота пишет:

Запомни, работать с этой лентой очень непросто. Это задача не для "начинающих ардуинщиков". Сто пудов не для них.

Щас гайвера приплетут как контрпример :)))))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так гайвер-то ГУРУ!!! Тоже мне, начинающего нашли! :)))

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

начинающий ардуинщик пишет:

1.  FastLED занимает достаточно много памяти и вычислительной мощности.

WS2812b работают на фиксированной скорости передачи. Ускорить нельзя. С вычислительной мощьностью тоже особо ничего поделать нельзя, поскольку в АВР нету хардверных блоков которые можно было бы задействовать для обмена с WS2812b без участия CPU. 

parovoZZ
Offline
Зарегистрирован: 15.02.2016

начинающий ардуинщик пишет:

Управление адресной светодиодной лентой без использования библиотек

Вот здесь

http://forum.cxem.net/index.php?/blogs/entry/580-ws2812-%D0%B8%D0%BB%D0%...

Logik
Offline
Зарегистрирован: 05.08.2014

//Вот здесь

Не. SPI там без толку юзать. Слишком импульсы короткие. Ни прерывания ни "подключить буферы в SPI" непоможит. На длительностях 350-800нсек имеем считаные такты. И они посчитаны что у меня, что в Фастледе. Тут только асм, только хард ;) А SPI только откусит аппаратную часть под то, что и без неё работает с теми же свойствами - блокирующий вызов на все время записи в ленту.

Однако путь к поддержке дохрена светодиодов никак не закрыт. В  http://arduino.ru/forum/proekty/pokhvalimsya-khudozhestvennoi-samodeyatelnostyu-na-ws2812?page=1#comment-327386 рабочий пример. Основывается на идее определения цвета каждого светодиода в паузе после записи в предыдущий. Соответственно буфер становится не нужен, нет и ограничения на кол-во светодиодов. В примере определение цвета в void GetColor(word n, word t) делается. Надо только помнить о ограничении времени её выполнения. В даташите пишут "RES low voltage time Above 50µs" это время превышать нельзя. На самом деле даже хуже, моя лента не дает делать паузу более 10мксек, но я и в 2мксек успеваю делать GetColor. Получается чтоб поддерживать 100500 светодиодов надо: 1. Немного перевернуть мозги, чтоб уметь кодить эффекты ленты как функцию от номера светодиода и времени 2. Уметь писать быстрый код, который до 10мксек (а может и быстрей) реализовывал бы п.1

ПС. Хочу свою поделку на WS2812 из той темы переписать на новый подход, но времени нет руки не доходят. А сейчас - так вобще. Каникулы, бля! Отогнать малого от компа - нереально. Да и куча других забот. Вобщем дерзайте сами! Пока ;)