Я пытаюсь использовать библиотеку light_ws2812 для управления светодиодами WS2812 от ATTiny414. Ядром этой библиотеки является фрагмент встроенного ассемблера, который разбивает последовательную строку. вот это с вырезанными таймингами:
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;
}
Очевидная разница между определениями «обычного AVR» и ATTiny*14 серии C заключается в том, что регистры ввода-вывода называются не DDRx и PORTx, а PORTx.DIR и PORTx. Я это уже исправил в light_ws2812
шапке и вроде работает нормально.
Однако после этого я получаю сообщение об ошибке с операндом сборки 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
в качестве ограничения вместо I
, что меняет ошибку на
/tmp/ccBR4JKE.s:48: Error: operand out of range: 1028
Глядя на таблицу данных , это значение имеет смысл, PORTA
начинается с 0x400
(1024), а PORTx.OUT
регистр имеет дополнительное смещение в 4 байта, помещающееся PORTA.OUT
в 0x404 = 1028
.
с 16-битным ограничением регистра, например, x
или w
он компилируется, но затем я получаю ошибку компоновщика:
avr-ld: lib/light_ws2812.o: in function `loop32':
light_ws2812.c:(.text+0x38): undefined reference to `r30'
Я компилирую это, используя avr-gcc
и avr-ld
, с током avr-libc
, в который я вручную добавил соответствующие файлы из Atmel ATtiny Series Device Support
пакета.
В ATTiny 1-й серии регистры GPIO отображаются за пределами пространства регистров порта ввода-вывода, поэтому к ним нельзя получить доступ с помощью out
или in
. Вам нужно будет либо использовать регистры VPORT, либо загрузить адрес порта ввода-вывода в регистр и использовать инструкцию st
для записи данных. Если вы решите использовать обычную инструкцию сохранения, это может изменить время цикла, поэтому вам, возможно, придется настроить количество секунд nop
.
st
как занимающая 2 цикла, тогда как out
занимает 1 цикл.SBI
и так CBI
. Поскольку все они являются инструкциями с одним циклом, я полагаю, что нет никакой разницы (за исключением того, что если бы было активно периферийное устройство, мы бы не / не могли перезаписать их значения в регистре порта, но я не уверен, действительно ли это так) возможная проблема). Я проверю, работает ли это так, как ожидалось, когда вернусь домой и приму ответ :)"I"
теперь работает с VPORT *.
с-ол
VPORTA.OUT
регистр вместо этого? Это начинается0x0
так необычно,PORTA.OUT
что должно вписываться вi
...