|
|
  |
AT91SAM9G45, Настройка частоты работы GPIO |
|
|
|
Apr 24 2013, 18:19
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 23-04-13
Пользователь №: 76 596

|
Цитата(Fedor @ Apr 24 2013, 21:07)  И пропишите для вашей переменой i квалификатор register будет быстрее. Смысл в том что я хочу его в ддр запустить но пока что там что там работает одинаково поэтому в сраме и эксперементирую больше чем в ддраме ожидаю увеличения производительности сначало в сраме VDDPIO 3.3 register завтра попробую добавить
Сообщение отредактировал IgorKossak - Apr 24 2013, 18:40
Причина редактирования: избыточное цитирование
|
|
|
|
|
Apr 24 2013, 19:58
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
в дизасемблере надо смотреть что за такты в цикле, нет ли каких лишних на экономию регистров. На самом деле после компилятора на максимальной оптимизации я уверен смотреть нечего, и предложил это больше для вашего самоуспокоения. То есть вы бы увидели код, поняли что меньше 6 инструкций (или сколько там получается) не будет и успокоились бы)...
про кэш все абсолютно понятно. При работе кода из ДДР каждая инструкция требует чтение из памяти. Читать из ДДР - это далеко не 1 такт, там куча задержек на выбор ряда, колонки, потом просто ожидание данных и так далее. Чтение 1 инструкции из ДДР - это реально долго. Но если выбрать область памяти внутри проца, где время чтения 1 такт, и запихивать в нее куски кода из ДДР (а последовательно ДДР читает значительно быстрее, первая задержка считай делиться на все байты последовательности). Эти куски кода будут помещаться в кэш, тем более если есть циклы иногда они будут туда влезать целиком, и каждая инструкция будет выполнятся за 1 такт. Это и дает бешеный прирост производительности, без изменения вида кода.
|
|
|
|
|
Apr 25 2013, 05:23
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 26-10-05
Пользователь №: 10 125

|
Не мешает проверить также на какую область памяти у вас указывает sp Если в DRAM то настроить MMU так, чтобы стек тоже кэшировался.
|
|
|
|
|
Apr 25 2013, 09:08
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 23-04-13
Пользователь №: 76 596

|
Цитата(Fedor @ Apr 25 2013, 09:23)  Не мешает проверить также на какую область памяти у вас указывает sp Если в DRAM то настроить MMU так, чтобы стек тоже кэшировался. А как посмотреть куда указывает sp? Просто не доганяю как в эклипсовском дизасемблере это проделать)) да и думаю если я бутстрапом подгружаю приложение в ддр то наверное и переменная i будет там же И как настроить MMU чтобы стек кэшировался? Есть где нибудь примеры или описание с кусками кода в пример как вообще это настраивать этот MMU и все остальное? Где можно почитать о всяких таблицах и т.д.? Драм вариант в эмуляторе не запускается поэтому там дизассемблером посмотреть немогу а в срамовсом варианте sp указывает на срам область 0x30ff80
Сообщение отредактировал Sergey1212 - Apr 25 2013, 08:36
|
|
|
|
|
Apr 25 2013, 09:46
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 26-10-05
Пользователь №: 10 125

|
Цитата(Sergey1212 @ Apr 25 2013, 15:08)  А как посмотреть куда указывает sp?... Драм вариант в эмуляторе не запускается поэтому там дизассемблером посмотреть немогу а в срамовсом варианте sp указывает на срам область 0x30ff80 В конфигурационном файле для линковшика (*.ld, *.lds) обычно прописывается точка-указатель которым инициализируется SP в стартап файле. В самом стартап-файле прописываются вектора прерываний, начальная загрузка и проч. в том числе и загрузка указателя стека. Этот стартап файл написан на ассемблере (*.S, *.asm). Все это должно быть у вас в исходниках проекта. Поскольку в арме стэк это обычная область памяти, настройка MMU не отличается, лишь бы область стека попала в кэшируемую часть памяти.
|
|
|
|
|
Apr 25 2013, 10:57
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 23-04-13
Пользователь №: 76 596

|
Вот lds: CODE OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(entry)
MEMORY { sram (W!RX) : ORIGIN = 0x300000, LENGTH = 64K ddr_ebi0 (W!RX) : ORIGIN = 0x73f00000, LENGTH = 64M }
SECTIONS { .fixed : { . = ALIGN(4); _sfixed = .; *(.text*) *(.rodata*) *(.glue_7) *(.glue_7t) *(.data) *(.CP15_*) . = ALIGN(4); _efixed = .; } >ddr_ebi0
.prerelocate : AT (_efixed) { . = ALIGN(4); _sprerelocate = .; . = ALIGN(4); _eprerelocate = .; }
.postrelocate : AT (_efixed + SIZEOF(.prerelocate)) { . = ALIGN(4); _spostrelocate = .; *(.vectors); *(.ramfunc) . = ALIGN(4); _epostrelocate = .; } >sram
.bss (NOLOAD) : { _szero = .; *(.bss) . = ALIGN(4); _ezero = .; } >ddr_ebi0 _sstack = 0x73f00000 + 64 * 1024 * 1024; } end = .; А вот стартап: CODE #include "board.h"
//------------------------------------------------------------------------------ // Definitions //------------------------------------------------------------------------------
#define IRQ_STACK_SIZE 8*3*4
#define ARM_MODE_ABT 0x17 #define ARM_MODE_FIQ 0x11 #define ARM_MODE_IRQ 0x12 #define ARM_MODE_SVC 0x13
#define I_BIT 0x80 #define F_BIT 0x40
//------------------------------------------------------------------------------ // Startup routine //------------------------------------------------------------------------------
.align 4 .arm /* Exception vectors *******************/ .section .vectors, "a", %progbits
resetVector: ldr pc, =resetHandler /* Reset */ undefVector: b undefVector /* Undefined instruction */ swiVector: b swiVector /* Software interrupt */ prefetchAbortVector: b prefetchAbortVector /* Prefetch abort */ dataAbortVector: b dataAbortVector /* Data abort */ reservedVector: b reservedVector /* Reserved for future use */ irqVector: b irqHandler /* Interrupt */ fiqVector: /* Fast interrupt */ //------------------------------------------------------------------------------ /// Handles a fast interrupt request by branching to the address defined in the /// AIC. //------------------------------------------------------------------------------ fiqHandler: b fiqHandler //------------------------------------------------------------------------------ /// Handles incoming interrupt requests by branching to the corresponding /// handler, as defined in the AIC. Supports interrupt nesting. //------------------------------------------------------------------------------ irqHandler:
/* Save interrupt context on the stack to allow nesting */ sub lr, lr, #4 stmfd sp!, {lr} mrs lr, SPSR stmfd sp!, {r0, lr}
/* Write in the IVR to support Protect Mode */ ldr lr, =AT91C_BASE_AIC ldr r0, [lr, #AIC_IVR] str lr, [lr, #AIC_IVR]
/* Branch to interrupt handler in Supervisor mode */ msr CPSR_c, #ARM_MODE_SVC stmfd sp!, {r1-r3, r4, r12, lr} blx r0 /* Restore scratch/used registers and LR from User Stack */ /* Disable Interrupt and switch back in IRQ mode */ ldmia sp!, {r1-r3, r4, r12, lr} msr CPSR_c, #ARM_MODE_IRQ | I_BIT
/* Acknowledge interrupt */ ldr lr, =AT91C_BASE_AIC str lr, [lr, #AIC_EOICR]
/* Restore interrupt context and branch back to calling code */ ldmia sp!, {r0, lr} msr SPSR_cxsf, lr ldmia sp!, {pc}^
//------------------------------------------------------------------------------ /// Initializes the chip and branches to the main() function. //------------------------------------------------------------------------------ .section .text .global entry
entry: resetHandler:
/* Useless instruction for referencing the .vectors section */ ldr r0, =resetVector
/* Set pc to actual code location (i.e. not in remap zone) */ ldr pc, =1f
/* Initialize the prerelocate segment */ 1: ldr r0, =_efixed ldr r1, =_sprerelocate ldr r2, =_eprerelocate 1: cmp r1, r2 ldrcc r3, [r0], #4 strcc r3, [r1], #4 bcc 1b
/* Perform low-level initialization of the chip using LowLevelInit() */ ldr sp, =_sstack stmfd sp!, {r0} ldr r0, =LowLevelInit blx r0
/* Initialize the postrelocate segment */
ldmfd sp!, {r0} ldr r1, =_spostrelocate ldr r2, =_epostrelocate 1: cmp r1, r2 ldrcc r3, [r0], #4 strcc r3, [r1], #4 bcc 1b
/* Clear the zero segment */ ldr r0, =_szero ldr r1, =_ezero mov r2, #0 1: cmp r0, r1 strcc r2, [r0], #4 bcc 1b
/* Setup stacks **************/ /* IRQ mode */ msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT ldr sp, =_sstack sub r4, sp, #IRQ_STACK_SIZE
/* Supervisor mode (interrupts enabled) */ msr CPSR_c, #ARM_MODE_SVC | F_BIT mov sp, r4
/* Branch to main() ******************/ ldr r0, =main blx r0
/* Loop indefinitely when program is finished */ 1: b 1b Почему если я запускаю только айкеш производительность возрастает по сравнению с тем когда запускаю ММУ датакеш и айкеш в 1,5 раза вот на всякий случай мой код включения мму дата и айкешей CODE static unsigned char *BufMMU = (unsigned char *) (SRAM_ADDRESS + 0x4000);
#include "cp15/cp15.h" //Atmel at91lib
void InitMMU(unsigned int *pTranslationTable) { int i; int addSRAM;
// Program the TTB printf("TTB = 0x%X\n\r", (unsigned int)pTranslationTable);
CP15_WriteTTB((unsigned int)pTranslationTable);
// Program the domain access register CP15_WriteDomainAccessControl(0xFFFFFFFF); // domain 15: access are not checked
// Reset table entries for (i = 0; i < 4096; i++) { //printf("0x%X %d \r\n", (i << 20 | (3 << 10) | 0x12), (i << 20 | (3 << 10) | 0x12)); pTranslationTable[i] = i << 20 | (3 << 10) | 0x12; } // Program level 1 page table entry
// Vector adress pTranslationTable[0x0] = (0x00000000)|TLB_NCNB; // SRAM adress (with D cache) addSRAM = (SRAM_ADDRESS >> 20); printf("addSRAM = 0x%X\n\r", addSRAM); printf("SRAM_ADDRESS = 0x%X\n\r", SRAM_ADDRESS); pTranslationTable[addSRAM] = (SRAM_ADDRESS)|TLB_WB; //DDRAM buf1 with write-through pTranslationTable[0x701] = (AT91C_DDR2 + 0x00100000)|TLB_WT; //DDRAM buf2 with write-through pTranslationTable[0x702] = (AT91C_DDR2 + 0x00200000)|TLB_WT; // Peripherals adress
pTranslationTable[0xFFF] = (0xFFF00000)|TLB_NCNB; CP15_EnableMMU(); CP15_EnableDcache(); CP15_EnableIcache(); }
void main(void) { InitMMU((unsigned int*)BufMMU);
unsigned int mask = (1<<20);
AT91S_PIOM *pioa; pioa = PIOA_BASE; pio_enable(pioa, mask); pio_disable_irq(pioa, mask); pio_disable_multiple_driver(pioa, mask); pio_disable_pull_ups(pioa, mask); pio_output_enable(pioa, mask);
volatile unsigned int i; while(1) { i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++ ;i++; PIO_ClearM(pioa, mask); i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++;i++ ;i++; PIO_SetM(pioa, mask); } } pTranslationTable[i] = i << 20 | (3 << 10) | 0x12; Эту строку взял из убута до этого было pTranslationTable[i] = 0 И при этом не работали мму и дкеш но производительность при включении мму и дкеша сразу уменьшается чем это можно объяснить?
Сообщение отредактировал IgorKossak - Apr 25 2013, 13:58
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
Apr 25 2013, 14:08
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 26-10-05
Пользователь №: 10 125

|
Код pTranslationTable[i] = i << 20 | (3 << 10) | 0x12; Эта запись организует TLB и запрещает кеширование выбранных секций. Т.е. в данном случае для всего адресуемого 4GB. В убуте это видимо сделанно намеренно чтобы избежать коллизий при перезагрузке из линукса Код pTranslationTable[0x701] = (AT91C_DDR2 + 0x00100000)|TLB_WT; //DDRAM buf2 with write-through pTranslationTable[0x702] = (AT91C_DDR2 + 0x00200000)|TLB_WT; // Peripherals adress Здесь вы почемуто разрешаете кеширование, но для секций которые находятся вообще вне вашей области DRAM, судя по скрипту lds оно начинается с 0x73f00000, а у вас включено на 0x70100000 и на 0x70200000 ? Код ddr_ebi0 (W!RX) : ORIGIN = 0x73f00000, LENGTH = 64M Видимо пример был для другого случая. И вот такое |TLB_WT по моему больше подходит для перемещения массивов из одной области в другую, вам лучше write-back включить. Вобщем судя по настройке MMU и DCaсhe хоть и включен, но бестолку. Думаю, что нужно прочитать ARM926EJ-S Technical Reference Manual Complete. Код _sstack = 0x73f00000 + 64 * 1024 * 1024; это ваш верх стека из lds.
|
|
|
|
|
Apr 25 2013, 16:55
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 23-04-13
Пользователь №: 76 596

|
поправил pTranslationTable[i] = i << 20 | (3 << 10) | 0xDFE // Write-back 11 0 1111 1 11 10 т.е. как я понимаю разрешил кеширование всех секций? а чем может быть опасно кеширование секций всмысле почему в том же убуте запрещено? если кеширование разрешено то какие подводные камни могут выплыть?) Какие области памяти не стоит кешированть? зачем отдельно от мму есть возможность оключать датакеш? зачем их вообще отключать почему нельзя было сделать их все время включеными? если я буду кешировать все секции кроме 0x00000000 как сейчас получилось могут возникнуть какие-то проблемы?
Сообщение отредактировал Sergey1212 - Apr 25 2013, 17:23
|
|
|
|
|
Apr 25 2013, 17:52
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 26-10-05
Пользователь №: 10 125

|
Не нужно кэшировать область памяти где расположена внутренняя периферия. Куда читаете или пишете используя DMA, поскольку ЦП не знает про DMA , хотя вроде после каждой транзакции можно принудительно перезаливать кэш. Смысл кэшировать сегиент кода? Это не данные для этого есть ICache. Думаю что есть еще нюансы... Ну и нужно помнить что кэш данных не даст существенного прироста производительности если вы работаете с данными из разрозненных областей памяти вне пределов размера кэша.
|
|
|
|
|
Apr 25 2013, 18:28
|
Участник

Группа: Участник
Сообщений: 51
Регистрация: 8-10-09
Пользователь №: 52 809

|
Вот код инициализации MMU из softpack для sam9g35.
mmu.rar ( 1.68 килобайт )
Кол-во скачиваний: 57
|
|
|
|
|
Apr 25 2013, 18:30
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 23-04-13
Пользователь №: 76 596

|
Цитата(Fedor @ Apr 25 2013, 21:52)  Смысл кэшировать сегиент кода? Это не данные для этого есть ICache. Извеняюсь конечно но чет я не понимаю не фига) бутстрапом приложение копируется в 0x73f00000 это получается сегмент кода для которого достаточно только ICache? а где тогда сегмент данных? ICache кеширует только сам код программы? а чем занимаются DCache и MMU?
|
|
|
|
|
Apr 25 2013, 18:55
|
Участник

Группа: Участник
Сообщений: 51
Регистрация: 8-10-09
Пользователь №: 52 809

|
Для измерения скорости работы проца можно использовать basic-dhrystone-project. Я использую его для sam9g35, до этого для sam9xe. Максимальную скорость дает включение полной оптимизации по скорости(iar). Примеры atmel это конечно полный отстой, в плане того, что все они работают только при отключенном MMU. Если немного поискать можно найти много информации по MMU на этом форуме. А если хотите все знать ищите информацию по ARM926EJ.
|
|
|
|
|
Apr 25 2013, 19:06
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 23-04-13
Пользователь №: 76 596

|
Да пожалуй на пока инфы и примеров достаточно, надо теперь все переварить, в субботу выложу результаты полученные с хорошего осциллографа, по предварительным косвенным оценкам производительность вычисления i++ выросла в 25 раз! было 100 нс теперь предположительно должна стать 4 нс. Ногодрыгание имеющимся сейчас осциллографом не разглядеть. Всем большое спасибо за ответы.
|
|
|
|
|
Apr 25 2013, 20:51
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
Цитата(Sergey1212 @ Apr 25 2013, 22:30)  Извеняюсь конечно но чет я не понимаю не фига) бутстрапом приложение копируется в 0x73f00000 это получается сегмент кода для которого достаточно только ICache? а где тогда сегмент данных? ICache кеширует только сам код программы? а чем занимаются DCache и MMU? к дополнительному перевариванию надо в общих чертах про кэши и АРМ. У вас в проце отдельно шина данных и шина команд. Первые идеи были положить и данные и инструкции в одну память и сложение выглядело так загрузить адрес инструкции загрузить инструкцию распознать ее, понять что надо складывать загрузить адрес первого операнда загрузить операнд загрузить адрес 2 операнда загрузить операнд сложить получить адрес результата загрузить адрес результата выложить данные. Если к этому добавить что операнды обычно лежат черти как, а инструкции одна за одной, при это операнды лежат там где появились, а иснтрукции идут вперед и вперед, всем показалось разумным разделить области с операндами и инструкциями. При том пошли радикально, и разделили даже шины доступа к ним. А потом борясь с медленной памятью сделали кэши, вот мы и имеем их 2 штуки. кеш данных - на шине данных кеширует операнды кеш инструкций - на шине инструкций кеширует выполняемый код Кеши имеют разные алгоритмы работы, но в целом они автоматизированы, попали в ячейку памяти забрали ее и некую область вокруг. Попали в область кеша работаем из него, промазали, сбросили кеш загрузили новую область. Размер кеша допустим 4 кбайта, если вы будите тыкаться в ячейки расположенные друг от друга в 5 кбайтах так и будет постоянный сброс кеша и загрузка, будет медленее чем без него. И вот тут как я понимаю и помогает ММУ, как я понял при помощи него вы можете положить себе поближе нужные куски памяти, и постараться учесть как будет вести себя программа, как она будет и куда прыгать и так далее.. То есть это как бы интеллектуальный, управляемый кеш... Хотя я могу ошибаться, и тогда меня поправят  ... Если шину данных и адреса использовать для управления чем либо, то есть выставляя биты на ножках адреса и данных, то кешировать это пространство низя, данные будт в кеше, а ножки не будут шевелиться. Так же как и для переферии если надо менять ее регистры, то кеш не даст это делать, вы будите менять внутреннюю память проца (кеш), а не регистры. Ну и при обращении через ДМА - тоже беда, рассинхронизация памяти...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|