repstosw 18 17 сентября, 2023 Опубликовано 17 сентября, 2023 (изменено) · Жалоба Удалось заставить 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=; Изменено 17 сентября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 17 сентября, 2023 Опубликовано 17 сентября, 2023 (изменено) · Жалоба resp... responce? Из мануала: If the corresponding bit is set, the interrupt with the lower or the same priority level is masked Разрешение вложенности при том же приореитете как-бы. Изменено 17 сентября, 2023 пользователем GenaSPB Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 17 сентября, 2023 Опубликовано 17 сентября, 2023 (изменено) · Жалоба 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 Изменено 17 сентября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 17 сентября, 2023 Опубликовано 17 сентября, 2023 (изменено) · Жалоба В общем этот китаец взял описание регистров 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 прерываний все прерывания не уложатся. Изменено 17 сентября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 0 17 сентября, 2023 Опубликовано 17 сентября, 2023 (изменено) · Жалоба 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; интересно есть ли какая-то закономерность или прерывания как попало разбросаны, прикинул если убрать пропуски в таблице чтобы подряд шли - все равно не клеится с тем что в мануале написано Изменено 17 сентября, 2023 пользователем sasamy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 18 сентября, 2023 Опубликовано 18 сентября, 2023 (изменено) · Жалоба Столкнулся с такой проблемой. В ассемблерном сорце в коде обработчика прерывания пытаюсь сохранить в стеке регистры, которые восстанавливаются перед выходом из обработчика. Для этого нужно сместить(уменьшить) указатель стека на число байт, которое надо для резервирования данных. Затем сохранить регистры, вызвать обработчик(на С), восстановить регистры, и обратно сместить(увеличить) указатель стека. Обработчик срабатывает, но при выходе из прерывания генерируется 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). Изменено 18 сентября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 0 18 сентября, 2023 Опубликовано 18 сентября, 2023 (изменено) · Жалоба 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 не касался. Изменено 18 сентября, 2023 пользователем sasamy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 18 сентября, 2023 Опубликовано 18 сентября, 2023 (изменено) · Жалоба 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 и вывел в консоль сообщение Мне нужно было сохранить регистры в стековом фрейме. Обработчики у меня и так прекрасно работают ))) Плюс я не использовал функции из фриртос, а писал установку прерываний самостоятельно. Изменено 18 сентября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 0 18 сентября, 2023 Опубликовано 18 сентября, 2023 · Жалоба On 9/18/2023 at 11:52 AM, repstosw said: Плюс я не использовал функции из фриртос, а писал установку прерываний самостоятельно. я на всякий случай привёл пример на freertos + С, чтобы люди не подумали что для работы с DSP на t113 обязательно нужны вериги из асма, нужны они если только погружаться в оптимизацию выходящую за рамки core isa Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 18 сентября, 2023 Опубликовано 18 сентября, 2023 (изменено) · Жалоба 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. Ещё касаемо ABI.... В ассемблерном листинге наблюдаю только вызовы call8, callx8. Не вижу call4, call12, callx4, callx12. тоесть какой-то фиксированный протокол вызова выходит. Хотелось чтобы это можно было задавать либо глобально, либо для каждой функции - как в нормальном GCC. Я уже не говорю об атрибутах функции - pure, naked, interrupt... Это всё нужно для системного уровня. Изменено 18 сентября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 0 18 сентября, 2023 Опубликовано 18 сентября, 2023 (изменено) · Жалоба On 9/18/2023 at 1:20 PM, repstosw said: Не работает этот параметр с компилятором. Пишет - unrecognized option. ABI прописан в конфиге ядра - возможно только на новых версиях gcc можно переключаться, при сборке я указал версию gcc 10 - она у китайца и у SOF используется, с чем связано не знаю. Я давал ссылку на то как сконвертировать оверлей для crosstool-ng - попробуйте собрать свой тулчейн, и добавить в компилятор всё что не хватает. Ещё вариант - потребуйте у cadence. Изменено 18 сентября, 2023 пользователем sasamy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 18 сентября, 2023 Опубликовано 18 сентября, 2023 · Жалоба Запустил тест на быстродействие: длинный кодер-декодер Рида Соломона 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 0 18 сентября, 2023 Опубликовано 18 сентября, 2023 (изменено) · Жалоба 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 Изменено 18 сентября, 2023 пользователем sasamy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 22 сентября, 2023 Опубликовано 22 сентября, 2023 (изменено) · Жалоба Поймал забавную багу. Если включено кеширование у 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. Изменено 22 сентября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 0 22 сентября, 2023 Опубликовано 22 сентября, 2023 (изменено) · Жалоба 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 Изменено 22 сентября, 2023 пользователем sasamy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться