Ограничения операнда встроенной сборки ATTiny414 для параметра вывода ввода-вывода

Я пытаюсь использовать библиотеку 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пакета.

возможно, мне следует использовать VPORTA.OUTрегистр вместо этого? Это начинается 0x0так необычно, PORTA.OUTчто должно вписываться в i...

Ответы (1)

В ATTiny 1-й серии регистры GPIO отображаются за пределами пространства регистров порта ввода-вывода, поэтому к ним нельзя получить доступ с помощью outили in. Вам нужно будет либо использовать регистры VPORT, либо загрузить адрес порта ввода-вывода в регистр и использовать инструкцию stдля записи данных. Если вы решите использовать обычную инструкцию сохранения, это может изменить время цикла, поэтому вам, возможно, придется настроить количество секунд nop.

Отлично, я тоже пришел к такому же выводу после того, как наконец понял, как читать общую схему памяти из таблицы данных. Будет ли преимущество в использовании инструкций по битовой адресации для установки вывода?
Я не уверен насчет tiny414, но общая дуга AVR определяется stкак занимающая 2 цикла, тогда как outзанимает 1 цикл.
Думаю будет SBIи так CBI. Поскольку все они являются инструкциями с одним циклом, я полагаю, что нет никакой разницы (за исключением того, что если бы было активно периферийное устройство, мы бы не / не могли перезаписать их значения в регистре порта, но я не уверен, действительно ли это так) возможная проблема). Я проверю, работает ли это так, как ожидалось, когда вернусь домой и приму ответ :)
Хорошо, я еще не смог заставить свой код работать, но это, вероятно, не связано с вопросом, поскольку исходный код с ограничением "I"теперь работает с VPORT *.