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

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

On 9/23/2023 at 11:44 AM, sasamy said:

вдруг мне тоже потом надо барьер памяти делать

похоже что в freertos обработка прерываний корректно работает без барьера. Написал тестовый драйвер для Linux msgbox и проверил прерывания - соединил два gpio, один на выход с меандром а второй на вход прерываний, число пульсов совпадает с числом прерываний

#define GPIO_IN   GPIO_PIN(PORTD, 12)
#define GPIO_OUT  GPIO_PIN(PORTD, 13)

int interrupts = 0;

void vTaskMain(void *pvParameters)
{
	(void)pvParameters;
	int i = 1000;

	gpio_init(GPIO_OUT, GPIO_OUTPUT);
	gpio_set_value(GPIO_OUT, 1);

	gpio_init(GPIO_IN, GPIO_PERIPH_MUX14);
	gpio_set_pull(GPIO_IN, GPIO_PULL_UP);
	eint_init(GPIO_IN, EINT_NEGATIVE_EDGE);
	eint_ctl(GPIO_IN, EINT_ENABLE);

	dsp_msgbox_init(NULL);
	intc_init(NULL);

	printf("DSP uart\n");
	msgbox_channel_send_data(3, 0x12345678);

	printf("pulses %d\n", i);
	while (i--) {
		gpio_set_value(GPIO_OUT, 0);
		vTaskDelay(1);
		gpio_set_value(GPIO_OUT, 1);
		vTaskDelay(1);
	}
	printf("interrupts %d\n", interrupts);

	while (1) {
		vTaskDelay(1000);
	}
}

обработчик

extern int interrupts;

static int intc_isr(int dummy, void *args)
{
	(void)dummy;
	(void)args;
	uint32_t val;

	++interrupts;

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

	val = read32(SUNXI_R_INTC_PBASE + INTC_PENDING1);
	write32(SUNXI_R_INTC_PBASE + INTC_PENDING1, val);

	return 0;
}

результат

Quote

# echo -n dsp.elf > /sys/class/remoteproc/remoteproc0/firmware
# echo start > /sys/class/remoteproc/remoteproc0/state
[  233.242474] remoteproc remoteproc0: powering up 1700000.dsp
[  233.248299] remoteproc remoteproc0: Booting fw image dsp.elf, size 97904
[  233.255121] remoteproc remoteproc0: No resource table in elf
[  233.260805] remoteproc remoteproc0: map memory: 0x00400000+20000 to 0xc8780000
[  233.268091] remoteproc remoteproc0: map memory: 0x47f00000+100000 to 0xc8800000
[  233.275424] remoteproc remoteproc0: Loading phdr 0 from 0x00400000 to 0xc8780000 (284 bytes)
[  233.283879] remoteproc remoteproc0: Loading phdr 1 from 0x00401000 to 0xc8781000 (364 bytes)
[  233.292329] remoteproc remoteproc0: Loading phdr 2 from 0x00401178 to 0xc8781178 (16 bytes)
[  233.300675] remoteproc remoteproc0: Loading phdr 3 from 0x00401198 to 0xc8781198 (16 bytes)
[  233.309035] remoteproc remoteproc0: Loading phdr 4 from 0x004011b8 to 0xc87811b8 (16 bytes)
[  233.317401] remoteproc remoteproc0: Loading phdr 5 from 0x004011d8 to 0xc87811d8 (16 bytes)
[  233.325765] remoteproc remoteproc0: Loading phdr 6 from 0x004011f8 to 0xc87811f8 (16 bytes)
[  233.334129] remoteproc remoteproc0: Loading phdr 7 from 0x00401218 to 0xc8781218 (16 bytes)
[  233.342491] remoteproc remoteproc0: Loading phdr 8 from 0x00401238 to 0xc8781238 (16 bytes)
[  233.350836] remoteproc remoteproc0: Loading phdr 9 from 0x37f00000 to 0xc8800000 (38428 bytes)
[  233.359646] remoteproc remoteproc0: remote processor 1700000.dsp is now up
DSP uart
pulses 1000
[  233.368530] test-msgbox 3003000.mailbox: 0x12345678
interrupts 1000

 

 

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


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

33 minutes ago, sasamy said:

похоже что в freertos обработка прерываний корректно работает без барьера. Написал тестовый драйвер для Linux msgbox и проверил прерывания - соединил два gpio, один на выход с меандром а второй на вход прерываний, число пульсов совпадает с числом прерываний

Очевидно, роль барьера взял на себя вот этот фрагмент кода:

33 minutes ago, sasamy said:
val = read32(SUNXI_R_INTC_PBASE + INTC_PENDING1);
	write32(SUNXI_R_INTC_PBASE + INTC_PENDING1, val);

Проверил.  Действительно, если сделать чтение-запись регистра GPIO раньше, чем чтение-запись  INTC, то работает нормально.  И барьер не нужен:

void GPIOC_Handler(void)
{
 u32 val;

 UART_putc('c');

 val=PC_EINT_STATUS;
 PC_EINT_STATUS=val;

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

Так тоже работает нормально без барьера:

void GPIOC_Handler(void)
{
 UART_putc('c');

 PC_EINT_STATUS=PC_EINT_STATUS;
 pintc_regs->pending1=pintc_regs->pending1;
}

А вот так уже не работает нормально - без барьера будет второй заход в прерывание:

void GPIOC_Handler(void)
{
 UART_putc('c');

//buggy...
 pintc_regs->pending1=pintc_regs->pending1;
 PC_EINT_STATUS=PC_EINT_STATUS;
}

 

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


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

On 9/25/2023 at 10:39 AM, repstosw said:

А вот так уже не работает нормально - без барьера будет второй заход в прерывание:

проверил - в freertos перестановка пендингов мествами не влияет, код работает корректно без дополнительных барьеров

static inline __attribute__((__always_inline__)) void write32(virtual_addr_t addr, uint32_t value)
{
	*((volatile uint32_t *)(addr)) = value;
}

 

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


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

16 minutes ago, sasamy said:

проверил - в freertos перестановка пендингов мествами не влияет, код работает корректно без дополнительных барьеров

Значит в коде freertos есть фрагмент, который вносит задержку после чтения-записи регистра, выполняющий роль барьера )))

Что там идёт после вашего сишного обработчика?  Простыня из контекстов восстановлений? ))) Чем не барьер?

 https://github.com/YuzukiHD/FreeRTOS-HIFI4-DSP/blob/master/kernel/portable/xtensa_vectors.S#L617

https://github.com/YuzukiHD/FreeRTOS-HIFI4-DSP/blob/master/kernel/portable/xtensa_vectors.S#L1051

Слишком дофига всего:

   /* Save rest of interrupt context and enter RTOS. */
    call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */

    /* !! We are now on the RTOS system stack !! */ 

    /* Set up PS for C, enable interrupts above this level and clear EXCM. */
    #ifdef __XTENSA_CALL0_ABI__
    movi    a0, PS_INTLEVEL(1) | PS_UM
    #else 
    movi    a0, PS_INTLEVEL(1) | PS_UM | PS_WOE
    #endif
    wsr     a0, PS
    rsync

    /* OK to call C code at this point, dispatch user ISRs */

    dispatch_c_isr 1 XCHAL_INTLEVEL1_MASK

    /* Done handling interrupts, transfer control to OS */
    call0   XT_RTOS_INT_EXIT                /* does not return directly here */

 

На голом железе обработчик намного быстрее и понятнее )))

Kernel:
	addi		sp,sp,-64
	s32i		a0,sp,0
	s32i		a2,sp,4
	s32i		a3,sp,8
	s32i		a4,sp,12
	s32i		a5,sp,16
	s32i		a6,sp,20
	s32i		a7,sp,24
	s32i		a8,sp,28
	s32i		a9,sp,32
	s32i		a10,sp,36
	s32i		a11,sp,40
	s32i		a12,sp,44
	s32i		a13,sp,48
	s32i		a14,sp,52
	s32i		a15,sp,56

	movi		a2,PS_INTLEVEL(1)		//mask interrupts to prevent stack corrupt in C/C++ calls
	wsr.ps		a2
	rsync
      
	rsr.exccause	a2
	beqi		a2,EXCCAUSE_LEVEL1,IntLevel1
	
	j		. 	//catch rest interrupts

	.align 4

IntLevel1:
	movi		a2,INTC_VECTOR
	memw
	l32i		a2,a2,0
	l32i		a2,a2,0
	callx0		a2
      
	l32i		a15,sp,56
	l32i		a14,sp,52
	l32i		a13,sp,48
	l32i		a12,sp,44
	l32i		a11,sp,40
	l32i		a10,sp,36
	l32i		a9,sp,32
	l32i		a8,sp,28
	l32i		a7,sp,24
	l32i		a6,sp,20
	l32i		a5,sp,16
	l32i		a4,sp,12
	l32i		a3,sp,8
	l32i		a2,sp,4
	l32i		a0,sp,0
	addi		sp,sp,64
	rfi		1

 

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

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


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

Коллеги, вопрос к вам и модераторам, может вынесем тему про DSP Allwinner в отдельную, тут уже много всего по нему, потом мало ли что искать будет удобнее, как считаете?

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


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

Пытаюсь поднять C++ окружение.  Создаю конструкторы:

//C constructor
__attribute__((constructor(101))) void init101() { UART_puts("init101"); }

//C++ constructor
IClass ic(2,5);      //делаем экземпляр класса - уже на момент создания класса, С++ рантайм должен сработать
TestClass tc(ic);

int main(void)
{
//...

В линкере описываю нужные секции:

.preinit_array :
{
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
} > ROM

.init_array :
{
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
} > ROM

.fini_array :
{
    _fini = . ;
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
} > ROM

.ctors :
{
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors*))
} > ROM

.dtors :
{
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors*))
} > ROM

А в сишном стартапе пишу:

extern void (*__preinit_array_start []) (void) __attribute__((weak));
extern void (*__preinit_array_end []) (void) __attribute__((weak));
extern void (*__init_array_start []) (void) __attribute__((weak));
extern void (*__init_array_end []) (void) __attribute__((weak));
extern void (*__fini_array_start []) (void) __attribute__((weak));
extern void (*__fini_array_end []) (void) __attribute__((weak));

void _fini(void);
void _exit(int return_code) __attribute__((noreturn));

static void __libc_init_array(void)
{
 size_t count,i;

 count=__preinit_array_end-__preinit_array_start;
 for(i=0;i<count;i++)__preinit_array_start[i]();

 count=__init_array_end-__init_array_start;
 for(i=0;i<count;i++)__init_array_start[i]();
}

static void __libc_fini_array(void)
{
 int count,i;
 count=__preinit_array_end-__preinit_array_start;
 for(i=count-1;i>=0;i--)__fini_array_start[i]();
 _fini();
}

void exit(int return_code)
{
 __libc_fini_array();
 _exit(return_code);
}

void libc_init(void)
{
// memcpy(&_sdata,&_sidata,&_edata-&_sdata); //copy LMA to VMA
 memset(&_sbss,0,&_ebss-&_sbss);           //clear BSS

 __libc_init_array();                      //constructor init (C++)
}

 

В итоге конструкторы не работают!  Если их вызвать в main(), то они работают.   Вариант выше работает в ARM GCC, но не работает в DSP GCC.

Ассемблер показал следующее:

c18028a4 <.text.__libc_init_array>:
c18028a4:	e0c112                      	addi	a1, a1, -32
c18028a7:	7109                          	s32i.n	a0, a1, 28
c18028a9:	fff631                      	l32r	a3, 0xc1802884
c18028ac:	fff621                      	l32r	a2, 0xc1802884
c18028af:	c02320                      	sub	a2, a3, a2
c18028b2:	212220                      	srai	a2, a2, 2
c18028b5:	1129                          	s32i.n	a2, a1, 4
c18028b7:	020c                          	movi.n	a2, 0
c18028b9:	0129                          	s32i.n	a2, a1, 0
c18028bb:	0005c6                      	j	0xc18028d6
c18028be:	000000                      	ill
c18028c1:	fff031                      	l32r	a3, 0xc1802884
c18028c4:	0128                          	l32i.n	a2, a1, 0
c18028c6:	1122e0                      	slli	a2, a2, 2
c18028c9:	232a                          	add.n	a2, a3, a2
c18028cb:	0228                          	l32i.n	a2, a2, 0
c18028cd:	0002c0                      	callx0	a2

 

Тоесть он почему-то считает что __preinit_array_end = __preinit_array_start =  0xc1802884.   Тоесть в этой секции дырка от бублика, а не указатели, которые надо вызвать:

 count=__preinit_array_end-__preinit_array_start;
 for(i=0;i<count;i++)__preinit_array_start[i]();

 

Вопрос, как побороть это?   Может в данном GCC это не preinit_array, а как-то по-другому называется?

map-файл тоже пишет, что секция не занята.

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


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

13 hours ago, repstosw said:

Вопрос, как побороть это?   Может в данном GCC это не preinit_array, а как-то по-другому называется?

map-файл тоже пишет, что секция не занята.

Заработали конструкторы и статические объявления классов в С++.

Тулчейн размещает конструкторы в секцию .ctors, а не в .init / .init_array. Следовательно стартап для С++ с рабочими конструкторами выглядит так:

extern char _sidata,_sdata,_edata;
extern char _sbss,_ebss;
extern char _ctors_start,_ctors_end;

static void cxx_invoke_constructors(void)
{
 typedef void (*ctor_func_t)(void);
 ctor_func_t *func=(ctor_func_t*)&_ctors_start;
 for(;func!=(ctor_func_t*)&_ctors_end; func++)(*func)();
}

void libc_init(void)
{
// memcpy(&_sdata,&_sidata,&_edata-&_sdata); //copy LMA to VMA
 memset(&_sbss,0,&_ebss-&_sbss);           //clear BSS
 cxx_invoke_constructors();                //constructor init (C++)
}

Для линкера:

.ctors :
{
    PROVIDE_HIDDEN (_ctors_start = .);
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors*))
    PROVIDE_HIDDEN (_ctors_end = .);
} > ROM

Работают нормально как сишные конструкторы, так и статически объявленные C++ классы с инициализацией:

#include "klass.h"

void init101(void) __attribute__((constructor));
void init102(void) __attribute__((used,constructor));

void init101(void)
{
 UART_puts("init101\n");
}

void init102(void)
{
 UART_puts("init102\n");
}

IClass ic(2,5);      //делаем экземпляр класса - уже на момент создания класса, С++ рантайм должен вывести строку
TestClass tc(ic);

int main(void)
{
 UART_init();
 printf("\nHiFi4 C++ Class Example\n");
 while(1);
 return 0;
}

вывод:

init101
init102
Hi! I'm Constructor ;)
HiFi4 C++ Class Example

 

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

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


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

On 9/25/2023 at 7:39 PM, mantech said:

Коллеги, вопрос к вам и модераторам, может вынесем тему про DSP Allwinner в отдельную, тут уже много всего по нему, потом мало ли что искать будет удобнее, как считаете?

Добрый день! Не совсем понял, что Вы предлагаете?

 

Что-то выделить из этой темы в отдельную? Если да, то я поглядел всю тему бегло, считаю, что это сделать сложно без потери целостности изложения материала.

 

Или прицепить, т.е. закрепить, эту всю тему в шапке текущей ветки (TI,Allwinner, GigaDevice, Nordic, Espressif, etc.)?

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


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

5 часов назад, haker_fox сказал:

Что-то выделить из этой темы в отдельную?

Это было б хорошо, но если сложно, то что поделаешь, можно закрепить, тут много чего полезного для тех, кто захочет освоить данный DSP, ИМХО.

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


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

Пожалуй переименование и закреп здорово помогут.  Мне кстати на начальных этапах именно данная тема здорово помогла в разбирательствах с allwinner

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

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


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

6 minutes ago, GenaSPB said:

Пожалуй переименование и закреп здорово помогут. 

Модератор: Закрепил. Предлагайте новые имена темы. Я в данной теме микроконтроллеров не очень компетентен. Чтобы не засорять тему, я предлагаю писать мне личные сообщения.

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


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

9 hours ago, haker_fox said:

Что-то выделить из этой темы в отдельную? Если да, то я поглядел всю тему бегло, считаю, что это сделать сложно без потери целостности изложения материала.

Совершенно верно.

Я как автор темы, против разбиения этой темы.

 

3 hours ago, GenaSPB said:

Пожалуй переименование и закреп здорово помогут.  Мне кстати на начальных этапах именно данная тема здорово помогла в разбирательствах с allwinner

 

3 hours ago, haker_fox said:

Модератор: Закрепил. Предлагайте новые имена темы. Я в данной теме микроконтроллеров не очень компетентен. Чтобы не засорять тему, я предлагаю писать мне личные сообщения.

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

 

Доделал настройку тулчейна и SDK для C++.

Портировал ещё один мега-проектище, поддерживающий музыкальные форматы различных игровых систем: https://github.com/mmontag/game-music-emu

Game_Music_Emu is a collection of video game music file emulators that
support the following formats and systems:

AY        ZX Spectrum/Amstrad CPC
GBS       Nintendo Game Boy
GYM       Sega Genesis/Mega Drive
HES       NEC TurboGrafx-16/PC Engine
KSS       MSX Home Computer/other Z80 systems (doesn't support FM sound)
NSF/NSFE  Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)
SAP       Atari systems using POKEY sound chip
SPC       Super Nintendo/Super Famicom
VGM/VGZ   Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro

 

Как раз там один жёсткий С++ с классами.

 

Из особенностей, можно отметить следующее:

 

1. Линковать с -lstdc++. Иначе многое будет не определено.

 

2. Пришлось сделать свою реализацию __ieee754_remainder():

//                       IEEERemainder   Remainder operator
// 3 / 2 =                          -1                    1
// 4 / 2 =                           0                    0
// 10 / 3 =                          1                    1
// 11 / 3 =                         -1                    2
// 27 / 4 =                         -1                    3
// 28 / 5 =                         -2                    3
// 17.8 / 4 =                      1.8                  1.8
// 17.8 / 4.1 =                    1.4                  1.4
// -16.3 / 4.1 =    0.0999999999999979                   -4
// 17.8 / -4.1 =                   1.4                  1.4
// -17.8 / -4.1 =                 -1.4                 -1.4
/*
Remainder = (Math.Abs(dividend) - (Math.Abs(divisor) *   
            (Math.Floor(Math.Abs(dividend) / Math.Abs(divisor))))) *   
            Math.Sign(dividend)  

IEEERemainder = dividend - (divisor * Math.Round(dividend / divisor))  
*/

double __ieee754_remainder(double x,double y)
{
 return x-(y*round(x/y));
}

 

3. Функции-пустышки.  Не вызываются.  Но из-за -lstdc++ должны быть определены:

Spoiler
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wreturn-type"

void _exit(void)
{
 printf("_exit\n");
}

int _getpid_r(struct _reent *r)
{
 printf("_getpid_r\n");
}

int _kill_r(struct _reent *r,int a,int b)
{
 printf("_kill_r\n");
}

int _fstat_r(struct _reent *r,int a,struct stat *s)
{
 printf("_fstat_r\n");
}

_ssize_t _read_r(struct _reent *r,int a,void *p,size_t s)
{
 printf("_read_r\n");
}

_off_t _lseek_r(struct _reent *r,int a,_off_t o,int b)
{
 printf("_lseek_r\n");
}

_ssize_t _write_r(struct _reent *r,int a,const void *p,size_t s)
{
 printf("_write_r\n");
}

int _close_r(struct _reent *r,int a)
{
 printf("_close_r\n");
}

#pragma GCC diagnostic pop

 

 

4. Компиляция с флагами:

-Ofast -DNDEBUG -fmax-errors=1 
-ftree-vectorize -fno-math-errno -ffast-math 
-fno-rtti -fno-exceptions -fno-unwind-tables 
-fno-asynchronous-unwind-tables -fomit-frame-pointer
-fno-threadsafe-statics -ffunction-sections -fdata-sections

5. Линковка:

-nostartfiles -nostdlib -nodefaultlibs -ffreestanding 
-Wl,--gc-sections -Wl,--static -Wl,--strip-all
-lstdc++ -lhal

Постарался всё лишнее вырезать.

 

Работы над SDK для HiFi4 завершены.  Всё что хотел, получил.:biggrin:

 

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

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


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

4 часа назад, repstosw сказал:

Я как автор темы, против разбиения этой темы.

Это как так? Потрудитесь объяснить.

В 11.06.2020 в 11:54, __inline__ сказал:

Раскурил  Allwinner A13 SoC на уровне голого железа.

 

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


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

Потерялся логин давно...

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

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


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

По просьбе ТС поменял название темы на "Allwinner T113-s3 уделал HiFi4 DSP. Смеяться или плакать?". Во избежание ненужных проблем тему разделения этой темы на несколько предлагаю далее исключить из обсуждения и если интересно обсуждать какие-то частные вопросы - создавать отдельные темы.

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


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

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

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

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

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

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

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

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

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

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