Mitt svar på WS2811 med en AVR sak (3 / 5 steg)
Steg 3: Bit Banging och spara några fler klockcykler
800khz på en 16Mhz AVR är 20 klockcykler.
20 klockcykler på en AVR är mycket. Vi talar inte om PIC12 / 16C här med 4 fästingar per instruktion och enda riktiga register. AVR mycket per klocka cykel. Om det inte fanns kravet att blanda RGB ordning gör AVR denna följetong jobb utan att bryta en svett.
I själva verket förändras det enda AVR inte skiner på bitar i I/O register. Detta tar två klockcykler som visas i Detaljer för SBI instruktionen nedan. Processorn har att läsa registret, ändra den och skriva det tillbaka. Det är en av de få icke-förgrening instruktionerna i AVR ta två klockor. (Obs: AVR XMega har fastställt denna fråga och nu är endast 1 klocka)
Använda denna instruktion i tid kritiska linjer är inte mycket kul som alanerna kod visade. Han var tvungen att hoppa och hoppa över platsen för att utjämna den sökväg längden.
sbrc r19, 7. testa Hej lite klart
rjmp 3f; sant, skippa pin Hej -> lo
CBI % [port], [pin]; falsk, pin Hej -> lo
3: sbrc r19, 7. utjämna fördröjning av båda kodsökvägar
rjmp 4f
4: nop; puls timing fördröjningen
Så om de faktiska CBI och SBI instruktionerna kommer att ta 2 klockcykler ändå och då måste man slösa 2 klockcykler för att utjämna den sökväg längden, varför inte bara Läs ändra skriva själv. Detta kommer att ta 3 cykler totalt.
I R16, PortX; Läs det aktuella läget i registret
ORI R16, PinX; Ange Xth bit hög
UT PortX, R16; Skriv det nya värdet till registret
Nästa sak du kan göra för att spara tid är flytta allt utanför loopen du kan. Eftersom den här koden använder 100% av CPU-tid, det finns ingen risk något annat kommer att ändra PortX. Eftersom ingen annan kod körs kan vi också använda så många CPU register som vi gillar.
Så gör detta IN-ning och AND/OR-ning sätt utanför loopen.
I PinLo, PortX; Gör en kopia av byten i PortX
ANDI PinLo, 0xFE; Ändra det så att det värde att skriva att göra pin lo
I PinHi, PortX; Gör en kopia av byten i PortX
ORI PinHi, 0x01; Ändra det så att det värde att skriva att göra pin Hej
Slinga:
bla
bla
ut PortX, PinLo; Ställa in utgångsstiftet låg
bla
bla
rjmp Loop:
Detta har nu gjort hela lite togglande, seriell SKIFT, lite räkna och looping ta bara 9 klockor. Detta lämnar 11 klockor gratis för inläsning av data och blanda.
Igen skulle detta vara massor av tid om inte för det i ordning RGB. På grund av den i ordning RGB sak kan vi inte bara behandla varje byte läsa som nästa gång går ut. Vi måste göra ett beslut om var du vill spara den nya Läs byten till en buffert och var från en buffert för att få den nästa byten att skicka.
Det är där instruktionen IJMP kommer till undsättning. Sin sida från AVR instruktionsuppsättning visas ovanför. Vi använder det som ett fall/switch uttalande i en software-tillståndsdator. I varje stat kan vi ställa in vad nästa tillstånd bör utan att behöva göra några utvärderingar.
Vi kan göra detta eftersom vi alltid vet vilken färg den nästa byten kommer att vara
Om vi för närvarande bearbetar den röda byten blir den nästa byten grön
Om vi för närvarande bearbetar den gröna byten blir den nästa byten blå
Om vi för närvarande bearbetar den blå byten blir den nästa byten röd
t.ex. I det röda tillståndet kan vi helt enkelt säga
STATE = GRÖN
Vi behöver inte säga
om (något) sedan staten = grön annan stat = blå
Detta sparar några klockor inte behöva utvärdera något.
Hela koden visas som en bild här. Igen skicka mig ett PM om du vill att jag ska maila det till dig.
Kommentarerna i koden är förhoppningsvis tillräckligt även låta någon obekant med AVR-ASM förstår.