|
Эффективно и быстро управлять линией порта STM32F407 |
|
|
|
May 21 2014, 03:11
|
Частый гость
 
Группа: Свой
Сообщений: 133
Регистрация: 12-01-05
Из: Украина. Чернигов
Пользователь №: 1 908

|
Мне необходимо быстро менять состояние линии порта (програмно, без таймеров и прочего аппаратного). Пишу кусочек кода для проверки скорости функций управления линией порта portC.13. Код while (1) {
HAL_GPIO_TogglePin(GPIOC, 1 << 13);
} Получаю меандр с частотой порядка 2.4MHz. Это очень медленно. Посмотрел как работает функция и переписал код так: Код while (1) {
GPIOC->ODR ^= 1 << 13; } Получил меандр 8.4 MHz Уже лучше, но все равно очень медленно. Учитывая что ядро летает на скорости 168 MHz. Подскажите пожалуйста как сделать управление эффестивнее и быстрее.
Сообщение отредактировал IgorKossak - May 21 2014, 14:49
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
May 21 2014, 03:24
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(derun @ May 21 2014, 11:21)  Мне необходимо быстро менять состояние линии порта (програмно, без таймеров и прочего аппаратного). Подскажите пожалуйста как сделать управление эффестивнее и быстрее. "Без аппаратного" и "эффективнее и быстрее" два противоречащих понятия. Можете задачу описать подробнее? Код while(1) { GPIOC->BSRR = (1 << 13) << 0; GPIOC->BSRR = (1 << 13) << 16; } Даст Вам максимальную частоту. Включите опримизацию по скорости. Покажите листинг.
|
|
|
|
|
May 21 2014, 04:06
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(adnega @ May 21 2014, 10:34)  Код while(1) { GPIOC->BSRR = (1 << 13) << 0; GPIOC->BSRR = (1 << 13) << 16; } Вариант 2 (какой лучше?): Код while(1) { GPIOC->BSRR = (1 << 13); GPIOC->BRR = (1 << 13); }
|
|
|
|
|
May 21 2014, 04:08
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(scifi @ May 21 2014, 12:06)  Если хочется максимально быстро и именно процессором, то без ассемблера не получится. Всё прекрасно получается и без ассемблера. Код static __inline volatile uint32_t* bb_bit_address(volatile uint32_t* p, uint_fast8_t bit) { return ( (volatile uint32_t*) ( (((uint32_t)p & 0xf0000000UL) | 0x02000000UL) + ((((uint32_t)p & 0x000fffffUL)<<5) | (bit<<2)) ) ); }
#define _PIN_BITBAND_RD_PTR(XPORT, XPIN, ...) bb_bit_address(&GPIO##XPORT->IDR, XPIN) #define _PIN_BITBAND_WR_PTR(XPORT, XPIN, ...) bb_bit_address(&GPIO##XPORT->ODR, XPIN)
#define _PIN_TOGGLE(XPORT, XPIN, ...) do {*_PIN_BITBAND_WR_PTR(XPORT, XPIN) = ~*_PIN_BITBAND_RD_PTR(XPORT, XPIN);} while (0) #define pin_toggle(PIN) _PIN_TOGGLE(PIN) И далее в программе: Код #define PIN_LED_RED B,9,H,OUTPUT_PUSH_PULL,SPEED_10MHZ // можно и 50MHZ, но не особо нужно...
pin_init(PIN_LED_RED);
for(;;) pin_toggle(PIN_LED_RED);
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
May 21 2014, 04:26
|
Частый гость
 
Группа: Свой
Сообщений: 133
Регистрация: 12-01-05
Из: Украина. Чернигов
Пользователь №: 1 908

|
Нужно просто быстро. Порт сконфигурирован на 100 MHz. Попробовал предложенный способ: Код while (1) { GPIOC->BSRRH = (1 << 13); GPIOC->BSRRL = (1 << 13); } Этот вариант работает быстрее получил частоту 14 MHz Думаю этого будет вполне достаточно. Посмотрел код дизассемблером, выглядит прилично думаю врядли смогу его сильно оптимизировать. Спасибо всем за советы и adnega за его вариант решения.
Сообщение отредактировал IgorKossak - May 21 2014, 14:51
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
May 21 2014, 05:00
|
Частый гость
 
Группа: Свой
Сообщений: 133
Регистрация: 12-01-05
Из: Украина. Чернигов
Пользователь №: 1 908

|
Цитата(ViKo @ May 21 2014, 10:54)  12 тактов на весь цикл? Многовато. А листинг покажите. GPIOC->BSRRL = (1 << 13); 080002d8: ldr r3, [pc, #16] ; (0x80002ec <main+116>) 080002da: mov.w r2, #8192 ; 0x2000 080002de: strh r2, [r3, #24] 117 GPIOC->BSRRH = (1 << 13); 080002e0: ldr r3, [pc, #8] ; (0x80002ec <main+116>) 080002e2: mov.w r2, #8192 ; 0x2000 080002e6: strh r2, [r3, #26] 120 } 080002e8: b.n 0x80002d8 <main+96> Как-то так
|
|
|
|
|
May 21 2014, 05:08
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ViKo @ May 21 2014, 13:07)  Потому что в данном случае вы не выиграете ничего. Ну давайте померяемся... Напишите макрос, инвертирующий состояние линии GPIO без BB и посмотрите, что получится... На STM32F103 разница очевидна. Код 8000bb2: 6823 ldr r3, [r4, #0] 8000bb4: ea6f 0203 mvn.w r2, r3 8000bb8: 602a str r2, [r5, #0] 8000bba: e7fa b.n 8000bb2 <Reset_Handler+0xc2> Итого по предварительной оценке 18МГц при тактовой 72МГц.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
May 21 2014, 05:14
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(demiurg_spb @ May 21 2014, 12:18)  Ну давайте померяемся... Напишите макрос, инвертирующий состояние линии GPIO без BB и посмотрите, что получится... На STM32F103 разница очевидна. Давайте по-другому.  Будем не инвертировать предыдущее состояние, а конкретно задавать то 0, то 1. Мой "макрос" уже выдан чуть выше. Отдельно обращу внимание, что в обычном варианте можно одновременно изменить состояние не одного бита, а целой группы. Причем, некоторые можно установить, а некоторые сбросить. Цитата(derun @ May 21 2014, 12:10)  Как-то так А оптимизация не задана?
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|