Сделал небольшую процедуру для параллельной отрисовки 8-ми линий адресных светодиодов WS2812B. Отрисовка именно параллельная, а не последовательная тк за один фрейм отправляется один бит на каждую из линий. Тк весь порт D занят(D0..D7), UART будет не доступен.
Не знаю сильно ли кому это будет нужно, но вдруг...
Описание процедур:
По цифрам:
Не знаю сильно ли кому это будет нужно, но вдруг...
C++:
#define LEDS_NUM 5 //светодиодов на каждой линии
uint8_t ledsBuf[LEDS_NUM * 24];
const uint8_t maskBit[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; //маска анализа бита
const uint8_t setBit[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,}; //маска установки бита
const uint8_t clrBit[] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}; //маска очистки бита
//---------------------------------Передача массива данных на шины-----------------------------
void ledWrite(uint8_t* data, uint16_t size) {
__asm__ __volatile__ (
"LD r21, X+ \n\t" //загрузили байт из масива
"CLR r20 \n\t" //очистка всех разрядов регистра
"OUT %[PORT], r20 \n\t" //LOW на выход пинов
"LDI r19, 200 \n\t" //счетчик сигнала reset(50мкс)
//-----------------------------------------------------------------------------------------
"_LOOP_DELAY_%=: \n\t" //цикл задержки
"NOP \n\t" //пропускаем цикл
"DEC r19 \n\t" //декремент счетчика циклов
"BRNE _LOOP_DELAY_%= \n\t" //переход в начало цикла задержки
//-----------------------------------------------------------------------------------------
"CLI \n\t" //запретили прерывания
"_BYTE_START_%=: \n\t" //начало цикла отправки байта
//-----------------------------------------------------------------------------------------
"SER r20 \n\t" //установка всех разрядов регистра
"OUT %[PORT], r20 \n\t" //HIGH на выход пинов
"NOP \n\t" //пропускаем цикл
"NOP \n\t" //пропускаем цикл
"AND r20, r21 \n\t" //очищаем необходимые биты
"OUT %[PORT], r20 \n\t" //LOW на выход установленных пинов
"NOP \n\t" //пропускаем цикл
"LD r21, X+ \n\t" //загрузили байт из масива
"CLR r20 \n\t" //очистка всех разрядов регистра
"SBIW %[COUNT], 1 \n\t" //отнимаем от счетчика байт
"OUT %[PORT], r20 \n\t" //LOW на выход пинов
//-----------------------------------------------------------------------------------------
"BRNE _BYTE_START_%= \n\t" //переход к загрузке нового байта
"SEI \n\t" //разрешили прерывания
:
:"x"(data),
[COUNT]"w"(size),
[PORT]"I"(_SFR_IO_ADDR(PORTD))
:"r19", "r20", "r21"
);
}
//---------------------------------Инициализация шины-------------------------------------
void ledInit(void) {
DDRD = 0xFF; //устанавливаем D0-D7 как выходы
PORTD = 0xFF; //HIGH на пины D0-D7
for (uint16_t i = 0; i < sizeof(ledsBuf); i++) ledsBuf[i] = 0; //очищаем массив данных
}
//-----------------------------Отрисовка всех светодиодов----------------------------------
void ledShow(void) {
ledWrite(ledsBuf, sizeof(ledsBuf)); //отрисовываем массив
}
//-----------------------------Установка цвета светодиода----------------------------------
void setGRB(uint8_t line, uint16_t led, uint8_t G, uint8_t R, uint8_t B) {
uint16_t temp = led * 24; //находим начало буфера
for (uint8_t i = 0; i < 8; i++) { //записываем новый цвет светодиода
if (G & maskBit[i]) ledsBuf[temp + i] |= setBit[line]; //устанавливаем бит зелёного цвета
else ledsBuf[temp + i] &= clrBit[line]; //очищаем бит зелёного цвета
if (R & maskBit[i]) ledsBuf[temp + i + 8] |= setBit[line]; //устанавливаем бит красного цвета
else ledsBuf[temp + i + 8] &= clrBit[line]; //очищаем бит красного цвета
if (B & maskBit[i]) ledsBuf[temp + i + 16] |= setBit[line]; //устанавливаем бит синего цвета
else ledsBuf[temp + i + 16] &= clrBit[line]; //очищаем бит синего цвета
}
}
- ledInit() - инициализирует порт D, очищает массив светодиодов.
- ledShow() - отправляет массив данных на линии.
- setGRB(линия(0..7), светодиод(0..LEDS_NUM - 1), зеленый(0..255), красный(0..255), синий(0..255)) - устанавливает цвет для конкретного светодиода.
По цифрам:
- Отрисовать 512 светодиодов можно за 2мс(примерно 500к/с), но узким горлышком выступает упаковка цвета в массив(если его ускорить, то профиту будет в разы больше).
- Запись одного светодиода занимает 23мкс. Те, если мы будем заполнять светодиоды последовательно по одному, то это будет занимать также 2мс(против 15,4мс), если же все светодиоды разом то 13,7мс(против17,4).
- Но даже при одинаковом времени отрисовки, с заблокированными прерываниями мы будем находиться 2мс(против 15,4).
Изменено: