|
Расчёт скорости GPIO, какова максимальна скорость дрогонья и чтения? |
|
|
|
Dec 22 2008, 11:23
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
День добрый всем! Прошу помочь с расчётом. Есть мк LPC2194. Необходимо проделать следующее 1) считать значение порта Р0 с 0 по 7 (8 линий) 2) с "0" на "1" переключить одну ногу(не из тех 8 линий) 3) снова считать значение (1) 4) значения по байтно записывать в память оперативную Условия: - и на всё это отводится не более 900 нс. - цикл (1-4) повторяется раз в 2 мкс - VPBDIV = 0 , т.е. деления частоты для переферии нет = частоте тактирования проца. (хотя не уверен) - Кварц 10МГц, с ФАПЧ 60 МГц. Можно ли успеть? Думаю асм вставку придётся делать... + код в оперативу кидать... К сожелению генератора под рукой нет... чтоб проверить. А смысл в следующем: у ацп есть функция смена местами на выводах старшую и младшую байт, тем самым используя 8 линий сосчитать 16 бит. Для этого нужно "менять" уровень на определённой ноге. Уж не знаю с какой скорость читать будет... но обычный "дрогатель": Код IO0SET = 0x40000000; IO0CLR = 0x40000000; Дал мне максимум 2,5 МГц при расположение кода в оперативе... Это максимум? (правда сейчас стоит проц 2294 и кварц 14,7456 МГц и ФАПЧ до 56 МГц должно разгонять)
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 29)
|
Dec 22 2008, 12:40
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
МК именно 01. (только сейчас на олимексовской плате тренеруюсь H2294(старый, не 01)) А что за быстрые регистры? Они: IOPIN, IOSET, IOCLR? А есть воопче смысл в рам кидать? и для каких операций? Цитата Вне зависимости откуда выполняется прога - из рамы или из флэша. А в мануале прочёл: Код For the best performances, compile this code in the ARM mode and execute from the on-chip SRAM memory. и код: ldr r0,=0xe01fc1a0 /*register address--enable fast port*/ mov r1,#0x1 str r1,[r0] /*enable fast port0*/ ldr r1,=0xffffffff ldr r0,=0x3fffc000 /*direction of fast port0*/ str r1,[r0] ldr r0,=0xe0028018 /*direction of slow port 1*/ str r1,[r0] ldr r0,=0x3fffc018 /*FIO0SET -- fast port0 register*/ ldr r1,=0x3fffc01c /*FIO0CLR0 -- fast port0 register*/ ldr r2,=0x00001000 /*select fast port 0.12 for toggle*/ ldr r3,=0xE0028014 /*IO1SET -- slow port1 register*/ ldr r4,=0xE002801C /*IO1CLR -- slow port1 register*/ ldr r5,=0x00100000 /*select slow port 1.20 for toggle*/ /*Generate 2 pulses on the fast port*/ str r2,[r0] str r2,[r1] str r2,[r0] str r2,[r1] /*Generate 2 pulses on the slow port*/ str r5,[r3] str r5,[r4] str r5,[r3] str r5,[r4] loop: b loop Получается есть эфект? Т.е. регистры FIO0MASK FIO0PIN
|
|
|
|
|
Dec 22 2008, 15:58
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(bullit @ Dec 22 2008, 17:23)  ... Условия: - и на всё это отводится не более 900 нс. - цикл (1-4) повторяется раз в 2 мкс - VPBDIV = 0 , т.е. деления частоты для переферии нет = частоте тактирования проца. (хотя не уверен) - Кварц 10МГц, с ФАПЧ 60 МГц.
Можно ли успеть? Думаю асм вставку придётся делать... + код в оперативу кидать... Успеть можно. На асме не напрягаясь даже на старых чипах. Без использования рамы. Цитата Получается есть эфект? Чуть быстрее предвыборка после перехода. Возможно 1-2 такта. Ещё быстрее выполняются команды типа: Код ldr r4,=0xE002801C А линейный код из рамы и флэша исполняется одинаково быстро. Кроме того, неясно, кроме чтения/записи в порт будет какая-то основная прога выполняться? Если да, то придётся делать через FIQ, но при этом появится джиттер.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Dec 22 2008, 18:05
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Цитата Кроме того, неясно, кроме чтения/записи в порт будет какая-то основная прога выполняться? Если да, то придётся делать через FIQ, но при этом появится джиттер. Да будет конечно... Необходимо с 2 АЦП в течении порядка 2 мс, с переодичностью 2 мкс, опрашивать байты (8 линий). Кстати забыл совсем, что необходимо сначала с одного сосчитать 2 бита и потом с другого 2 бита. Между чтениями битов переключать "старший/младший"(byteswap помоему) и на всё это 900 нс. Т.е. на каждую ацп по 450 нс. По программе: запускаем конвертирование (1 на ногу КОНВ) и ждём когда бизи в ноль упадёт... Как лучше всего "ждать бизи"? по прерыванию или по опросу? В это время не на что не отвлекаюсь... все прерывания стороние не интересуют. А джитер будет больше 1 - 2 тактов?
|
|
|
|
|
Dec 22 2008, 19:00
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(bullit @ Dec 22 2008, 21:05)  Как лучше всего "ждать бизи"? по прерыванию или по опросу? В это время не на что не отвлекаюсь... все прерывания стороние не интересуют. Однозначно по опросу. Цитата(bullit @ Dec 22 2008, 21:05)  А джитер будет больше 1 - 2 тактов? Да, и значительно больше.
|
|
|
|
|
Dec 23 2008, 04:46
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(bullit @ Dec 23 2008, 00:05)  Да будет конечно... Необходимо с 2 АЦП в течении порядка 2 мс, с переодичностью 2 мкс, опрашивать байты (8 линий). Кстати забыл совсем, что необходимо сначала с одного сосчитать 2 бита и потом с другого 2 бита. Между чтениями битов переключать "старший/младший"(byteswap помоему) и на всё это 900 нс. Т.е. на каждую ацп по 450 нс. По программе: запускаем конвертирование (1 на ногу КОНВ) и ждём когда бизи в ноль упадёт... Как лучше всего "ждать бизи"? по прерыванию или по опросу? В это время не на что не отвлекаюсь... все прерывания стороние не интересуют.? А эти две миллисекунды нельзя полностью "посвятить" работе с АЦП? Было бы неплохо и очень надёжно. Ждать бизи лучше по тактам, если известно сколько оно длится. А если он длится больше 400 нс, то становится долго его ждать по опросу, и можно в лимит не уложиться. Цитата А джитер будет больше 1 - 2 тактов? Намного больше. В среднем вход в FIQ будет задержан на 4 такта. Минимум 0 (или 1 - хз), максимум около 20, но недавно исследуя этот вопрос выше 17 я не смог получить, хотя использовал в коде самые длинные команды LDM и STM.
Сообщение отредактировал GetSmart - Dec 23 2008, 04:48
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Dec 23 2008, 04:59
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Цитата А эти две миллисекунды нельзя полностью "посвятить" работе с АЦП? Было бы неплохо и очень надёжно. Именно 2 мс буду отданы на АЦП... Цитата Ждать бизи лучше по тактам, если известно сколько оно длится. А если он длится больше 400 нс, то становится долго его ждать по опросу, и можно в лимит не уложиться Т.к. конвертирование на двух АЦП я запускаю одновременно, то ждать буду на каком АЦП появится раньше, с того и начну опрос. Известно, что от запуска конвертирования до спада бизи в ноль как максимум 1100нс. Получается на опрос с двух АЦП 900нс максимум. Думаю всё таки зациклить опрос бизи... делать паралельно нечего... жди приход да и всё... Главное успеть за 900нс опросить оба АЦП. А вот по поводу запуска конвертирования: лучше на таймер 2 мкс отсчёт сделать? потому как более надёжного способа я не вижу...
|
|
|
|
|
Dec 23 2008, 09:46
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
У меня обе АЦПшки висят на одном порту. АЦП имеет 3 состояние, управляемое CS и RD. Заводить бизи с двух АЦП на одну ногу - значит не иметь информации с какого именно АЦП пришло. Использовать отдельные порты МК для каждого АЦП и накладно (трудно развести плату), да и портов нет. Потому как возможно часть свободных портов может уйти на другие нужды. Наверое рисунок схемы будет Вам полезен. А то всплывают каждый раз новые подробности... файл бмп в архиве (с 2 Мб до 57 кб  ). Цитата Оба варианта медленные. Лучше так: считали 2 бита, если оба равны нулю, то начинаем считывать АЦП. Считываем всегда в одном порядке. Иначе потеряете вагон времени. Получается что ждём пока оба не закончут конвертирование. В принципе вариант хорош тем, что шумы при работе МК не пройдут на другой АЦП, который в это время будет опрашиваться... А так только по одной линии - что в принципе снизит уровень "помех наводок". НО тогда надо иметь хороший запас во времени. И еще хотел сросить про организацию сохранения результатов в памяти. Можно ли силами си/си++ организовать массив или что-то подобное. И еще: как вы можите видеть: старший бит АЦП на "месте" младшего бита мк. Как можно "перевернуть" данные? Хотя это можно сделать и позднее на ПК. Сделано так с точки зрения разводки платы, нет перекрёсных цепей.
|
|
|
|
|
Dec 23 2008, 10:43
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(bullit @ Dec 23 2008, 15:46)  Заводить бизи с двух АЦП на одну ногу - значит не иметь информации с какого именно АЦП пришло. Использовать отдельные порты МК для каждого АЦП и накладно (трудно развести плату), да и портов нет. Потому как возможно часть свободных портов может уйти на другие нужды. Речь шла о том, чтобы весить бизи на два разных пина одного порта. Порт - это IOPIN0 или IOPIN1, или IOPINx. Порт содержит до 32 пинов, то есть бит. Хотя есть вариации у каждого проца, иногда всего пол порта наружу выходит, а иногда с дырками, но не суть. Два пина есть на любом порте. И их оба можно прочитать за одно чтение порта, сэкономив МНОГО времени. ЗЫ. P0.14 зря задействовали. Он управляет бутлоадером. Его надо бы подтянуть к плюсу через 10к.
Сообщение отредактировал GetSmart - Dec 23 2008, 10:59
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Feb 3 2009, 15:56
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Хотел бы поднять тему, с целью получения совета, на вопрос в посте выше №14: Цитата И еще хотел сросить про организацию сохранения результатов в памяти. Можно ли силами си/си++ организовать массив или что-то подобное. Програмирую а IARe. Т.е. мне нужно в оперативу скинуть 2 бита с двух ацп, и таких измерений, т.е. 2 бита всего 1000. Но можно и меньше до 900. Памяти ОЗУ у меня в принципе нечем не занято. Я принимаю команду по SPI, даю одну команду на UART и принимаю данные с АЦП, а затем уже их по SPI сливаю. И потом опять всё повтаряю. Вот как програмно реализовать массив?
|
|
|
|
|
Feb 3 2009, 18:43
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(bullit @ Feb 3 2009, 21:35)  Типа d: array[0..1000;0..1]: short; ?  Типа: Код short d[1000]; Хотя не знаю, чем это может помочь - надо изучать язык. Цитата(bullit @ Feb 3 2009, 21:35)  И еще не понятно насчет быстрых GPIO, т.е. вместо обычных регистров GPIO использовать FGPIO регистры? Да.
|
|
|
|
|
Feb 4 2009, 04:32
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Цитата я так понял, что эти два АЦП 8-разрядные? Нет! Это 14 битная АЦП, с паралельным выходом, с возможностью передачи по 8 линиям все 14 бит. Т.е. сначала младший потом старший. А вариант с STM32 я уже смотрел. И Силабсы 06х серии тоже. НО остановился на этом варианте.
|
|
|
|
|
Feb 20 2009, 09:07
|

пуля
   
Группа: Свой
Сообщений: 674
Регистрация: 10-05-06
Из: Уфа
Пользователь №: 16 959

|
Делал тут я испытания... и вот что у меня получилось: CODE // Настройка выводов для работы Первого АЦП #define CONV_START1 FIO0CLR_bit.P0_29=1; // Старт Конвертирования АЦП #define CONV_STOP1 FIO0SET_bit.P0_29=1; // Вернуть состояние входа "CONV" АЦП в нормальное состояние #define START_READ1 FIO0CLR_bit.P0_30=1; // Разрешение на чтение ответа от АЦП #define STOP_READ1 FIO0SET_bit.P0_30=1; // Запрет чтения ответа от АЦП #define READ_LOWBYTE1 FIO1CLR_bit.P1_24=1; // Чтение МЛАДШЕГО байта #define READ_HIGHBYTE1 FIO1SET_bit.P1_24=1; // Чтение старшего байта #define BUSY_ADC1 FIO0PIN_bit.P0_16 // Чтение стостояния АЦП
// Настройка выводов для работы Второго АЦП #define CONV_START2 FIO0CLR_bit.P0_10=1; // Старт Конвертирования АЦП #define CONV_STOP2 FIO0SET_bit.P0_10=1; // Вернуть состояние входа "CONV" АЦП в нормальное состояние #define START_READ2 FIO0CLR_bit.P0_11=1; // Разрешение на чтение ответа от АЦП #define STOP_READ2 FIO0SET_bit.P0_11=1; // Запрет чтения ответа от АЦП #define READ_LOWBYTE2 FIO0CLR_bit.P0_13=1; // Чтение МЛАДШЕГО байта #define READ_HIGHBYTE2 FIO0SET_bit.P0_13=1; // Чтение старшего байта #define BUSY_ADC2 FIO0PIN_bit.P0_12 // Чтение стостояния АЦП
// Настройка выводов для работы 2-ух АЦП #define CONV_START FIO0CLR=0x20000400; // Старт Конвертирования АЦП #define CONV_STOP FIO0SET=0x20000400; // Вернуть состояние входа "CONV" АЦП в нормальное состояние
// Усиление #define GAIN1 FIO0SET = 0x1A000000; // Усиление 1(0) dB #define GAIN2 FIO0SET = 0x18000000; FIO0CLR = 0x02000000; // Усиление 3 dB #define GAIN3 FIO0SET = 0x12000000; FIO0CLR = 0x08000000; // Усиление 6 dB #define GAIN4 FIO0SET = 0x10000000; FIO0CLR = 0x0A000000; // Усиление 9 dB #define GAIN5 FIO0SET = 0x0A000000; FIO0CLR = 0x10000000; // Усиление 12 dB #define GAIN6 FIO0SET = 0x08000000; FIO0CLR = 0x12000000; // Усиление 15 dB #define GAIN7 FIO0SET = 0x02000000; FIO0CLR = 0x18000000; // Усиление 18 dB #define GAIN8 FIO0CLR = 0x1A000000; // Усиление 21 dB
// Variable
u8 dataMB; u8 dataSB; u16 data[1000][2];
int main (void) { // System initialization, this will map the exception vectors. LPC2294SystemInit(APBDIVISOR); // initialization PLL LPC2194PLLInit(); // Power Control LPC2194PowerControl(); // First disable interrupts. __disable_interrupt(); // Setup interrupt controller. LPC2294InitVIC(); // Enable interrupts. // __enable_interrupt(); // Set up peripheral registers. LPC2294InitPIO();
// Установить усиление 5 GAIN5 CONV_STOP1 STOP_READ1 CONV_STOP2 STOP_READ2
for (;;){ // Loop forever.
for (u16 i = 0; i<1000; i++) { CONV_START CONV_STOP while(BUSY_ADC1 == 1){}; //Ждем Busy START_READ1 dataMB = FIO0PIN0; READ_HIGHBYTE1 dataSB = FIO0PIN0; data[i][0] = dataMB; data[i][0] = data[i][0] | (dataSB << 8);
STOP_READ1 // Чтение со второго канала START_READ2 dataMB = FIO0PIN0; READ_HIGHBYTE2 dataSB = FIO0PIN0; data[i][1] = dataMB; data[i][1] = data[i][1] | (dataSB << 8); // Конец READ_LOWBYTE2 READ_LOWBYTE1 STOP_READ2 }
} }// End Main Так при максимальной оптимизации (в сторону скорости) время между стартами конвертирования 2,5 мкс. а мне надо 2 мкс. Время конвертирования 1,1 мкс. Т.е. на все остальные операции не более 0,9 мкс. К сожелению с асмом тока знаком, но не программировал. Так бы на асме быстрее получилось бы. Или нет? Или может из генерированного файла взять посмотреть? Как можно ускорить? Может буфер сделать не двойным, а четверным? тогда можно будет избавиться от data[i][1] = data[i][1] | (dataSB << 8);
Причина редактирования: Уменьшение видимого размера цитаты исходника.
|
|
|
|
|
Feb 20 2009, 21:54
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(bullit @ Feb 20 2009, 15:07)  Как можно ускорить? Может буфер сделать не двойным, а четверным? тогда можно будет избавиться от data[i][1] = data[i][1] | (dataSB << 8); Вы походу не практиковались в написании оптимизированных прог даже на си. Замечания по проге: 1. CONV_START и CONV_STOP сделаны правильно, а все остальные обращения к FIO неправильно, т.к. при побитовом обращение к ним происходит ненужное чтение. Регистры FIO0SET и FIO0CLR аппаратно сделаны для ускорения работы с портами. В них лучше всего только писать и не читать (ну кроме регистра SET, там отдельная песня). Так что записав в регистр 0х00010000 будет сброшен (или установлен) 16-ый бит в порте, а другие биты не изменятся. 2. Цикл переделайте на обращение к массиву через указатель, с увеличивающимся адресом, а не через индекс по i. Лучше сделать dataMB и dataSB локальными, т.к. неизвестно с какой скоростью будет работать компилятор со статикой. Локальные переменные должны быть размером 32 бита для ускорения работы. Например так: Код u16 *ptr = (u16 *)&data[0];
u32 mb, sb;
for (u16 i = 0; i<1000; i++) { CONV_START CONV_STOP
// перенёс сюда для ускорения READ_LOWBYTE2 READ_LOWBYTE1
while(BUSY_ADC1 == 1){};
START_READ1 mb = FIO0PIN0; READ_HIGHBYTE1 sb = FIO0PIN0; *ptr++ = (mb & 0xff) | (sb << 8); STOP_READ1
START_READ2 mb = FIO0PIN0; READ_HIGHBYTE2 sb = FIO0PIN0; *ptr++ = (mb & 0xff) | (sb << 8); STOP_READ2 } Если это не поможет, то придётся делать на асме.
Сообщение отредактировал GetSmart - Feb 20 2009, 22:08
Причина редактирования: Уменьшение видимого размера цитаты исходника.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Feb 21 2009, 07:42
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(bullit @ Feb 21 2009, 10:39)  А где можно посмотреть в сторону оптимизации кода? В листинге  А длительность инструкций процессора ARM7 в файле arm7tdmi.pdf. Должен лежать где-нибудь в сети. Думаю можно ещё ускорить перенеся CONV_START в конец, сразу после чтения обоих каналов CODE CONV_START CONV_STOP
for (u16 i = 0; i<1000; i++) { READ_LOWBYTE2 READ_LOWBYTE1
while(BUSY_ADC1 == 1){};
START_READ1 mb = FIO0PIN0; READ_HIGHBYTE1 sb = FIO0PIN0; *ptr++ = (mb & 0xff) | (sb << 8); STOP_READ1
START_READ2 mb = FIO0PIN0; READ_HIGHBYTE2 sb = FIO0PIN0; *ptr++ = (mb & 0xff) | (sb << 8); STOP_READ2 CONV_START CONV_STOP }
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|