Перейти к содержанию
    

Allwinner T113-s3 уделал HiFi4 DSP. Смеяться или плакать?

Удалось заставить DSP видеть прерывания от GPIOC. А также произвести настройку дочернего контроллера прерываний INTC.

Номер источника прерываний от GPIOC - 42:

#define GPIOC_INTC_SOURCE 42

Общее прерывание INTC - номер 20, как об этом упомянули выше.  Инициализация INTC для GPIOC:

#define INTC_IRQ	20

extern void *INTC_Vectors; //объявлена в ассемблере

void Init_INTC(u32 intsource)
{
 pintc_regs->base_addr=(u32)&INTC_Vectors; //установаить базоввый адрес таблицы векторов

 //замаскировать все источники прерываний
 pintc_regs->mask =~0;
 pintc_regs->mask1=~0;
 pintc_regs->mask2=~0;

 //запретить все источники прерываний
 pintc_regs->enable =0;
 pintc_regs->enable1=0;
 pintc_regs->enable2=0;

 //демаскировать нужный источник прерывания
 if(intsource<32)pintc_regs->mask=~(1U<<intsource);
 else
 if(intsource<64)pintc_regs->mask1=~(1U<<(intsource-32));
 else            pintc_regs->mask2=~(1U<<(intsource-64));

 //разрешить нужный источник прерывания
 if(intsource<32)pintc_regs->enable=(1U<<intsource);
 else
 if(intsource<64)pintc_regs->enable1=(1U<<(intsource-32));
 else            pintc_regs->enable2=(1U<<(intsource-64));
   
 Int_Enable(1<<INTC_IRQ); //enable INTC interrupt
}
   
void Int_Enable(u32 intenable)
{
 __asm__ __volatile__ ("wsr.intenable %0" :: "r"(intenable));
}
   
int main(void)
{
 printf("\nHiFi4 DSP...\n");

 Init_INTC(GPIOC_INTC_SOURCE);

 while(1)
 {
  UART_putc('_');
  DelayMS(20);
 }
   
//...

 

INTC_Vectors - это таблица векторов прерываний - источников от T113-s3:

	.align 4 //здесь выравнивание обязательно!

INTC_Vectors:
	.word		INTC_Dummie //+0 *4
	.word		INTC_Dummie
	.word		INTC_Dummie

//...

	.word		INTC_Dummie
	.word		GPIOC_Handler //+42 *4
	.word		INTC_Dummie

//...

INTC_Dummie:
	movi		a3,'I'
	movi		a2,UART_THR
	memw
	s32i.n		a3,a2,0
	j		.

 

INTC_Dummie - заглушка на остальные источники прерываний.   GPIOC_Handler - обработчик для GPIO C :

void GPIOC_Handler(void)
{
 printf("GPIOC Interrupt %c\n",rand());
 PC_EINT_STATUS=PC_EINT_STATUS; //подтверждение прерывания GPIOC
}

 

Общее прерывание INTC висит на смещении .org 0x21C в таблице векторов прерывний DSP - прерывание IntLevel1/User.  Вызов обработчика прерывания:

//...

	movi		a3,PS_UM|PS_WOE_ABI|PS_INTLEVEL(1)
	wsr.ps		a3
	rsync

	call8		INTC_Handler

	movi		a3,PS_UM|PS_WOE_ABI|PS_INTLEVEL(0)
	wsr.ps		a3
      
//...
      
//или так (быстрее, вместо INTC_Handler):

#define INTC_VECTOR 0x01700800

//...
      
	movi		a3,INTC_VECTOR
	memw
	l32i		a3,a3,0
	l32i		a3,a3,0
	callx8		a3

//...

 

INTC_Handler - обёртка вызова по содержимому указателя на регистр:

void INTC_Handler(void)
{
((void (*)(void))(*(u32*)pintc_regs->vector))();
}

 

Тоесть работает это так:  вначале происходит прерывание Level1/User от INTC (разрешение - бит 20 регистра intenable) - INTC_Handler, затем считывается содержимое регистра pintc_regs->vector, там должен быть адрес обработчика прерывания источника: базовый адрес таблицы векторов источников прерваний + актуальное смещение для источника (для GPIOC+ (42*4) - в байтах).  Далее вызывается функция по этому адресу - GPIOC_Handler.

На самом деле таблицу векторов источников прерываний делать необязательно - можно просто написать одну функцию (вместо INTC_Handler), а выделить источник прерывания можно через регистры:

  pintc_regs->pending;
  pintc_regs->pending1;
  pintc_regs->pending2;

Но с таблицей векторов источников прерываний выглядит более системнее.

 

P.S.   Остальные регистры - их назначение понять не удалось:

 pintc_regs->resp =0; //все должны быть нулями, иначе не работает
 pintc_regs->resp1=0;
 pintc_regs->resp2=0;

 pintc_regs->priority0=; //не влияет
 pintc_regs->priority1=;
 pintc_regs->priority2=;
 pintc_regs->priority3=;
 pintc_regs->priority4=;
 pintc_regs->priority5=;

 pintc_regs->group_config0=; //не влияет
 pintc_regs->group_config1=;
 pintc_regs->group_config2=;
 pintc_regs->group_config3=;

 

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

resp... responce?

Из мануала:
If the corresponding bit is set, the interrupt with the lower or the same priority level is masked
Разрешение вложенности при том же приореитете как-бы.

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, GenaSPB said:

Из мануала:
If the corresponding bit is set, the interrupt with the lower or the same priority level is masked
Разрешение вложенности при том же приореитете как-бы.

Любое ненулевое значение в этих регистрах приводит к  тому, что прерывание переставало работать.   Оставил их как есть (при включении питания они =0).

 

В идеале конечно бы хотелось сдвинуть вектор INTC с Level1/User на свободные Level 2,3,4.   Но это можно только в XEA3.   В XEA2 вроде намертво прибито.

Итого в Level1/User уже  три случая работают:

	.org		0x21C		//User

User:
	wsr.excsave1	a0		//save a0

	rsr.exccause	a0
	beqi		a0,EXCCAUSE_LEVEL1,_xt_lowint1         //INTC
	beqi		a0,EXCCAUSE_ALLOCA,_xt_alloca_exc      //Alloca MOVSP exception
	beqi		a0,EXCCAUSE_SYSCALL,_xt_syscall_exc    //Syscall setjmp exception
Dummie:
	j		Dummie

 

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В общем этот китаец взял описание регистров R_INTC из Tina Linux T113-s3:

Tina-t113\lichee\rtos-dsp\rtos-hal\hal\source\intc\platform\intc-sun8iw20.h

Tina-t113\lichee\rtos-dsp\rtos-hal\hal\source\intc

Сделал архив с сорцами, всё что касается INTC: intc.zip

В принципе, ничего нового там я не увидел.

Номера источников прерываний для T113-s3 интересно было бы увидеть.  Иначе, методом бинарного отсева приходится искать.

Заявление:  "номер обоаботчика в DSP = номеру в T113-s3 минус 32" - не работает.  К тому же, в 96 прерываний все прерывания не уложатся.

 

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 9/17/2023 at 3:33 PM, repstosw said:

Номер источника прерываний от GPIOC - 42

GPIOD - 44

  pintc_regs->pending1 = 0xffffffff;
  pintc_regs->enable1 = 0x1000;
  pintc_regs->mask1 = 0x0;

интересно есть ли какая-то закономерность или прерывания как попало разбросаны, прикинул если убрать пропуски в таблице чтобы подряд шли - все равно не клеится с тем что в мануале написано

Изменено пользователем sasamy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Столкнулся с такой проблемой. В ассемблерном сорце в коде обработчика прерывания пытаюсь сохранить в стеке регистры, которые восстанавливаются перед выходом из обработчика.

Для этого нужно сместить(уменьшить) указатель стека на число байт, которое надо для резервирования данных. Затем сохранить регистры, вызвать обработчик(на С),  восстановить регистры, и обратно сместить(увеличить) указатель стека.  Обработчик срабатывает, но при выходе из прерывания генерируется Double Exception и программа падает.

Если же место сишной функции вызвать call0 (не оконный вызов), то всё работает нормально.

В чём может быть дело? Как вообще с этим стеком работать так, чтобы не нарушать работу оконных переключений во время выполнения сишного обработчика?

Ну или с другого края зайду - как компилятору принудительно указать, что именно эту функцию оформить для вызова call0, вместо виндовых call4,8,12 ?

Interrupt:

	wsr.excsave1	a0		//save a0

	addi		sp,sp,-4	//decrease stack pointer up -4

	s32i		a3,sp,4		//a3 => [sp+4]

	movi		a3,PS_UM|PS_WOE_ABI|PS_INTLEVEL(1)
	wsr.ps		a3
	rsync

	call8		Handler

	movi		a3,PS_UM|PS_WOE_ABI|PS_INTLEVEL(0)
	wsr.ps		a3
	rsync

	l32i		a3,sp,4		//[sp+4] => a3
	      
	rsr.excsave1	a0		//restore a0
      
	addi		sp,sp,4		//correct stack ------ !!!

	rfe

.. //Double exception

 

Сейчас вынужден хранить регистры либо в выделенной памяти, либо в самом начале стека и не изменять содержимое регистра  sp (=a1).

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 9/18/2023 at 7:34 AM, repstosw said:

как компилятору принудительно указать, что именно эту функцию оформить для вызова call0, вместо виндовых call4,8,12 ?

abi можно поменять через параметры компилятора но непонятно как потом будет стыковаться такой винегрет

Quote
-mabi=name

Generate code for the specified ABI. Permissible values are: ‘call0’, ‘windowed’. Default ABI is chosen by the Xtensa core configuration.

https://gcc.gnu.org/onlinedocs/gcc/Xtensa-Options.html

У себя я экспериментировал с freertos  - ассемблера вообще не касался, добавил обработчик intc по аналогии с msgbox, там отпендил intc и gpio и вывел в консоль сообщение

static int intc_interrupt(int dummy, void *args) {
  static volatile struct intc_regs *(pintc_regs) = (volatile struct intc_regs *)SUNXI_R_INTC_PBASE;
  (void)dummy;
  uint32_t dat;
  intc_rxcb rcb = (intc_rxcb)args;

  uint32_t val = read32(0x02000000 + 0x274);
  write32(0x02000000 + 0x274, val);

  val = pintc_regs->pending1;
  pintc_regs->pending1 = val;

  printf("INTC irq\n");
  return 0;
}

void intc_init(void (*rxcb)(uint32_t, uint32_t)) {
  xt_set_interrupt_handler(INTC_IRQ, (xt_handler)intc_interrupt, (void *)rxcb);
  xt_ints_on(1 << INTC_IRQ);
}

вроде не падало. gpio настроил так

void vTaskMain(void *pvParameters) {
  (void)pvParameters;

  sunxi_gpio_init(GPIO_PIN(PORTD, 12), GPIO_PERIPH_MUX14);
  sunxi_gpio_set_pull(GPIO_PIN(PORTD, 12), GPIO_PULL_UP);
  write32(0x02000000 + 0x274, 0xffffffff);
  write32(0x02000000 + 0x270, 1 << 12);

//  dsp_msgbox_init(NULL);
  intc_init(NULL);

sunxi_gpio_Х взял из awboot но там нет ф-ий для прерываний - можно потом дописать для красоты. PLL включены в убуте поэтому я тактирования в freertos не касался.

Изменено пользователем sasamy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 hours ago, repstosw said:

В чём может быть дело? Как вообще с этим стеком работать так, чтобы не нарушать работу оконных переключений во время выполнения сишного обработчика?

Вопрос решён.  Нужно использовать DSP в режиме Kernel, а не User.   В режиме Kernel  манипуляции со стековыми фреймами работают.

//Было:
	movi		a3,PS_UM|PS_WOE_ABI|PS_INTLEVEL(0)
	wsr.ps		a3

//Стало:
	movi		a3,PS_WOE_ABI|PS_INTLEVEL(0)
	wsr.ps		a3

При этом обработчики прерываний уже будут висеть на Kernel: .org 0x1FC

 

1 hour ago, sasamy said:

abi можно поменять через параметры компилятора но непонятно как потом будет стыковаться такой винегрет

Это при линковке всего и вся.  Речь шла о том как сделать это с одной функцией, чтобы компилятор не создавал пролог:  entry a1,N  и вместо оконного выхода retw использовал регистровый  ret.

Эту функцию можно было вызвать в ассемблерном сорце через call0.   Если писать в ассемблере, то это работает.  А вот как сишную функцию сделать ABI=CALL0 - ХЗ, через GCC #pragma опция игнорируется.

 

1 hour ago, sasamy said:

У себя я экспериментировал с freertos  - ассемблера вообще не касался, добавил обработчик intc по аналогии с msgbox, там отпендил intc и gpio и вывел в консоль сообщение

Мне нужно было сохранить регистры в стековом фрейме.  Обработчики у меня и так прекрасно работают )))

Плюс я не использовал функции из фриртос, а писал установку прерываний самостоятельно.

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 9/18/2023 at 11:52 AM, repstosw said:

Плюс я не использовал функции из фриртос, а писал установку прерываний самостоятельно.

я на всякий случай привёл пример на freertos + С, чтобы люди не подумали что для работы с DSP на t113 обязательно нужны вериги из асма, нужны они если только погружаться в оптимизацию выходящую за рамки core isa

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, sasamy said:

abi можно поменять через параметры компилятора но непонятно как потом будет стыковаться такой винегрет

Quote
-mabi=name

Generate code for the specified ABI. Permissible values are: ‘call0’, ‘windowed’. Default ABI is chosen by the Xtensa core configuration.

https://gcc.gnu.org/onlinedocs/gcc/Xtensa-Options.html

Не работает этот параметр с компилятором. Пишет - unrecognized option.

Для линкера аналогичные:

  --abi-windowed              Choose windowed ABI for the output object
  --abi-call0                 Choose call0 ABI for the output object

Работает только -Wl,--abi-windowed,   c сall0 вываливаются ошибки во время линковки -  этот тулчейн  сконфигурирован только для windowed.  Жаль... ((

Скорее всего можно пересобрать и для call0-abi.

image.thumb.png.1900a5c81370bd0fb5d3d540838ce1bc.png

 

Ещё касаемо ABI.... В ассемблерном листинге наблюдаю только вызовы call8, callx8.   Не вижу call4, call12, callx4, callx12. тоесть какой-то фиксированный протокол вызова выходит. Хотелось чтобы это можно было задавать либо глобально, либо для каждой функции - как в нормальном GCC.

Я уже не говорю об атрибутах функции - pure, naked, interrupt...  Это всё нужно для системного уровня.

 

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 9/18/2023 at 1:20 PM, repstosw said:

Не работает этот параметр с компилятором. Пишет - unrecognized option.

ABI прописан в конфиге ядра - возможно только на новых версиях gcc можно переключаться, при сборке я указал версию gcc 10 - она у китайца и у SOF используется, с чем связано не знаю. Я давал ссылку на то как сконвертировать оверлей для crosstool-ng - попробуйте собрать свой тулчейн, и добавить в компилятор всё что не хватает. Ещё вариант - потребуйте у cadence.

Изменено пользователем sasamy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Запустил тест на быстродействие:  длинный кодер-декодер Рида Соломона GF(2^16).  Результаты огорчили: 4 FPS / 2  FPS на DSP:

Encode: 4 FPS   Decode: 2 FPS
Encode: 4 FPS   Decode: 2 FPS
Encode: 4 FPS   Decode: 2 FPS

На CPU  быстрее:

Encode: 26.2 FPS   Decode: 12.4 FPS
Encode: 26.2 FPS   Decode: 12.2 FPS
Encode: 26.2 FPS   Decode: 12.3 FPS

Кеширование включено. Без него вообще - менее 0.1 FPS.

 

Бенчмарк:   RS(2^16)_test.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 9/17/2023 at 4:18 PM, GenaSPB said:

resp... responce?

Из мануала:
If the corresponding bit is set, the interrupt with the lower or the same priority level is masked

смотря какого мануала

Quote

The priority logic appears not to be implemented, as setting any bit in the RESP register stops the AR100 from receiving interrupt exceptions from all IRQs.

https://linux-sunxi.org/INTC#Hardware_Architecture

но опять же этот мануал не подходит целиком для т113

Quote

Only the first register of each type is implemented, so a maximum of 32 IRQs are supported (but see below).

у т113 как минимум 88 прерываний снаружи можно подключить если верить freertos, проверено 44

Изменено пользователем sasamy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поймал забавную багу.  Если включено кеширование у DSP,  то подтверждение прерывания для DMA должно быть таким:

void DMA_Handler(void)
{
//...

 DMA_IRQ_PEND_REG1=DMA_IRQ_PEND_REG1;
 __asm__ __volatile__ ("memw");
}

или таким:

void DMA_Handler(void)
{
//...

 DMA_IRQ_PEND_REG1=DMA_IRQ_PEND_REG1;
 (void)DMA_IRQ_PEND_REG1;
}

Иначе после завершения прерывания - залетает один раз повторно! Только ОДИН раз!  И так до следующего  момента когда прерывание наступит - снова 2 раза.

Если кеш отключить, то можно просто вот так:

void DMA_Handler(void)
{
//...

 DMA_IRQ_PEND_REG1=DMA_IRQ_PEND_REG1;
}

Регистр объявлен как volatile.

На T113-s3 синхронизировать память-регистр было не нужно (но в конце обработчика прерывания стоит инструкция ISB).

 

Ещё особенность:  если разрешить прерывание GPIO обоим ядрам, то первым на него реагирует DSP,  следом  T113-s3.

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 9/22/2023 at 7:07 PM, repstosw said:

Если включено кеширование у DSP,  то подтверждение прерывания для DMA должно быть таким

кеширование чего - кода или данных ? диапазон MMIO периферии не кешируется

https://github.com/YuzukiHD/FreeRTOS-HIFI4-DSP/blob/164696d952116d20100daefd7a475d2ede828eb0/arch/board-init.c#L12C20-L12C20

я пока кроме экспериментов не касался прерываний от периферии, доделал загрузку кода в DSP из Linux на ARM

Quote

# echo -n dsp.elf > /sys/class/remoteproc/remoteproc0/firmware
# echo start > /sys/class/remoteproc/remoteproc0/state
[  266.893129] remoteproc remoteproc0: powering up 1700000.dsp
[  266.922401] remoteproc remoteproc0: Booting fw image dsp.elf, size 97808
[  266.929177] remoteproc remoteproc0: No resource table in elf
[  266.934857] remoteproc remoteproc0: map memory: 0x00400000+20000 to 0xc85c0000
[  266.942140] remoteproc remoteproc0: map memory: 0x47f00000+100000 to 0xc8600000
[  266.949489] remoteproc remoteproc0: Loading phdr 0 from 0x00400000 to 0xc85c0000 (284 bytes)
[  266.957928] remoteproc remoteproc0: Loading phdr 1 from 0x00401000 to 0xc85c1000 (364 bytes)
[  266.966382] remoteproc remoteproc0: Loading phdr 2 from 0x00401178 to 0xc85c1178 (16 bytes)
[  266.974741] remoteproc remoteproc0: Loading phdr 3 from 0x00401198 to 0xc85c1198 (16 bytes)
[  266.983112] remoteproc remoteproc0: Loading phdr 4 from 0x004011b8 to 0xc85c11b8 (16 bytes)
[  266.991476] remoteproc remoteproc0: Loading phdr 5 from 0x004011d8 to 0xc85c11d8 (16 bytes)
[  266.999836] remoteproc remoteproc0: Loading phdr 6 from 0x004011f8 to 0xc85c11f8 (16 bytes)
[  267.008183] remoteproc remoteproc0: Loading phdr 7 from 0x00401218 to 0xc85c1218 (16 bytes)
[  267.016546] remoteproc remoteproc0: Loading phdr 8 from 0x00401238 to 0xc85c1238 (16 bytes)
[  267.024905] remoteproc remoteproc0: Loading phdr 9 from 0x37f00000 to 0xc8600000 (38364 bytes)
[  267.033722] remoteproc remoteproc0: remote processor 1700000.dsp is now up
# DSP uart
DSP uart
DSP uart
DSP uart

# echo stop > /sys/class/remoteproc/remoteproc0/state
[  275.628899] remoteproc remoteproc0: stopped remote processor 1700000.dsp
[  275.635697] remoteproc remoteproc0: unmap memory: 0x00400000
[  275.641430] remoteproc remoteproc0: unmap memory: 0x47f00000

 

 

Изменено пользователем sasamy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...