|
Как оценить время в Keil, Не могу посчитать количество тактов |
|
|
|
Mar 16 2010, 15:09
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Nikitoc @ Mar 16 2010, 17:30)  Посоветуйте, как мерить время (в тактах, или наносекундах) выполнения команд. Debug->Execution Profiling->Time Только вейтстейты при работе с флеш и обращению к периферии он не учитывает. Я уж не говорю про простои из-за работы DMA. Поэтому считать лучше или в уме или на железке. Цитата(Nikitoc @ Mar 16 2010, 17:30)  Да, и еще, если разогнать проц до 80Мгц и выполнять программу из оперативной памяти... Ну, если он разгонится еще. Цитата(Nikitoc @ Mar 16 2010, 17:30)  ...будут ли быстрее выполняться команды обращения к портам? Мне нужно максимально быстро их сканировать для считывания видео с простенькой CMOS-камеры. Будут, конечно. Но чтение порта в любом случае достаточно медленное - 4 такта.
|
|
|
|
|
Mar 19 2010, 12:23
|

Местный
  
Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367

|
Типа отчет, о том что получилось. Тестовая программка: Код while (1) { AT91C_BASE_PIOA -> PIO_SODR = AT91C_BASE_PIOA -> PIO_SODR | 0x00000800; // PA11 = 1 AT91C_BASE_PIOA -> PIO_CODR = AT91C_BASE_PIOA -> PIO_CODR | 0x00000800; // PA11 = 0 } Мне удалось разогнать процессор (at91sam7s256) до 100 Мгц. При выполнении программы из ОЗУ период меандра на ножке PA11 был примерно 200 нс. И это при тактовом цикле 10нс! Дизассемблер показал, что изменение состояния ножки занимает 4-5 команд: Код 319: while (1) { 0x00102CE0 EA000008 B 0x00102D08 320: AT91C_BASE_PIOA -> PIO_SODR = AT91C_BASE_PIOA -> PIO_SODR | 0x00000800; // PA11 = 1 0x00102CE4 E3A00000 MOV R0,#0x00000000 0x00102CE8 E5100BD0 LDR R0,[R0,#-0x0BD0] 0x00102CEC E3800B02 ORR R0,R0,#0x00000800 0x00102CF0 E3A01000 MOV R1,#0x00000000 0x00102CF4 E5010BD0 STR R0,[R1,#-0x0BD0] 321: AT91C_BASE_PIOA -> PIO_CODR = AT91C_BASE_PIOA -> PIO_CODR | 0x00000800; // PA11 = 0 0x00102CF8 E3A00000 MOV R0,#0x00000000 0x00102CFC E5100BCC LDR R0,[R0,#-0x0BCC] 0x00102D00 E3800B02 ORR R0,R0,#0x00000800 0x00102D04 E5010BCC STR R0,[R1,#-0x0BCC] 319: while (1) { 0x00102D08 EAFFFFF5 B 0x00102CE4 Если каждая команда будет выполняться ровно 2 такта, то все складывается. Но, если я не ошибаюсь, у армов большинство команд выполняется за один такт. Может кто-нибудь подскажет, в чем дело?
|
|
|
|
|
Mar 19 2010, 13:24
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Nikitoc @ Mar 19 2010, 15:23)  Мне удалось разогнать процессор (at91sam7s256) до 100 Мгц. Что за стремление разогнать процессор, даже не попытавшись сначала освоить работу с ним в штатном режиме? Цитата(Nikitoc @ Mar 19 2010, 15:23)  Но, если я не ошибаюсь, у армов большинство команд выполняется за один такт. Ошибаетесь. Только MOV и ORR в приведенном листинге выполняются за один такт. Цитата(Nikitoc @ Mar 19 2010, 15:23)  Может кто-нибудь подскажет, в чем дело? Оптимизатор надо было включить. Ну и на чтениях порта теряете время.
|
|
|
|
|
Mar 19 2010, 13:47
|

Местный
  
Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367

|
Цитата(aaarrr @ Mar 19 2010, 17:24)  Ошибаетесь. Только MOV и ORR в приведенном листинге выполняются за один такт. А не подскажете, случайно, где можно подробно посмотреть время исполнения (в тактах) ассемблерных команд? Цитата Оптимизатор надо было включить. Ну и на чтениях порта теряете время. Ну да. При включенной оптимизации по времени 3-го уровня компилятор сократил код до 3-х команд: Код 319: AT91C_BASE_PIOA -> PIO_CODR = AT91C_BASE_PIOA -> PIO_CODR | 0x00000800; 0x00102BC4 E5140BCC LDR R0,[R4,#-0x0BCC] 0x00102BC8 E3800B02 ORR R0,R0,#0x00000800 0x00102BCC E5040BCC STR R0,[R4,#-0x0BCC] 320: AT91C_BASE_PIOA -> PIO_SODR = AT91C_BASE_PIOA -> PIO_SODR | 0x00000800; 0x00102BD0 E5140BD0 LDR R0,[R4,#-0x0BD0] 0x00102BD4 E3800B02 ORR R0,R0,#0x00000800 0x00102BD8 E5040BD0 STR R0,[R4,#-0x0BD0] 318: while (1) { 0x00102BDC EAFFFFF8 B 0x00102BC4 Но измерить разницу (увидеть на осциллографе) в периоде мне не удалось. Я имею в виду, что период так и остался равным примерно 200 нс... А по поводу разгона... так я ж говорил это мне видео хочется поснимать  При таких условиях мне удается захватить примерно 3,5 fps (QCIF 176x144). Но меня ограничивает скорость COM-порта PC - 115200. Поэтому следующий этап - освоение SPI и DMA. Хочется сделать потоковую запись на SD-карточку. Если это конечно будет иметь смысл (по скорости).
Сообщение отредактировал Nikitoc - Mar 19 2010, 13:48
|
|
|
|
|
Mar 19 2010, 14:14
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Nikitoc @ Mar 19 2010, 16:47)  А не подскажете, случайно, где можно подробно посмотреть время исполнения (в тактах) ассемблерных команд? В даташите на ARM7TDMI. Цитата(Nikitoc @ Mar 19 2010, 16:47)  Но измерить разницу (увидеть на осциллографе) в периоде мне не удалось. Я имею в виду, что период так и остался равным примерно 200 нс... Было 22 такта, стало 19. Уберите чтение PIO_SODR и PIO_CODR - это регистры только для записи. И почитайте даташит на процессор.
|
|
|
|
|
Mar 19 2010, 14:27
|

Местный
  
Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367

|
Цитата(aaarrr @ Mar 19 2010, 18:14)  В даташите на ARM7TDMI. Было 22 такта, стало 19. Уберите чтение PIO_SODR и PIO_CODR - это регистры только для записи. И почитайте даташит на процессор. :-) Все, я ушел просвещаться. Спасибо за помощь. P.S. Хотя по поводу PIO_SODR и PIO_CODR я не понял. Код AT91C_BASE_PIOA -> PIO_CODR = AT91C_BASE_PIOA -> PIO_CODR | 0x00000800 Я здесь вроде не читаю, а записываю... Как это сделать - на асме или на Си тоже можно?
Сообщение отредактировал Nikitoc - Mar 19 2010, 14:42
|
|
|
|
|
Mar 19 2010, 20:04
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Цитата AT91C_BASE_PIOA -> PIO_SODR = AT91C_BASE_PIOA -> PIO_SODR | 0x00000800; Цитата Я здесь вроде не читаю, а записываю... 0x00102BC4 E5140BCC LDR R0,[R4,#-0x0BCC] 0x00102BC8 E3800B02 ORR R0,R0,#0x00000800 0x00102BCC E5040BCC STR R0,[R4,#-0x0BCC] и где же _только пишем_?
|
|
|
|
|
Mar 19 2010, 20:29
|

Местный
  
Группа: Свой
Сообщений: 397
Регистрация: 3-12-09
Из: Россия, Москва
Пользователь №: 54 040

|
Цитата(Nikitoc @ Mar 19 2010, 17:27)  Я здесь вроде не читаю, а записываю... Ну как же: AT91C_BASE_PIOA -> PIO_CODR = AT91C_BASE_PIOA -> PIO_CODR | 0x00000800; Если подумать, откуда берётся значение выражения, выделенного жирным шрифтом?  Поэтому вполне достаточно будет просто: AT91C_BASE_PIOA -> PIO_CODR = 0x00000800; То же самое для PIO_SODR. Если записать в CODR 0x800 то установится в 0 только 11-й бит порта, на остальные никакого влияния не будет
|
|
|
|
|
Mar 19 2010, 20:37
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Nikitoc @ Mar 19 2010, 17:27)  Код AT91C_BASE_PIOA -> PIO_CODR = AT91C_BASE_PIOA -> PIO_CODR | 0x00000800 Я здесь вроде не читаю, а записываю... Как это сделать - на асме или на Си тоже можно? Читаете, естественно. Откуда иначе возьмется содержимое PIO_CODR, над которым производится операция bitwise OR? Если принять во внимание совершенную бесполезность чтения PIO_CODR (вредность, точнее, ибо никто даже не гарантирует, что из этого регистра будет считан 0, хотя на практике это и так), то останется: Код AT91C_BASE_PIOA->PIO_CODR = 0x00000800; И этот код даст точно такой же результат. P.S. Запись вида a |= 1 вместо a = a | 1 делает код гораздо более удобочитаемым.
|
|
|
|
|
Mar 19 2010, 22:45
|

Местный
  
Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367

|
Огромное спасибо за пояснения уважаемым гуру. Я, видите ли, не силен в arm-ассемблере (в СИ тоже не профессор  ), знаю более-менее только микрочиповский, для 8-битников, но это совсем другое дело . С этим чтением запутался вообще. В общем сделал как вы рекомендовали и скомпилилось компактней: Код 0x00103C14 E3A01B02 MOV R1,#0x00000800 0x00103C18 E3A00000 MOV R0,#pI2C(0x00000000) 0x00103C1C E5001BD0 STR R1,[R0,#-0x0BD0] 3169: AT91C_BASE_PIOA -> PIO_CODR = 0x00000800; 0x00103C20 E5001BCC STR R1,[R0,#-0x0BCC] 0x00103C24 EAFFFFFC B 0x00103C1C здесь: Код AT91S_TWI * pI2C = AT91C_BASE_TWI; #define AT91C_BASE_TWI (AT91_CAST(AT91PS_TWI) 0xFFFB8000) // (TWI) Base Address Вроде бы (особенно с вашими разъяснениями) код стал понятен, кроме строки: Код 0x00103C18 E3A00000 MOV R0,#pI2C(0x00000000) Как я не отнимал от 0xFFFB8000 0x0BD0 и 0x0BCC, базовых адресов регистров PIO_CODR (0xFFFFF434) PIO_SODR (0xFFFFF430) я не получил  . Что я неправильно понимаю? Почему нельзя занести в регистр R0 значение не pI2C, а pPIO? Относительно него смещения были бы меньше.
Сообщение отредактировал Nikitoc - Mar 19 2010, 22:47
|
|
|
|
|
Mar 19 2010, 22:51
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Nikitoc @ Mar 20 2010, 01:45)  Вроде бы (особенно с вашими разъяснениями) код стал понятен, кроме строки: Код 0x00103C18 E3A00000 MOV R0,#pI2C(0x00000000) Как я не отнимал от 0xFFFB8000 0x0BD0 и 0x0BCC, базовых адресов регистров PIO_CODR (0xFFFFF434) PIO_SODR (0xFFFFF430) я не получил. Что я неправильно понимаю? Почему нельзя занести в регистр R0 значение не pI2C, а pPIO? Относительно него смещения были бы меньше. А почему от 0xFFFB8000, а не от 0, как, собственно, и написано в команде? 0 - 0x0BD0 = 0xFFFFF430; 0 - 0x0BCC = 0xFFFFF434 Откуда в листинге взялся pI2C - остается только гадать. Вполне допускаю, что это просто своеобразный глюк дизассемблера.
|
|
|
|
|
Apr 6 2010, 15:59
|

Местный
  
Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367

|
Продолжаю терзать at91sam7s256. Привожу код который я написал для работы с SPI. Самое удивительное (для меня) и чему я не могу найти объяснения - это то, что код этот нормально работал (писал на SD-карточку), а теперь перестал работать. Код ///////////////////////////////////////////////////////////////////////////// void CONFIG_SPI () { pSPI -> SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | (AT91C_SPI_PCS & (0x0D << 16)); //Master mode, use freq divider, select 1 chanel CS. pSPI -> SPI_CSR[1] = AT91C_SPI_NCPHA | AT91C_SPI_BITS_8 | AT91C_SPI_CSAAT | (AT91C_SPI_SCBR & (SCBR << 8)); // clock idle low, data valid on rising edge, 8-bit data pSPI -> SPI_CR = AT91C_SPI_SPIEN | AT91C_SPI_LASTXFER; } ///////////////////////////////////////////////////////////////////////////////////// char SPI (char DATA) { pSPI -> SPI_TDR = DATA; while (!(pSPI -> SPI_SR & AT91C_SPI_TDRE)); /* Wait for Empty Tx Buffer */ while (!(pSPI -> SPI_SR & AT91C_SPI_RDRF)); return (pSPI -> SPI_RDR & 0xFF); } //////////////////////////////////////////////////////////////////////////////////// Просьба помочь найти ошибку.
|
|
|
|
|
Apr 6 2010, 16:26
|

Местный
  
Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367

|
Цитата(aaarrr @ Apr 6 2010, 19:08)  Предлагаете угадать, как именно он "перестал работать"? Да нет же. Может в коде какая-то ошибка... Отладчиком дохожу до условия - Код while (!(pSPI -> SPI_SR & AT91C_SPI_TDRE)); /* Wait for Empty Tx Buffer */ - и зависаю здесь, не могу дождаться этого флага. Линия CS в низкий уровень после загрузки SPI_TDR тоже не переводится. Такое впечатление, что SPI вообще не включен.
|
|
|
|
|
Apr 6 2010, 16:44
|

Местный
  
Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367

|
Цитата(aaarrr @ Apr 6 2010, 19:39)  А он включен? Выложите весь код, относящийся к SPI. Код void PIO_INIT () { pP_M_C -> PMC_PCER = pP_M_C -> PMC_PCER | 0x00000024; // Enable clocking of SPI and PIO (PIO clk enable for reading input state) pPIO -> PIO_PDR = 0x80027000; // disable PA17 I/O for PCK1 out and PA12,13,14,31 for SPI pPIO -> PIO_PER = 0x00240800; // enable PA21, PA18 and PA11 I/O pPIO -> PIO_PPUDR = 0xFFFFFCFF; // Turn off pull-up resistor except 8 and 9 pPIO -> PIO_ODR = 0x200014FF; // Enable input for PIO PA29, PA12, PA10, PA0-PA7 pPIO -> PIO_OER = pPIO -> PIO_OER | 0x00240800; // Enable out for PA11(CAMERA ON/OFF) and PA21 (ON/OFF SDcard) and PA18 (RED_LED) } Использую такие дефайны: Код #define SCBR ((MCK/SPCK)) /*SPI Baud Rate Divisor */
#define SPCK 18000000 /* SPI Baud Rate */
#define QUARTZ 20000000
#define FREQ_DIV 10
#define FREQ_MUL 89
#define MCK (((QUARTZ*(FREQ_MUL+1)/FREQ_DIV))/2) Код AT91S_SPI * pSPI = AT91C_BASE_SPI;
Сообщение отредактировал Nikitoc - Apr 6 2010, 16:50
|
|
|
|
|
Apr 6 2010, 17:12
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
pP_M_C чему равен? И зачем вообще использовать эти указатели? Запись Код *AT91C_PMC_PCER = 1UL << AT91C_ID_SPI; куда более читабельна и не вызывает лишних вопросов. Кроме того, не нужно читать write only регистры - PMC_PCER, PIO_OER. Начните с приведения частоты MCK к разрешенным значениям.
|
|
|
|
|
Apr 6 2010, 17:27
|

Местный
  
Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367

|
Цитата pP_M_C чему равен? И зачем вообще использовать эти указатели? Код AT91S_PMC *pP_M_C = AT91C_BASE_PMC; Цитата Запись Код *AT91C_PMC_PCER = 1UL << AT91C_ID_SPI; куда более читабельна и не вызывает лишних вопросов. Кроме того, не нужно читать write only регистры - PMC_PCER, PIO_OER. Угу. Спасибо. Понял. Цитата Начните с приведения частоты MCK к разрешенным значениям. К сожалению не помогло (уменьшил до 50МГц) симптомы те же :-( Значения прочитанных отладчиком регистров соответствуют тому, что я в них записываю (кроме WRITE ONLY, конечно). Я в тупике.
|
|
|
|
|
Apr 6 2010, 17:33
|

Местный
  
Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367

|
Цитата(aaarrr @ Apr 6 2010, 20:29)  Проверьте, включен ли клок для SPI в PMC_PCSR. Да включен, там записано значение 0xA4 P.S. А может SPI выйти из строя? И так чтобы регистры при этом остались доступными для чтения и записи?
Сообщение отредактировал Nikitoc - Apr 6 2010, 17:36
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|