Source file: /~heha/Mikrocontroller/LEDs/800.zip/800.cpp

#include <avr/io.h>
#include <util/delay.h>

#define NOINIT __attribute__((section(".noinit")))

typedef unsigned char byte;
struct GRB{
 byte g,r,b;
};

// Repeat ist hier „vertikal“, d.h. das Muster wiederholt sich
// nach LEN WS2812-LEDs.
// Für andersherum = nach LEN gleicher Farbe kommt LEN anderer Farbe
// muss die Update-Funktion anders geschrieben werden.

// Ein Armutszeugnis warum das bei Arduino nicht genau so
// (mit Templates und ohne malloc()) gelöst wird. Sind halt Deppen.
template<unsigned PORT,byte BIT,unsigned LEN,unsigned REP> class WS2812 {
public:
 GRB data[LEN];
// data[] auf WS2812-kompatible LED-Kette REP-fach ausgeben
// Interrupts müssen gesperrt sein!
 void update() const{
  byte*workp;
  unsigned workl;
  asm volatile(
// Takte-Soll: T0H = 6,4 T1H = 12,8, T0L = 13,6, T1L = 7,2, Toleranz = ±2,4
// Bitslot = 20, Toleranz = ±9,6
// Takte-Ist: T0H = 6, T1H = 12, T0L = 14, T1L = 8, Summe (1 Bit) = 20
"1:	movw	%0,%4		\n"	//  0	LL
"	movw	%1,%5		\n"	//  1	LL
"2:	ld	r0,%a0+		\n"	//  2	LL
					//  3	LL
"3:	sbi	%2,%3		\n"	//  4	LL
					//  5	LL
"	lsl	r0		\n"	//  6	HH
"	inc	r1		\n"	//  7	HH
"	nop			\n"	//  8	HH
"	brcs	4f		\n"	//  9	HH
"	cbi	%2,%3		\n"	// 10	H-
					// 11	H-
"4:"					//	    10 -H
"	brcc	.		\n"	// 12	L-  11 -H
					//          12 -H
"	sbrs	r1,3		\n"	// 13	LH
"	 rjmp	8f		\n"	// 14	LH
"	clr	r1		\n"	// 	15 LH
"	cbi	%2,%3		\n"	//	16 LH
					//	17 LH
"	subi	%A1,1		\n"	// 	18 LL
"	sbci	%B1,0		\n"	// 	19 LL
"	brne	2b		\n"	// 	20 LL
					//	21 LL = kein Extra-Takt fürs nächste Byte
"	subi	%A6,1		\n"	//	22 LL
"	sbci	%B6,0		\n"	//	23 LL
"	brne	1b		\n"	//	24 LL
					//	25 LL = 6 Takte mehr bei Wiederholung
"	rjmp	9f		\n"
// Für das Bit mittendrin ist mehr Zeit, deshalb „nach unten ausgelagert“.
"8:"					// 15	LH
"	cbi	%2,%3		\n"	// 16	LH
					// 17	LH
"	rjmp	.		\n"	// 18	LL
					// 19	LL
"	rjmp	.		\n"	// 20	LL
					// 21	LL
"	rjmp	3b		\n"	// 22	LL
					// 23	LL
"9:"
:"=&e"(workp),"=&r"(workl):
 "I"(PORT),"I"(BIT),"r"(data),"r"(sizeof data),"r"(REP));
 }
};

static WS2812<_SFR_IO_ADDR(PORTD),7,1,800> ws2812 NOINIT;
// bedeutet: 3 Byte Puffer für 800 RGB-LEDs.
// Für unifarbene Lichtbänder sowieso die richtige Lösung!

int main() {
// Kein originaler ATmega328p sondern ein von Arduino verhunzter.
// Vorteil: Taktteiler ist bereits 1
// CLKPR=0x80;
// CLKPR=0;
 DDRD|=0x80;
 GRB&pixel=ws2812.data[0];
// Bei voller Lichtstärke kommt am Ende des 5-m-Bands nur noch knapp
// 2 V Speisespannung an, und es kommt zu einer Rotverschiebung.
// Deshalb hier extra geringe Lichtstärken zum Test der „Schnecke“.
 pixel={8,4,2};
 for(;;) {
  _delay_ms(300);
  ws2812.update();
  pixel={pixel.r,pixel.b,pixel.g};	// Farbanteile rotieren
 }
}
Detected encoding: UTF-80