I'm trying to use the light_ws2812 library to drive WS2812 LEDs from an ATTiny414.
The core of that library is an inline assembly snippet that bitbangs the serial line. here it is with the timing-nops stripped out:
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;
}
An obvious difference between the 'regular AVR' and the ATTiny*14 series
C definitions is that the IO registers aren't called DDRx and PORTx but PORTx.DIR and PORTx. I already fixed that in the light_ws2812
header and it seems to work fine.
After this I am however getting an error with the assembly operand 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
I also tried using a lowercase i
as the constraint instead of the I
, which changes the error to
/tmp/ccBR4JKE.s:48: Error: operand out of range: 1028
Looking at the datasheet this value makes sense, PORTA
starts at 0x400
(1024) and the PORTx.OUT
register has an additional offset of 4 bytes, placing PORTA.OUT
at 0x404 = 1028
.
with a 16-bit register constraint like x
or w
it compiles but then I get a linker error:
avr-ld: lib/light_ws2812.o: in function `loop32':
light_ws2812.c:(.text+0x38): undefined reference to `r30'
I am compiling this using avr-gcc
and avr-ld
, with a current avr-libc
that I manually added the relevant files from the Atmel ATtiny Series Device Support
package to.
Best Answer
The ATTiny 1-series has the GPIO registers mapped outside of the io port register space, so they cannot be accessed using
out
orin
. You will either need to use the VPORT registers, or load the address of the io port into a register and use anst
instruction to write the data. If you decide to use a regular store instruction, it may change the timing of the loop so you may have to adjust the number ofnop
s.