Jump to content

    

__inline__

Участник
  • Content Count

    740
  • Joined

  • Last visited

Everything posted by __inline__


  1. Читаются большими блоками в память. Применительно к секторам карты ?
  2. Voice activity detection (VAD)

    Калина samsun, бред пишут. Наверное посты набивают ))) личка никак )))
  3. Добрый день. Использую C674x в связке с внешней SDRAM: организация памяти 32M x 16 (64 МБ), 4 банка памяти, одна страница памяти 1024 байт (10 бит). Кеш L1D, L1P и L2 включены, регионы кеширования MAR для адресов 0xC0000000 ... 0xC3FFFFFF (все 64 МБ) включены в регистрах. Программа выполняется из этой SDRAM, много данных (на несколько МБ), кода - несколько сотен килобайт (от 500 кБ). Активно используется выделения памяти из кучи (через memalign(128,x) ) - указатели выровнены на длину строки кеша L2 (максимальная длина) - 128 байт. Вопрос собственно вот в чём: есть ли смысл привязываться к банкам SDRAM для ускорения доступа к данным? Например - стек - в одном банке, куча - в другом, Zero-Init, UnInit - в третьем, код (.text) - в четвёртом? Или это ничего не даст? Прилагаю файл для линковщика - с расписанными секциями и регионами памяти, который сейчас используется. Программа стартует с самого начала SDRAM 0xC0000000: #define SDRAM_BASE 0xC0000000 #define SDRAM_SIZE 0x04000000 // 64 MB #define RO_SIZE 0x00098000 // <512 kB -c -stack 0x01700000 -heap 0x02800000 MEMORY { RO o = SDRAM_BASE l = RO_SIZE RW o = SDRAM_BASE+RO_SIZE l = SDRAM_SIZE-RO_SIZE } SECTIONS { .text:_c_int00* > SDRAM_BASE .text > RO .const > RO .switch > RO .cinit > RO .rodata > RO .init_array > RO //C++ .sysmem > RW .far > RW .stack > RW .bss > RW .neardata > RW .fardata > RW }
  4. Достиг 140 FPS (отрисовка + процессинг). Сделал буфер поворота на весь кадр (ранее было на 4 строки) и в L2. А видеобуфер расположил в SDRAM (номер банки SDRAM для буфера совпадает с номером банки где лежат исходные данные для отрисовки). DSP делает поворот на 90 градусов - оперирует блоками 4x4 пикселя сразу: void Video_Draw(void) { for(int y=0;y<(SCREEN_HEIGHT<<1);y+=8) //копирование видеобуфера с SDRAM с поворотом на 90 градусов в буфер L2 { u64 * __restrict vc=(u64*)(VIDEO_CACHE+y); u64 * __restrict vb0=(u64*)&VRAMBuffer[((SCREEN_WIDTH-4)<<1)+(SCREEN_WIDTH*y)]; u64 * __restrict vb1=vb0+(SCREEN_WIDTH>>2); u64 * __restrict vb2=vb1+(SCREEN_WIDTH>>2); u64 * __restrict vb3=vb2+(SCREEN_WIDTH>>2); for(int x=0;x<(SCREEN_WIDTH>>2);x++) { _amem8(&vc[(3*(SCREEN_HEIGHT>>2))+(SCREEN_HEIGHT*x)])=((u64)((u16) _amem8(&vb0[-x]) ))|((u64)((u16) _amem8(&vb1[-x]) )<<16)|((u64)((u16) _amem8(&vb2[-x]) )<<32)|((u64)((u16) _amem8(&vb3[-x]) )<<48); _amem8(&vc[(2*(SCREEN_HEIGHT>>2))+(SCREEN_HEIGHT*x)])=((u64)((u16)(_amem8(&vb0[-x])>>16)))|((u64)((u16)(_amem8(&vb1[-x])>>16))<<16)|((u64)((u16)(_amem8(&vb2[-x])>>16))<<32)|((u64)((u16)(_amem8(&vb3[-x])>>16))<<48); _amem8(&vc[(1*(SCREEN_HEIGHT>>2))+(SCREEN_HEIGHT*x)])=((u64)((u16)(_amem8(&vb0[-x])>>32)))|((u64)((u16)(_amem8(&vb1[-x])>>32))<<16)|((u64)((u16)(_amem8(&vb2[-x])>>32))<<32)|((u64)((u16)(_amem8(&vb3[-x])>>32))<<48); _amem8(&vc[(0*(SCREEN_HEIGHT>>2))+(SCREEN_HEIGHT*x)])=((u64)((u16)(_amem8(&vb0[-x])>>48)))|((u64)((u16)(_amem8(&vb1[-x])>>48))<<16)|((u64)((u16)(_amem8(&vb2[-x])>>48))<<32)|((u64)((u16)(_amem8(&vb3[-x])>>48))<<48); } } while(PRUSS_VideoBuffer); //PRU закончил рисовать предыдущий кадр? PRUSS_VideoBuffer=VIDEO_CACHE; //даём команду PRU отрисовывать новый кадр из L2 в LCD } В итоге выходит такая же производительность, что и без поворота! И это радует. Если же поворот переложить на PRU или дать ему буфер не в L2, то в SDRAM, то производительность падает в 3 раза по понятным причинам (PRU не имеет кеша данных и доступ к SDRAM идёт медленно. Также у PRU тактовая частота вдвое ниже частоты ядра DSP). А вот рутинную пересылку PRU очень даже отлично переваривает - можно бурстами делать (до 44 байт за 1 раз). Драйвер PRU для отрисовки всего LCD: #define IO volatile #define u32 unsigned int #define LCD 0x60004000 #define Pixel16 memcpy((void*)LCD,(const void*)VideoBuffer,32);VideoBuffer+=32; #define REP150(x) {x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x} #pragma LOCATION(VideoBuffer,0x0000) IO u32 VideoBuffer; void main(void) { VideoBuffer=0; Loop: if(!VideoBuffer)goto Loop; for(register int i=0;i<40;i++)REP150(Pixel16) VideoBuffer=0; goto Loop; } Ассемблер красиво это преобразует в бурсты по 32 байта: ;* --------------------------------------------------------------------------* ;* BEGIN LOOP ||$C$L2|| ;* ;* Loop source line : 22 ;* Loop closing brace source line : 22 ;* Known Minimum Trip Count : 40 ;* Known Maximum Trip Count : 40 ;* Known Max Trip Count Factor : 40 ;* --------------------------------------------------------------------------* ||$C$L2||: LDI32 r23, 0x60004000 ; [] |22| LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14.b0, r14, 0, 32 ; [] |22| SBBO &r14.b0, r23, 0, 32 ; [] |22| LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 ADD r14, r14, 0x20 ; [] |22| SBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14.b0, r14, 0, 32 ; [] |22| SBBO &r14.b0, r23, 0, 32 ; [] |22| LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 ADD r14, r14, 0x20 ; [] |22| SBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14.b0, r14, 0, 32 ; [] |22| SBBO &r14.b0, r23, 0, 32 ; [] |22| LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 ADD r14, r14, 0x20 ; [] |22| SBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14.b0, r14, 0, 32 ; [] |22| SBBO &r14.b0, r23, 0, 32 ; [] |22| LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 ADD r14, r14, 0x20 ; [] |22| ... SBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14.b0, r14, 0, 32 ; [] |22| SBBO &r14.b0, r23, 0, 32 ; [] |22| LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 ADD r14, r14, 0x20 ; [] |22| SBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 LBBO &r14.b0, r14, 0, 32 ; [] |22| SBBO &r14.b0, r23, 0, 32 ; [] |22| LBBO &r14, r0, 0, 4 ; [] |22| $O$K2 ADD r14, r14, 0x20 ; [] |22| SBBO &r14, r0, 0, 4 ; [] |22| $O$K2 SUB r22.b0, r22.b0, 0x01 ; [] |22| $O$L1,$O$L1 JMPNE ||$C$L2||, r22.b0, 0x00 ; [] |22| ... Думаю, на этих результатах можно остановиться: достигнут чистый FPS видеосистемы: 172 FPS, с процессингом : 140 FPS. А нужно было не меньше 60 FPS
  5. Есть ли другие способы копирования из одной памяти в другую с помощью DSP (именно DSP, не DMA), кроме как _mem8 и _amem8 ? У меня отрисовка тайла 8x8 занимает 34 цикла: void PPU16_Test(u16 SX,u32 SY,s16 DX,s16 DY) { u64 * __restrict SROMOffset=(u64*)&SROMBuffer[((SY*SROM_WIDTH8)+SX)<<1]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*VRAM_WIDTH )+DX)<<1]; _nassert((int)SROMOffset%16==0); _nassert((int)VRAMOffset%2==0); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*0)+0])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*0)+0]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*1)+0])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*1)+0]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*2)+0])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*2)+0]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*3)+0])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*3)+0]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*4)+0])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*4)+0]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*5)+0])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*5)+0]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*6)+0])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*6)+0]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*7)+0])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*7)+0]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*0)+1])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*0)+1]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*1)+1])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*1)+1]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*2)+1])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*2)+1]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*3)+1])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*3)+1]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*4)+1])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*4)+1]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*5)+1])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*5)+1]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*6)+1])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*6)+1]); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*7)+1])=_amem8(&SROMOffset[((SROM_WIDTH8>>2)*7)+1]); } ASM: ;****************************************************************************** ;* FUNCTION NAME: PPU16_Test * ;* * ;* Regs Modified : A3,A4,A5,A6,A7,A8,A9,A16,A17,A18,B4,B5,B6,B7,B8,B9, * ;* B16,B17,B18,B19,B20,B21,B22,B23,B24,B25 * ;* Regs Used : A3,A4,A5,A6,A7,A8,A9,A16,A17,A18,B3,B4,B5,B6,B7,B8, * ;* B9,DP,B16,B17,B18,B19,B20,B21,B22,B23,B24,B25 * ;* Local Frame Size : 0 Args + 0 Auto + 0 Save = 0 byte * ;****************************************************************************** PPU16_Test: ;** --------------------------------------------------------------------------* ; EXCLUSIVE CPU CYCLES: 34 LDW .D2T1 *+DP(SROMBuffer),A5 ; [B_D64P] |8| SHL .S2 B4,8,B4 ; [B_Sb674] |8| MVK .S2 400,B5 ; [B_Sb674] |9| ADD .L1X A4,B4,A3 ; [A_L674] |8| LDW .D2T2 *+DP(VRAMBuffer),B4 ; [B_D64P] |9| ADDAH .D1 A5,A3,A9 ; [A_D64P] |8| LDDW .D1T1 *A9(0),A5:A4 ; [A_D64P] |17| || MPYSU .M2 B6,B5,B5 ; [B_M674] |9| MVK .S1 512,A3 ; [A_S674] |18| ADD .L1 A3,A9,A8 ; [A_L674] |18| || MVK .S1 1024,A3 ; [A_S674] |19| || ADD .L2X A6,B5,B5 ; [B_L674] |9| || MVK .S2 1536,B6 ; [B_Sb674] |20| ADD .L1 A3,A9,A18 ; [A_L674] |19| || LDDW .D1T1 *A8(0),A7:A6 ; [A_D64P] |18| || ADDAH .D2 B4,B5,B22 ; [B_D64P] |9| || ADD .L2X B6,A9,B7 ; [B_L674] |20| LDDW .D1T1 *A18(0),A17:A16 ; [A_D64P] |19| || MVK .S2 2560,B4 ; [B_Sb674] |22| || LDDW .D2T2 *B7(0),B9:B8 ; [B_D64P] |20| MVK .S1 2048,A3 ; [A_S674] |21| || ADD .L2X B4,A9,B6 ; [B_L674] |22| || MVK .S2 3072,B4 ; [B_Sb674] |23| || STNDW .D2T1 A5:A4,*B22(0) ; [B_D64P] |17| ADD .L1 A3,A9,A3 ; [A_L674] |21| || ADD .L2X B4,A9,B5 ; [B_L674] |23| || LDDW .D2T2 *B6(0),B21:B20 ; [B_D64P] |22| || MVK .S2 100,B16 ; [B_Sb674] |18| LDDW .D1T1 *A3(0),A5:A4 ; [A_D64P] |21| || MVK .S2 3584,B4 ; [B_Sb674] |24| || LDDW .D2T2 *B5(0),B25:B24 ; [B_D64P] |23| ADD .L2X B4,A9,B4 ; [B_L674] |24| || STNDW .D2T1 A7:A6,*+B22[B16] ; [B_D64P] |18| MVK .S2 200,B16 ; [B_Sb674] |19| || LDDW .D2T2 *B4(0),B19:B18 ; [B_D64P] |24| || LDDW .D1T1 *A18(8),A7:A6 ; [A_D64P] |28| STNDW .D2T1 A17:A16,*+B22[B16] ; [B_D64P] |19| || MVK .S2 300,B16 ; [B_Sb674] |20| STNDW .D2T2 B9:B8,*+B22[B16] ; [B_D64P] |20| LDDW .D1T1 *A9(8),A17:A16 ; [A_D64P] |26| || LDDW .D2T2 *B7(8),B17:B16 ; [B_D64P] |29| MVK .S2 400,B7 ; [B_Sb674] |21| || LDDW .D1T1 *A8(8),A9:A8 ; [A_D64P] |27| || LDDW .D2T2 *B6(8),B9:B8 ; [B_D64P] |31| STNDW .D2T1 A5:A4,*+B22[B7] ; [B_D64P] |21| MVK .S2 500,B23 ; [B_Sb674] |22| || LDDW .D1T1 *A3(8),A5:A4 ; [A_D64P] |30| || LDDW .D2T2 *B5(8),B7:B6 ; [B_D64P] |32| STNDW .D2T2 B21:B20,*+B22[B23] ; [B_D64P] |22| || MVK .S2 600,B20 ; [B_Sb674] |23| STNDW .D2T2 B25:B24,*+B22[B20] ; [B_D64P] |23| || MVK .S2 700,B20 ; [B_Sb674] |24| STNDW .D2T2 B19:B18,*+B22[B20] ; [B_D64P] |24| STNDW .D2T1 A17:A16,*B22(8) ; [B_D64P] |26| || MVK .S2 101,B18 ; [B_Sb674] |27| STNDW .D2T1 A9:A8,*+B22[B18] ; [B_D64P] |27| || MVK .S2 201,B18 ; [B_Sb674] |28| STNDW .D2T1 A7:A6,*+B22[B18] ; [B_D64P] |28| || MVK .S2 301,B18 ; [B_Sb674] |29| LDDW .D2T2 *B4(8),B5:B4 ; [B_D64P] |33| || RET .S2 B3 ; [B_Sb674] |34| STNDW .D2T2 B17:B16,*+B22[B18] ; [B_D64P] |29| || MVK .S2 401,B16 ; [B_Sb674] |30| STNDW .D2T1 A5:A4,*+B22[B16] ; [B_D64P] |30| || ADD .L2 1,B23,B16 ; [B_L674] STNDW .D2T2 B9:B8,*+B22[B16] ; [B_D64P] |31| || MVK .S2 601,B8 ; [B_Sb674] |32| STNDW .D2T2 B7:B6,*+B22[B8] ; [B_D64P] |32| || ADD .L2 1,B20,B6 ; [B_L674] STNDW .D2T2 B5:B4,*+B22[B6] ; [B_D64P] |33| ; BRANCH OCCURS {B3} ; [] |34| Не всегда удаётся загрузить все 8 юнитов, как бы не старался (особенно простаивают L и M, активно используются S и D). В доке на ядро написано, что юниты не все операции могут, особенно M - это мультипликатор. В ARM'ах помню, можно было мульти-пересылку сделать наподобие: LDMCopy PUSH {r4-r10} LDMloop LDMIA r1!, {r3 - r10} STMIA r0!, {r3 - r10} SUBS r2, r2, #32 BGE LDMloop POP {r4-r10} или через регистровый файл VFP.
  6. Входные данные - SDRAM. Выходные - L2 и дисплей. SDRAM - на EMIFB, LCD на EMIFA. Вроде всё отвязано.. Конвеер видео-системы ниже на рисунке. С SDRAM видео-данные записываются в L2 - не весь буфер, а только выборочные элементы - спрайты с SDRAM. До 5 слоёв может быть. Загрузка с файлов музыки, звуков, картинок, спрайтов.... Размер неизвестен. С каждым новым уровнем - берутся новые данные: старые данные более неактуальны, идёт освобождение HEAP, занятие новыми объектами. Динамический менеджмент памяти. Однако же, помогло распределение памяти в скрипте ниже: модель памяти удалось сделать far_agregates, вместо far. Near не канает - код сильно большой. Выровнял указатели на 1024 байт (размер страницы SDRAM). Все объекты кроме кучи - толкнул с первую банку SDRAM. Итого: было 93 FPS, стало 110 FPS. Имеется ввиду не чистый FPS видео (он равен 171), а грязный - 1 фрейм + весь остальной процессинг. Нужно 60 FPS с VSYNC (что и обеспечивается), но запас не трёт ..... #define SDRAM_BASE 0xC0000000 #define SDRAM_SIZE 0x02000000 // 32 MB #define RO_SIZE 0x00098000 //< 640 kB -c -stack 0x00100000 -heap 0x00FFFF00 MEMORY { BANK0_RO o = 0xC0000000 l = RO_SIZE BANK0_RW o = 0xC0000000+RO_SIZE l = 0x00800000-RO_SIZE // BANK0_RO+BANK0_RW = 8MB BANK12 o = 0xC0800000 l = 0x01000000 // 16MB // BANK3 o = 0xC1800000 l = 0x00800000 // 8MB not used yet... } SECTIONS { .text:_c_int00* > SDRAM_BASE .text > BANK0_RO .const > BANK0_RO .switch > BANK0_RO .cinit > BANK0_RO .rodata > BANK0_RO .init_array > BANK0_RO //C++ .far > BANK0_RW .bss > BANK0_RW .neardata > BANK0_RW .fardata > BANK0_RW .stack > BANK0_RW //Stack .sysmem > BANK12 //Heap }
  7. Внял рекомендациям jcxz (за что ему громное спасибо! ). Удалось увеличить производительность на 30...50% (в зависимости от случая). Оказывается, индексная адресация лучше ложится на конвеер, чем инкременты с указателями. И однотипные операции лучше дублировать 2 , 4 или 8 раз. Перестановка действий также может влиять. И ещё можно не присваивать переменным промежуточный результат - компилятор это видит и оптимизирует сам. Инкременторы и питчи задефайнены в константы: SROMBuffer - это закешированная SDRAM на частоте CPU_CLK/3 VRAMBuffer - это L2 на частоте CPU_CLK Вот пример простого отображения: //102 цикла: void PPU16_Tile16B_0(u16 SX,u32 SY,s16 DX,s16 DY,u8 M) { u64 * __restrict SROMOffset=(u64*)&SROMBuffer[((SY*SROM_WIDTH)+SX)<<1]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*VRAM_WIDTH)+DX)<<1]; _nassert((int)SROMOffset%32==0); _nassert((int)VRAMOffset%2==0); for(int n=0;n<16;n++) { _mem8(&VRAMOffset[0])=_amem8(&SROMOffset[0]); _mem8(&VRAMOffset[2])=_amem8(&SROMOffset[2]); _mem8(&VRAMOffset[1])=_amem8(&SROMOffset[1]); _mem8(&VRAMOffset[3])=_amem8(&SROMOffset[3]); SROMOffset+=SROM_WIDTH>>2; VRAMOffset+=VRAM_WIDTH>>2; } } //96 циклов: ATT void PPU16_Tile16B_0(u16 SX,u32 SY,s16 DX,s16 DY,u8 M) { u64 * __restrict SROMOffset=(u64*)&SROMBuffer[((SY*SROM_WIDTH)+SX)<<1]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*VRAM_WIDTH)+DX)<<1]; _nassert((int)SROMOffset%32==0); _nassert((int)VRAMOffset%2==0); for(int n=0;n<4;n++) { _mem8(&VRAMOffset[(0*(VRAM_WIDTH>>2))+0])=_amem8(&SROMOffset[(0*(SROM_WIDTH>>2))+0]); _mem8(&VRAMOffset[(0*(VRAM_WIDTH>>2))+1])=_amem8(&SROMOffset[(0*(SROM_WIDTH>>2))+1]); _mem8(&VRAMOffset[(0*(VRAM_WIDTH>>2))+2])=_amem8(&SROMOffset[(0*(SROM_WIDTH>>2))+2]); _mem8(&VRAMOffset[(0*(VRAM_WIDTH>>2))+3])=_amem8(&SROMOffset[(0*(SROM_WIDTH>>2))+3]); _mem8(&VRAMOffset[(1*(VRAM_WIDTH>>2))+0])=_amem8(&SROMOffset[(1*(SROM_WIDTH>>2))+0]); _mem8(&VRAMOffset[(1*(VRAM_WIDTH>>2))+1])=_amem8(&SROMOffset[(1*(SROM_WIDTH>>2))+1]); _mem8(&VRAMOffset[(1*(VRAM_WIDTH>>2))+2])=_amem8(&SROMOffset[(1*(SROM_WIDTH>>2))+2]); _mem8(&VRAMOffset[(1*(VRAM_WIDTH>>2))+3])=_amem8(&SROMOffset[(1*(SROM_WIDTH>>2))+3]); _mem8(&VRAMOffset[(2*(VRAM_WIDTH>>2))+0])=_amem8(&SROMOffset[(2*(SROM_WIDTH>>2))+0]); _mem8(&VRAMOffset[(2*(VRAM_WIDTH>>2))+1])=_amem8(&SROMOffset[(2*(SROM_WIDTH>>2))+1]); _mem8(&VRAMOffset[(2*(VRAM_WIDTH>>2))+2])=_amem8(&SROMOffset[(2*(SROM_WIDTH>>2))+2]); _mem8(&VRAMOffset[(2*(VRAM_WIDTH>>2))+3])=_amem8(&SROMOffset[(2*(SROM_WIDTH>>2))+3]); _mem8(&VRAMOffset[(3*(VRAM_WIDTH>>2))+0])=_amem8(&SROMOffset[(3*(SROM_WIDTH>>2))+0]); _mem8(&VRAMOffset[(3*(VRAM_WIDTH>>2))+1])=_amem8(&SROMOffset[(3*(SROM_WIDTH>>2))+1]); _mem8(&VRAMOffset[(3*(VRAM_WIDTH>>2))+2])=_amem8(&SROMOffset[(3*(SROM_WIDTH>>2))+2]); _mem8(&VRAMOffset[(3*(VRAM_WIDTH>>2))+3])=_amem8(&SROMOffset[(3*(SROM_WIDTH>>2))+3]); SROMOffset+=SROM_WIDTH; VRAMOffset+=VRAM_WIDTH; } } Вариант с поворотом-отражением: //172 цикла //MIRROR_VERTICAL + ROTATE_90 ATT void PPU16_Tile16B_6(u16 SX,u32 SY,s16 DX,s16 DY,u8 M) { u64 * __restrict SROMOffset0=(u64*)&SROMBuffer[((SY*SROM_WIDTH)+SX)<<1]; u64 * __restrict SROMOffset1=SROMOffset0+(SROM_WIDTH>>2); u32 * __restrict VRAMOffset =(u32*)&VRAMBuffer[((DY*VRAM_WIDTH)+DX)<<1]; _nassert((int)SROMOffset0%32==0); _nassert((int)SROMOffset1%32==0); _nassert((int)VRAMOffset%2==0); for(int n=0;n<8;n++) { _mem4(&VRAMOffset[0x0*(VRAM_WIDTH>>1)])=(((u32)((u16) _amem8(&SROMOffset1[0]) ))<<16)|(u32)((u16) _amem8(&SROMOffset0[0]) ); _mem4(&VRAMOffset[0x2*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[0])>>32)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[0])>>32)); _mem4(&VRAMOffset[0x4*(VRAM_WIDTH>>1)])=(((u32)((u16) _amem8(&SROMOffset1[1]) ))<<16)|(u32)((u16) _amem8(&SROMOffset0[1]) ); _mem4(&VRAMOffset[0x6*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[1])>>32)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[1])>>32)); _mem4(&VRAMOffset[0x8*(VRAM_WIDTH>>1)])=(((u32)((u16) _amem8(&SROMOffset1[2]) ))<<16)|(u32)((u16) _amem8(&SROMOffset0[2]) ); _mem4(&VRAMOffset[0xA*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[2])>>32)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[2])>>32)); _mem4(&VRAMOffset[0xC*(VRAM_WIDTH>>1)])=(((u32)((u16) _amem8(&SROMOffset1[3]) ))<<16)|(u32)((u16) _amem8(&SROMOffset0[3]) ); _mem4(&VRAMOffset[0xE*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[3])>>32)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[3])>>32)); _mem4(&VRAMOffset[0x1*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[0])>>16)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[0])>>16)); _mem4(&VRAMOffset[0x3*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[0])>>48)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[0])>>48)); _mem4(&VRAMOffset[0x5*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[1])>>16)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[1])>>16)); _mem4(&VRAMOffset[0x7*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[1])>>48)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[1])>>48)); _mem4(&VRAMOffset[0x9*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[2])>>16)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[2])>>16)); _mem4(&VRAMOffset[0xB*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[2])>>48)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[2])>>48)); _mem4(&VRAMOffset[0xD*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[3])>>16)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[3])>>16)); _mem4(&VRAMOffset[0xF*(VRAM_WIDTH>>1)])=(((u32)((u16)(_amem8(&SROMOffset1[3])>>48)))<<16)|(u32)((u16)(_amem8(&SROMOffset0[3])>>48)); SROMOffset0+=SROM_WIDTH>>1; SROMOffset1+=SROM_WIDTH>>1; VRAMOffset++; } } Горизонтальное отражение: //MIRROR_HORIZONTAL ATT void PPU16_Tile16B_1(u16 SX,u32 SY,s16 DX,s16 DY,u8 M) { /* //102 cycle u64 * __restrict SROMOffset=(u64*)&SROMBuffer[((SY*SROM_WIDTH)+SX)<<1]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*VRAM_WIDTH)+DX)<<1]; _nassert((int)SROMOffset%32==0); _nassert((int)VRAMOffset%2==0); for(int n=0;n<16;n++) { _mem8(&VRAMOffset[0])=_itoll(_rotl(_loll(_amem8(&SROMOffset[3])),16),_rotl(_hill(_amem8(&SROMOffset[3])),16)); _mem8(&VRAMOffset[1])=_itoll(_rotl(_loll(_amem8(&SROMOffset[2])),16),_rotl(_hill(_amem8(&SROMOffset[2])),16)); _mem8(&VRAMOffset[2])=_itoll(_rotl(_loll(_amem8(&SROMOffset[1])),16),_rotl(_hill(_amem8(&SROMOffset[1])),16)); _mem8(&VRAMOffset[3])=_itoll(_rotl(_loll(_amem8(&SROMOffset[0])),16),_rotl(_hill(_amem8(&SROMOffset[0])),16)); SROMOffset+=SROM_WIDTH>>2; VRAMOffset+=VRAM_WIDTH>>2; } */ //96 cycle u64 * __restrict SROMOffset=(u64*)&SROMBuffer[((SY*SROM_WIDTH)+SX)<<1]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*VRAM_WIDTH)+DX)<<1]; _nassert((int)SROMOffset%32==0); _nassert((int)VRAMOffset%2==0); for(int n=0;n<4;n++) { _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*0)+0])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+3])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+3])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*0)+2])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+1])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+1])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*1)+0])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+3])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+3])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*1)+2])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+1])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+1])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*2)+0])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+3])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+3])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*2)+2])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+1])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+1])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*3)+0])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+3])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+3])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*3)+2])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+1])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+1])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*0)+1])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+2])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+2])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*0)+3])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+0])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*0)+0])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*1)+1])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+2])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+2])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*1)+3])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+0])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*1)+0])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*2)+1])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+2])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+2])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*2)+3])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+0])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*2)+0])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*3)+1])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+2])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+2])),16)); _mem8(&VRAMOffset[((VRAM_WIDTH>>2)*3)+3])=_itoll(_rotl(_loll(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+0])),16),_rotl(_hill(_amem8(&SROMOffset[((SROM_WIDTH>>2)*3)+0])),16)); SROMOffset+=SROM_WIDTH; VRAMOffset+=VRAM_WIDTH; } } Кто смотрели асм-листинг выше, те заметили, что число циклов было на 30 ... 50% больше, чем в последних вариантах. На практике прирост скорости подтвердился также. Особо радует вот это (несколько инструкций впараллель): $C$L164: ; PIPED LOOP PROLOG ; EXCLUSIVE CPU CYCLES: 4 MVK .S1 8800,A5 ; [A_S674] || MVK .S2 800,B8 ; [B_Sb674] || ADD .L2X A18,B18,B24 ; [B_L674] || ADD .L1X A29,B18,A25 ; [A_L674] || LDDW .D1T1 *A20(0),A19:A18 ; [A_D64P] |363| (P) <0,0> || LDDW .D2T2 *B19(0),B7:B6 ; [B_D64P] |363| (P) <0,0> MVK .S2 9600,B17 ; [B_Sb674] || MVK .S1 1600,A17 ; [A_S674] || ADD .L2 B8,B18,B23 ; [B_L674] || ADD .L1X A5,B18,A26 ; [A_L674] || LDDW .D1T2 *A20(16),B9:B8 ; [A_D64P] |367| (P) <0,1> || LDDW .D2T1 *B19(8),A5:A4 ; [B_D64P] |365| (P) <0,1> MVK .S1 10400,A31 ; [A_S674] || MVKH .S2 0xffff0000,B27 ; [B_Sb674] || ADD .L2 B17,B18,B22 ; [B_L674] || ADD .L1X A17,B18,A21 ; [A_L674] || LDDW .D1T1 *A20(8),A17:A16 ; [A_D64P] |365| (P) <0,2> ADDK .S1 -2,A0 ; [A_S674] || ADD .L2 B6,B18,B20 ; [B_L674] || ADD .S2 B16,B18,B21 ; [B_Sb674] || ADD .D2 B29,B18,B25 ; [B_D64P] || ADD .L1X A31,B18,A27 ; [A_L674]
  8. Да, скачал DSPlib, там везде индексный доступ типа такого: float DSPF_sp_dotprod(const float * x, const float * y, const int nx) { int i; float sum = 0; _nassert(nx > 0); _nassert(nx % 8 == 0); _nassert((int)x % 8 == 0); _nassert((int)y % 8 == 0); for(i = 0; i < nx; i++) sum += x[i]*y[i]; return (sum); } Немного рвёт шаблон, так как я предполагал, что индексная адресация более тормозная, чем работа через указатели. Вот наподобие сделал: void PPU16_Tile16B(u16 SX,u32 SY,s16 DX,s16 DY,u8 M) { u64 * __restrict SROMOffset=(u64*)&SROMBuffer[(SY*SPRITE_PITCH)+(SX<<1)]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*SCREEN_WIDTH)+DX)<<1]; _nassert((int)SROMOffset%32==0); //адрес откуда забираются данные всегда кратен 32 байтам (шаг 16 пикселей) _nassert((int)VRAMOffset%2==0); //адрес куда писать в видеобуфер всегда кратен 2 - точность 1 пиксел for(u32 y=0;y<16;y++) { _mem8(&VRAMOffset[4*y ])=_amem8(&SROMOffset[4*y ]); _mem8(&VRAMOffset[4*y+1])=_amem8(&SROMOffset[4*y+1]); _mem8(&VRAMOffset[4*y+2])=_amem8(&SROMOffset[4*y+2]); _mem8(&VRAMOffset[4*y+3])=_amem8(&SROMOffset[4*y+3]); } } Оно уже 102 цикла делается, вместо 168 что были. Тут не угадаешь, только пробовать и смотреть листинг. На счёт знаний ядра DSP, как повлиять на генерацию кода компилятором?
  9. Voice activity detection (VAD)

    написал в личку
  10. 8 лет назад я только заканчивал осваивать ARM9, BlackFin и Cyclone-2 FPGA Знать бы ещё как этот код поизменять. Сделал всё возможное от меня зависящее: память в SROM - это SDRAM закешированная на 152 МГц, там исходные данные, с неё читаю сразу 8 байт(4 пикселя) в регистр. Эти данные выровнены на 64 байта (вместо malloc использую memalign для выделения памяти), координаты образца-источника кратны 8 или 16. Память VRAM - это задний видеобуфер. Это кусочек L2 на частоте ядра 456 МГц - туда начитываю в зависимости от случая с атрибутами(отражение-поворот) - иногда удается сразу 8 байт записать, а иногда по 2 байта только. Здесь конечный адрес не выровнен, так как координаты записи могут быть не кратны 8. L2 - отдана на 64 кБ кеш данных, остальные 192 кБ- VRAM и буфер поворота. Отрисовка дисплея сделана через PRU1, с двойной буферизацией - пока DSP готовит новые данные, PRU1 отрисовывает предыдущие, затем меняем местами буфера. Процессор делает ещё поворот на 90 градусов, так как дисплей ведёт развертку вдоль меньшей стороны, и чтобы избежать тиринга изображения и подёргивания, приходится синхронизироваться по VSYNC. И поэтому буфер приходится записывать в дисплей повёрнутым на 90 градусов. Отрисовка в дисплей 171 FPS (переброс с L2 в LCD) , что очень близко к теоретическому максимуму - 176 FPS. Так как разрешение 400*240 *2 байта, шина 8 бит. Запись одного байта в дисплей EMIFA_CLK/3 = 101.3/3 = 33. 76 МГц Вот этих файлов как раз и не хватало для GCC. Попробую поковырять.
  11. Дано: C674x DSP. Цветовое пространство - 16 бит на пиксел (RGB 5:6:5). Надо: реализовать быстрый алгоритм отрисовки с цветом прозрачности. Цвет прозрачности один - либо прозрачно, либо нет. Пока так (неоптимально): for(y=0;y<100;y++) for(x=0;x<100;x++) if(src_color!=colorkey)dst_color=src_color; Советник производительности (perfomance adviser) пишет, что очень мешает условие внутри цикла и рекомендует заменить его на более быстрый алгоритм. Копаю intrinsic для C674x, что-то не могу сообразить из них что-то эффективное. Конкретно, вот это условие: if(src_color!=colorkey)dst_color=src_color; Надо заменить на быстрое выражение, логика которого: ( SRC_COLOR == COLOR_KEY ? ) DST_COLOR : DST_COLOR=SRC_COLOR ; Причём, значение цветового ключа можно выбрать любым, какое будет удобно. Будет только одно значение цветового ключа. Подозреваю, лучшие значения 0 или FFFF. И всё-же как ускориться ?
  12. Про алгоритмы отрисовки продолжил здесь:
  13. Листинг всей функции: test.asm Как можно ускорить если возможно? Опции компилятора:
  14. Я вам поверил на слово! :) Недавно стал разбираться с конвеерами. Мощная штука. А листинг я не додумался сгенерить, хотя бы по причине того, что в голову не пришло, что GCC не умеет конвееризировать код. :) Кстати, коль уж про конвееры речь пошла, какие опции полезны в настройках TI CC 8.3.5 ? У меня часто пишет в листинге такое: ;* Loop found in file : ..test.c ;* Loop source line : 10 ;* Loop opening brace source line : 11 ;* Loop closing brace source line : 15 ;* Known Minimum Trip Count : 8 ;* Known Maximum Trip Count : 8 ;* Known Max Trip Count Factor : 8 ;* Loop Carried Dependency Bound(^) : 3 ;* Unpartitioned Resource Bound : 2 ;* Partitioned Resource Bound(*) : 3 ;* Resource Partition: ;* A-side B-side ;* .L units 0 0 ;* .S units 1 2 ;* .D units 2 2 ;* .M units 0 0 ;* .X cross paths 0 0 ;* .T address paths 0 0 ;* Logical ops (.LS) 0 0 (.L or .S unit) ;* Addition ops (.LSD) 5 0 (.L or .S or .D unit) ;* Bound(.L .S .LS) 1 1 ;* Bound(.L .S .D .LS .LSD) 3* 2 ;* ;* Searching for software pipeline schedule at ... ;* ii = 3 Did not find schedule ;* ii = 4 Schedule found with 3 iterations in parallel ;* ;* Register Usage Table: ;* +-----------------------------------------------------------------+ ;* |AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB| ;* |00000000001111111111222222222233|00000000001111111111222222222233| ;* |01234567890123456789012345678901|01234567890123456789012345678901| ;* |--------------------------------+--------------------------------| ;* 0: | ***** | ** | ;* 1: | **** | ** | ;* 2: | ** * | **** | ;* 3: | ** * | ** | ;* +-----------------------------------------------------------------+ ;* ;* Done ;* ;* Loop will be splooped ;* Collapsed epilog stages : 0 ;* Collapsed prolog stages : 0 ;* Minimum required memory pad : 0 bytes ;* ;* Minimum safe trip count : 1 ;* Min. prof. trip count (est.) : 3 ;* ;* Mem bank conflicts/iter(est.) : { min 0.000, est 0.000, max 0.000 } ;* Mem bank perf. penalty (est.) : 0.0% ;* ;* ;* Total cycles (est.) : 8 + min_trip_cnt * 4 = 40 Это плохо или хорошо? На что надо обращать внимание чтобы код работал очень быстро? Пишу вывод графических примитивов размером 8x8 и 16x16 с учётом поворота (на кратные 90 градусов углы) и отзеркаливание по вертикали-горизонтали и оба. Всего 8 случаев вышло - вариант отражения + поворот Код отрисовки тайла 16x16 с поворотами и зеркалингами:
  15. Voice activity detection (VAD)

    Я брал VAD из кодека Speex на раздербан. Результаты порадовали. Оттудова же взял адаптивный шумоподавитель, очень помогает на MELP2400 или CELP4800 когда идешь вдоль дороги с автомобилями. Всё на C написано и портируемо. Пробовал реализацию на floating point, делать такое на fixed point -задолбаешься оптимизировать BASEOP.
  16. Огромное спасибо за информацию! Да, без пайплайнинга пасти там нечего. Фтпоку GCC, продолжаю работать на TI CC
  17. Приятно был удивлён, что сравнение с нулём привело к генерации более эффективного кода. Задача сводится к отрисовке небольшого квадратного блока 8x8 пикселей с цветом прозрачности. Ниже вариант без прозрачности - в нём за 1 раз рисуются 4 пиксела(8 байтная пересылка). Теперь как цвет прозрачности применить одновременно к 4-м пикселам, чтобы было быстро ? //VRAMOffset - указатель на видеобуфер, может быть невыровненный доступ //SROMOffset - указатель на исходные данные (выровнен на 8 байт) void Draw_Tile8x8(u16 SX,u32 SY,s16 DX,s16 DY) { u64 * __restrict SROMOffset=(u64*)&SROMBuffer[(SY*SPRITE_PITCH)+(SX<<1)]; u64 * __restrict VRAMOffset=(u64*)&VRAMBuffer[((DY*SCREEN_WIDTH)+DX)<<1]; for(u32 y=0;y<8;y++) { _mem8(VRAMOffset++)=_amem8(SROMOffset++); _mem8(VRAMOffset++)=_amem8(SROMOffset++); SROMOffset+=((SPRITE_PITCH>>1)-8)>>2; VRAMOffset+=(SCREEN_WIDTH-8)>>2; } }
  18. Отладочные платы, киты

    Актуально. + есть дисплей ардуино шилд на 480x320 с параллельной шиной + SD карта . Пишите на е-маил: repstosw2018 [dоg] gmail [dоt] com или в личку. Плюс новые платы для TMS320C6745.
  19. Актуально. Пишите на е-маил: repstosw2018 [dоg] gmail [dоt] com или в личку. Плюс новые платы для TMS320C6745.
  20. Завершил все работы с игровой консолью BlackPrism Portable. Презентация:
  21. Актуально. Пишите на е-маил: repstosw2018 [dоg] gmail [dоt] com или в личку. Плюс новые платы для TMS320C6745. Подробнее о проекте здесь: http://forum.easyelectronics.ru/viewtopic.php?f=17&t=39290&start=175 Монтажный чертёж, перечень элементов, тестовые прошивки, исходники SDK - по запросу. Схема : Видео в работе:
  22. Если по формулам, то аддитивный или FM-синтез. Yamaha OPL2, OPL3. Если нужна реалистичность звучания - Wavetable с ADSR-огибающей: OPL4. Камешек от Ямахи YMF721- может все типы синтеза аппаратно. Плюс декодирование MIDI-секвенций (MPU401). Использовал этот чип, всем доволен Комплект: Cхема:
  23. Насколько опасно повышать температуру паяльника для того, чтобы залить припой в металлизированное отверстие для Termal Pad? Монтаж ручной, в распоряжении паяльная станция с выставлением температуры и паяльный фен также с выставлением температуры. Нижнего подогрева нет. Диаметр отверстия 5,5 мм, толщина платы 0,91 мм, толщина фольги на внутренних слоях 35 мкм, на внешних 18 мкм, плата 4 слоя, два внутренних - сплошные плейны без разрезов, толщина ядра (между внутренними плейнами) 0,51 мм. Припой ПОС-61 (плавление 180 градусов), паяльная паста Mechanic Sn+Pb (плавление 180 градусов). Результаты: 1) Паяльный фен с тонкой круглой насадкой (больше диаметра отверстия) при температуре 180 градусов, 200 гр, 220 гр и 240 градусов - не оплавил паяльную пасту - просто легко вскипает флюс и ничего более. 2) Паяльник с температурой 350 градусов на кончике тонкого жала - не смог хорошо оплавить припой и равномерно распределить по отверстию. Жало паяльника пристаёт к плате. 3) Тот же паяльник с температурой на кончике жала 480 градусов с чуть-более толстым игольчатым жалом - смог равномерно залудить площадку и протащить припой в отверстие - соединив Termal Pad микросхемы с платой. Время - приблизительно 15 секунд Микросхема - TMS320C6745, QFP 176. Термал пад небольшой 7,5 x 6 мм примерно. При пайке или обдуве феном - плата жутко нагревается, особенно внутренние слои, а припой еле юлозит. Плата вoрует градусы тепла. Скажите, микросхема жить будет или нет? На прошлой версии тоже самое - работает (но там было 5 мелких отверстий вместо одного большого как сейчас).
  24. Задача: прикинуть компоновку радиоэлементов на печатной плате, изображённой на рисунке ниже. Контур платы сделан для определённого корпуса и изменению не подлежит. Красным цветом нарисованы компоненты, которые нельзя передвигать, так как в корпусе сделаны отверстия для них (регулировка громкости, индикация , разъёмы). Синим цветом - компоненты, которые можно двигать. На обратной стороне платы - дисплей LCD и управляющие кнопки (силикон с графитовым напылением + пара мембранных кнопок). Крайне нежалательно там что-либо размещать ещё, хотя если припрёт, то можно. Немного описания: Плата 4 слоя - верхний и нижний - трассы, второй и третий - сплошные плоскости земли и питания. Импульсник питания ядра стартует первый. Он разрешает запуск второго импульсника. На рисунке связь "enable" На аналоговое питание ЦАП выделен LDO, питающийся от аккумулятора Регулятор громкости и аудиовход УНЧ - высокоомные, поэтому УНЧ, ЦАП и регулятор находятся взаимно рядом. Чего не скажешь об аудиовыходе - он низкоомный и дифференциальный и поэтому его допустимо вести до самого аудио-разъёма. Если же сделать наоборот - УНЧ, ЦАП рядом с аудиовыходом, то прийдётся тащить трассу до регулятора громкости, а это шумы - иак как трасса слабосигнальная с высоким сопротивлением. Импульсник питания ядра DSP 1,3V больше ничего не питает - питание ядра инжектируется прямо на полигон питания ядра DSP (разведен в TOP слое) - самое кратчайшее соединение. Импульсник на 3,3 V - ведомый - включается после импульсника 1,3V и находится рядом с ним чтобы минимизировать дистанцию трассы управления Стабилизатор тока для светодиодной подсветки дисплея находится рядом со шлейфом LCD и его разъёмом. Хотя наверно лучше его на другую сторону перенести, так как разъём подключения LCD находится на обратной стороне Аккумулятор - плоский, кладётся сверху платы в специальный батарейный отсек корпуса. Из-за того что всё зарядное хозяйство находится в правом верхнем углу, прийдётся тянуть толстые трассы питания с Li-Io аккумулятора: запитывать импульсники, УНЧ и charge-pump Для подсветки. Вот так пока вижу. Покритикуйте пожалуйста! Выслушаю любые здравые соображения, рекомендации.
  25. Для себя я давно предпочёл фабричный корпус, в который будет устанавливаться разработанная плата. Он из пластика, какого- не знаю, может даже антистатик. Корпус с аналогичного устройства, разработанного китайцами. Это не MIL STD, а "for home or office use" !