Ich versuche, die light_ws2812- Bibliothek zu verwenden, um WS2812-LEDs von einem ATTiny414 anzusteuern. Der Kern dieser Bibliothek ist ein Inline-Assembly-Snippet, das die serielle Leitung bitbangt. Hier ist es mit den ausgezogenen Timing-Nops:
void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
{
uint8_t curbyte,ctr,masklo;
uint8_t sreg_prev;
ws2812_DDRREG |= maskhi; // Enable output
masklo =~maskhi&ws2812_PORTREG;
maskhi |= ws2812_PORTREG;
sreg_prev=SREG;
cli();
while (datlen--) {
curbyte=*data++;
asm volatile(
" ldi %0,8 \n\t"
"loop%=: \n\t"
" out %2,%3 \n\t" // '1' [01] '0' [01] - re
" sbrs %1,7 \n\t" // '1' [03] '0' [02]
" out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
" lsl %1 \n\t" // '1' [04] '0' [04]
" out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
" dec %0 \n\t" // '1' [+2] '0' [+2]
" brne loop%=\n\t" // '1' [+3] '0' [+4]
: "=&d" (ctr)
: "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
);
}
SREG=sreg_prev;
}
Ein offensichtlicher Unterschied zwischen den 'normalen AVR'- und den C-Definitionen der ATTiny*14-Serie besteht darin, dass die IO-Register nicht DDRx und PORTx, sondern PORTx.DIR und PORTx heißen. Ich habe das bereits in der light_ws2812
Kopfzeile korrigiert und es scheint gut zu funktionieren.
Danach erhalte ich jedoch einen Fehler mit dem Assembly-Operanden 2 ( "I" (_SFR_IO_ADDR(ws2812_PORTREG))
):
lib/light_ws2812.c: In function 'ws2812_sendarray_mask':
lib/light_ws2812.c:119:5: warning: asm operand 2 probably doesn't match constraints
asm volatile(
^~~
lib/light_ws2812.c:119:5: error: impossible constraint in 'asm'
make: *** [Makefile:28: lib/light_ws2812.o] Error 1
Ich habe auch versucht, i
anstelle von , einen Kleinbuchstaben als Einschränkung zu verwenden I
, wodurch sich der Fehler in ändert
/tmp/ccBR4JKE.s:48: Error: operand out of range: 1028
Wenn man sich das Datenblatt ansieht , ist dieser Wert sinnvoll, PORTA
beginnt bei 0x400
(1024) und das PORTx.OUT
Register hat einen zusätzlichen Offset von 4 Bytes und platziert PORTA.OUT
bei 0x404 = 1028
.
mit einer 16-Bit-Registerbeschränkung wie x
oder w
es wird kompiliert, aber dann erhalte ich einen Linker-Fehler:
avr-ld: lib/light_ws2812.o: in function `loop32':
light_ws2812.c:(.text+0x38): undefined reference to `r30'
Ich kompiliere dies mit avr-gcc
und avr-ld
mit einem Strom avr-libc
, dem ich die relevanten Dateien aus dem Atmel ATtiny Series Device Support
Paket manuell hinzugefügt habe.
Bei der ATTiny 1-Serie sind die GPIO-Register außerhalb des io-Port-Registerraums abgebildet, sodass auf sie nicht mit out
oder zugegriffen werden kann in
. Sie müssen entweder die VPORT-Register verwenden oder die Adresse des io-Ports in ein Register laden und eine st
Anweisung verwenden, um die Daten zu schreiben. Wenn Sie sich für die Verwendung einer regulären Speicheranweisung entscheiden, kann dies das Timing der Schleife ändern, sodass Sie möglicherweise die Anzahl der nop
s anpassen müssen.
st
2 Zyklen, während out
1 Zyklus benötigt wird.SBI
und CBI
. Da es sich bei allen um Einzelzyklusbefehle handelt, gibt es vermutlich keinen Unterschied (außer dass wir bei einem aktiven Peripheriegerät ihre Werte im Portregister nicht überschreiben würden / könnten, aber ich bin mir nicht sicher, ob dies tatsächlich der Fall ist ein mögliches Problem). Ich werde prüfen, ob dies wie erwartet funktioniert, wenn ich nach Hause komme und die Antwort akzeptieren :)"I"
Einschränkung jetzt mit VPORT * funktioniert.
Sol
VPORTA.OUT
stattdessen das Register verwenden? Es fängt0x0
so an, dassPORTA.OUT
es nicht hineinpassen solltei
...