реклама на сайте
подробности

 
 
6 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> STM32F0 Время реакции и выполнения прерывания
Влад Р.
сообщение Jun 21 2016, 12:40
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Добрый день!

Имеется МК STM32F0. Работает на частоте 48 МГц. Фоновая программа представляет собой пустой бесконечный цикл. По фронту сигнала на выводе МК настроено внешнее прерывание. В обработчике прерывания только операции с портами ввода/вывода и логические операции. Все задействованные выводы сконфигурированы на работу на максимальной скорости.
Согласно статье "A Beginner’s Guide on Interrupt Latency - and Interrupt Latency of the ARM® Cortex®-M processors" время реакции на прерывание для ядра Cortex-M0 составляет 16 машинных циклов. Первой командой после входа в обработчик я считываю один из портов в/в, затем на одном из выводов другого порта устанавливаю высокий уровень. Время между фронтом внешнего сигнала, вызвавшим внешнее прерывание, и установкой высокого уровня на выводе, указанном выше, составляет 800 нс. Почему такое большое время и как можно его сократить?
В той же статье говорится о джиттере времени реакции, но неясно от каких факторов он может зависеть?
Время выполнения обработчика прерывания составило 1,5 мкс, что тоже неожиданно много. Также буду рад советам как уменьшить.

Используется Keil 5.17. Пробовал различные уровни оптимизации компилируемого кода, оптимизацию по времени/объему. Не давало положительных результатов. Размещение обработчика прерывания в ОЗУ позволило сократить время его выполнения на 0,2 мкс, но не повлияло на время реакции на прерывание.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 21 2016, 13:05
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Обращение к портам ввода-вывода тоже время должно занимать, правда, неясно, какова задержка. Кроме того, если используете всякие кубы, халы и прочие библиотеки в обработчике прерывания, будут ещё тормоза от избыточного кода.
Кстати, в Кейле вроде бы есть симулятор, который считает такты (более-менее точно, я надеюсь). Посимулируйте и посмотрите, на что такты расходуются.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 21 2016, 13:14
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Влад Р. @ Jun 21 2016, 18:40) *
Время между фронтом внешнего сигнала, вызвавшим внешнее прерывание, и установкой высокого уровня на выводе, указанном выше, составляет 800 нс. Почему такое большое время и как можно его сократить?
В той же статье говорится о джиттере времени реакции, но неясно от каких факторов он может зависеть?
Время выполнения обработчика прерывания составило 1,5 мкс, что тоже неожиданно много. Также буду рад советам как уменьшить.

Покажите ассемблерный листинг ISR.
Время реакции состоит из:
ожидание завершения очередной команды + сохранение контекста и вход в ISR (видимо эти 16 тактов) + предвыборка кода начала обработчика (уменьшить можно разместив ISR в ОЗУ, посмотрев на матрицу шин; или включив кеш если есть) + PUSH при входе в ISR (листинг?) + задержки доступа к шине, на которой сидит GPIO + ...
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Jun 21 2016, 13:17
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



В статье указано, что 16 машинных циклов пройдёт от прерывания, до выполнения 1 команды прерывания. То есть до входа в прерывание. Сама п/п прерывания, должна сначала сохранить текущий контекст в стеке (текущие регистры) ну и возможно что-то проинициализировать (смотря как вы программу написали), после чего она приступит к выполнению программы пользователя. Учитывая, что 16 тактов это уже 333 нс, то 800 в целом неплохо. Не совсем понятно откуда у вас существенный выигрыш при размещении прерывания в ОЗУ. По моему у вас должно бы 0 циклов ожидания, при такой тактовой.
Ну и 1.5 мкс на выполнение тоже неплохо... )) всё относительно. Еще недавно это было совершенно недостижимо. )))
А в целом если у вас критическое исполнение, причём масштабы на микросекунды, то необходимо использовать аппаратные ресурсы.
Джитер образуется, за счёт того, что некоторые комманды выполняются > одного такта, а также за счёт работы конвеера, на сколько я понимаю.
Go to the top of the page
 
+Quote Post
dimka76
сообщение Jun 21 2016, 13:25
Сообщение #5


developer
****

Группа: Свой
Сообщений: 902
Регистрация: 12-04-06
Из: Казань
Пользователь №: 16 032



Цитата(SasaVitebsk @ Jun 21 2016, 16:17) *
Джитер образуется, за счёт того, что некоторые комманды выполняются > одного такта, а также за счёт работы конвеера, на сколько я понимаю.


На джитер еще будет момент прихода внешнего события, поскольку он не синхронизирован с тактовой МК.


--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 21 2016, 13:44
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(SasaVitebsk @ Jun 21 2016, 19:17) *
существенный выигрыш при размещении прерывания в ОЗУ. По моему у вас должно бы 0 циклов ожидания, при такой тактовой.

Обычно флеш в МК типа Cortex-M работает на частотах около 20МГц, так что 0-wait-states уже не получается.
Плюс ещё - какая ширина шины предвыборки в этом МК? Можно кстати выровнять начало ISR на границу 128бит - может помочь предвыборке.
Go to the top of the page
 
+Quote Post
AlexRayne
сообщение Jun 21 2016, 13:51
Сообщение #7


Местный
***

Группа: Участник
Сообщений: 319
Регистрация: 27-09-07
Пользователь №: 30 877



Цитата(SasaVitebsk @ Jun 21 2016, 16:17) *
В статье указано, что 16 машинных циклов пройдёт от прерывания, до выполнения 1 команды прерывания. То есть до входа в прерывание. Сама п/п прерывания, должна сначала сохранить текущий контекст в стеке (текущие регистры) ну и возможно что-то проинициализировать (смотря как вы программу написали), после чего она приступит к выполнению программы пользователя. Учитывая, что 16 тактов это уже 333 нс, то 800 в целом неплохо. Не совсем понятно откуда у вас существенный выигрыш при размещении прерывания в ОЗУ. По моему у вас должно бы 0 циклов ожидания, при такой тактовой.
Ну и 1.5 мкс на выполнение тоже неплохо... )) всё относительно. Еще недавно это было совершенно недостижимо. )))
А в целом если у вас критическое исполнение, причём масштабы на микросекунды, то необходимо использовать аппаратные ресурсы.
Джитер образуется, за счёт того, что некоторые комманды выполняются > одного такта, а также за счёт работы конвеера, на сколько я понимаю.

+1
время реакции по моему разумению означает время перехода на вектор прерывания. если вы установку порта сделаете прямо на месте вектора - то скорее всего получите ожидаемые такты +-лапоть.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 21 2016, 13:57
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(AlexRayne @ Jun 21 2016, 19:51) *
время реакции по моему разумению означает время перехода на вектор прерывания. если вы установку порта сделаете прямо на месте вектора - то скорее всего получите ожидаемые такты +-лапоть.

Объясните как это сделать, когда в Cortex-M по вектору прерывания находится не код, а адрес точки входа в ISR???

ЗЫ: Кстати вот не учли - время выборки вектора из таблицы векторов прерываний. Которая у автора наверное тоже во флешь находится. Можно её тож в ОЗУ перетащить.
Go to the top of the page
 
+Quote Post
AlexRayne
сообщение Jun 21 2016, 15:01
Сообщение #9


Местный
***

Группа: Участник
Сообщений: 319
Регистрация: 27-09-07
Пользователь №: 30 877



Цитата(jcxz @ Jun 21 2016, 16:57) *
Объясните как это сделать, когда в Cortex-M по вектору прерывания находится не код, а адрес точки входа в ISR???

ЗЫ: Кстати вот не учли - время выборки вектора из таблицы векторов прерываний. Которая у автора наверное тоже во флешь находится. Можно её тож в ОЗУ перетащить.

чтобы это сделать надо пилить стартап, и ассемблерный код наверняка. этот вопрос к специалистам по арм, я в нем с векторами не заморачивался. если вам настолько критична реакция на прерывание, то действительно стоит подумать над аппаратной реализацией того что вам надо. посмотрите на вашу периферию - может таймеры, или мультиплексор внутреней шины могут сделать то что вам надо сами?
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 21 2016, 15:58
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(AlexRayne @ Jun 21 2016, 21:01) *
чтобы это сделать надо пилить стартап, и ассемблерный код наверняка. этот вопрос к специалистам по арм, я в нем с векторами не заморачивался.

Хоть совсем его распилите - код там расположить не сможете. sm.gif Курите доку на ядро.

Цитата(AlexRayne @ Jun 21 2016, 21:01) *
если вам настолько критична реакция на прерывание, то действительно стоит подумать над аппаратной реализацией того что вам надо. посмотрите на вашу периферию - может таймеры, или мультиплексор внутреней шины могут сделать то что вам надо сами?

Мне не критична, у меня всё нормально. Вопрос задавал не я.

2ТС: Вынесите таблицу векторов прерываний в ОЗУ, напишите ISR на асм и вынесите его в ОЗУ, выровняйте его начало. По периферии ничего не подскажу.
Go to the top of the page
 
+Quote Post
RadiatoR
сообщение Jun 21 2016, 16:25
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 270
Регистрация: 8-08-15
Из: Москва
Пользователь №: 87 901



Цитата(jcxz @ Jun 21 2016, 16:57) *
ЗЫ: Кстати вот не учли - время выборки вектора из таблицы векторов прерываний. Которая у автора наверное тоже во флешь находится. М


А разве там не сквозная адресация идет на прерывание и cpu не обрабатывает взятие адреса функции прерывания? Разве по событию не рубится конвейер и не загружается этот адрес в pc?

А по теме - если у ТС такое требовательное к времени приложение (которое посилам мк), то может этот кусочек на асме написать? Уж тем более если присутствуют всякие HAL...
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 21 2016, 19:39
Сообщение #12


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(scifi @ Jun 21 2016, 16:05) *
Кроме того, если используете всякие кубы, халы и прочие библиотеки в обработчике прерывания, будут ещё тормоза от избыточного кода.

Библиотеки, кроме ASM-файла инициализации и CMSIS не использую. Код самописный.

Цитата(jcxz @ Jun 21 2016, 16:14) *
Покажите ассемблерный листинг ISR.
Время реакции состоит из:
ожидание завершения очередной команды + сохранение контекста и вход в ISR (видимо эти 16 тактов) + предвыборка кода начала обработчика (уменьшить можно разместив ISR в ОЗУ, посмотрев на матрицу шин; или включив кеш если есть) + PUSH при входе в ISR (листинг?)

Что подразумевается под сохранением контекста? Я думал, это и есть стэкирование РОН (PUSH) и, что оно включено в те самые 16 тактов.
На сколько я знаю, кэша в этих МК нет. Может ли влиять Prefetch Buffer (сейчас включен)?
Вот листинг на Си:
CODE
void EXTI4_15_IRQHandler(void)
{
uint16_t db = GPIOC->IDR & 0x1FFF;
uint8_t data = db;

if (!(db & (0x01 << 12))) {
switch (db & (0x03 << 9)) {
case 0x0000:
GPIOA->ODR = (GPIOA->ODR & ~0xFF) | data;
break;
case 0x0200:
GPIOB->ODR = (GPIOB->ODR & ~(0x03 << 5)) | (data & (0x03 << 5));
break;
case 0x0400:
GPIOA->ODR = (GPIOA->ODR & ~(0x0F << 8)) | ((uint16_t)HINIBBLE(data) << 8);
GPIOB->ODR = (GPIOB->ODR & ~(0x0F << 8)) | ((uint16_t)LONIBBLE(data) << 8);
break;
case 0x0600:
if (db & (0x01 << 4))
GPIOA->MODER &= ~(GPIO_MODER_MODER0 | GPIO_MODER_MODER1 | GPIO_MODER_MODER2 | GPIO_MODER_MODER3 |
GPIO_MODER_MODER4 | GPIO_MODER_MODER5 | GPIO_MODER_MODER6 | GPIO_MODER_MODER7);
else
GPIOA->MODER |= GPIO_MODER_MODER0_0 | GPIO_MODER_MODER1_0 | GPIO_MODER_MODER2_0 | GPIO_MODER_MODER3_0 |
GPIO_MODER_MODER4_0 | GPIO_MODER_MODER5_0 | GPIO_MODER_MODER6_0 | GPIO_MODER_MODER7_0;
if (db & (0x01 << 3))
GPIOA->MODER &= ~(GPIO_MODER_MODER8 | GPIO_MODER_MODER9 | GPIO_MODER_MODER10 | GPIO_MODER_MODER11);
else
GPIOA->MODER |= GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0 | GPIO_MODER_MODER10_0 | GPIO_MODER_MODER11_0;
if (db & (0x01 << 1))
GPIOB->MODER &= ~(GPIO_MODER_MODER5 | GPIO_MODER_MODER6);
else
GPIOB->MODER |= GPIO_MODER_MODER5_0 | GPIO_MODER_MODER6_0;
if (db & 0x01)
GPIOB->MODER &= ~(GPIO_MODER_MODER8 | GPIO_MODER_MODER9 | GPIO_MODER_MODER10 | GPIO_MODER_MODER11);
else
GPIOB->MODER |= GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0 | GPIO_MODER_MODER10_0 | GPIO_MODER_MODER11;
break;
}
}
EXTI->PR = EXTI_PR_PR8;
}


Вот дизассемблер:
CODE
61: {
0x08000240 B430 PUSH {r4-r5}
62: uint16_t db = GPIOC->IDR & 0x1FFF;
0x08000242 4831 LDR r0,[pc,#196] ; @0x08000308
0x08000244 8A00 LDRH r0,[r0,#0x10]
0x08000246 04C0 LSLS r0,r0,#19
0x08000248 0CC0 LSRS r0,r0,#19
63: uint8_t data = db;
64:
0x0800024A B2C1 UXTB r1,r0
65: if (!(db & (0x01 << 12))) {
0x0800024C 04C2 LSLS r2,r0,#19
61: {
62: uint16_t db = GPIOC->IDR & 0x1FFF;
63: uint8_t data = db;
64:
65: if (!(db & (0x01 << 12))) {
0x0800024E D455 BMI 0x080002FC
66: switch (db & (0x03 << 9)) {
67: case 0x0000:
0x08000250 2203 MOVS r2,#0x03
0x08000252 0252 LSLS r2,r2,#9
68: GPIOA->ODR = (GPIOA->ODR & ~0xFF) | data;
69: break;
70: case 0x0200:
0x08000254 4B2D LDR r3,[pc,#180] ; @0x0800030C
0x08000256 4002 ANDS r2,r2,r0
0x08000258 D00D BEQ 0x08000276
71: GPIOB->ODR = (GPIOB->ODR & ~(0x03 << 5)) | (data & (0x03 << 5));
0x0800025A 3AFF SUBS r2,r2,#0xFF
0x0800025C 4C2C LDR r4,[pc,#176] ; @0x08000310
0x0800025E 3AFF SUBS r2,r2,#0xFF
0x08000260 1E92 SUBS r2,r2,#2
0x08000262 D00E BEQ 0x08000282
0x08000264 3AFF SUBS r2,r2,#0xFF
0x08000266 3AFF SUBS r2,r2,#0xFF
0x08000268 1E92 SUBS r2,r2,#2
0x0800026A D011 BEQ 0x08000290
0x0800026C 3AFF SUBS r2,r2,#0xFF
0x0800026E 3AFF SUBS r2,r2,#0xFF
0x08000270 2A02 CMP r2,#0x02
0x08000272 D143 BNE 0x080002FC
0x08000274 E01B B 0x080002AE
0x08000276 8A98 LDRH r0,[r3,#0x14]
0x08000278 0A00 LSRS r0,r0,#8
0x0800027A 0200 LSLS r0,r0,#8
0x0800027C 4308 ORRS r0,r0,r1
0x0800027E 8298 STRH r0,[r3,#0x14]
69: break;
70: case 0x0200:
71: GPIOB->ODR = (GPIOB->ODR & ~(0x03 << 5)) | (data & (0x03 << 5));
0x08000280 E03C B 0x080002FC
0x08000282 8AA0 LDRH r0,[r4,#0x14]
0x08000284 2260 MOVS r2,#0x60
0x08000286 4390 BICS r0,r0,r2
0x08000288 4011 ANDS r1,r1,r2
0x0800028A 4308 ORRS r0,r0,r1
0x0800028C 82A0 STRH r0,[r4,#0x14]
72: break;
73: case 0x0400:
0x0800028E E035 B 0x080002FC
74: GPIOA->ODR = (GPIOA->ODR & ~(0x0F << 8)) | ((uint16_t)HINIBBLE(data) << 8);
0x08000290 8A9A LDRH r2,[r3,#0x14]
0x08000292 200F MOVS r0,#0x0F
0x08000294 0200 LSLS r0,r0,#8
0x08000296 090D LSRS r5,r1,#4
0x08000298 4382 BICS r2,r2,r0
0x0800029A 022D LSLS r5,r5,#8
0x0800029C 432A ORRS r2,r2,r5
0x0800029E 829A STRH r2,[r3,#0x14]
75: GPIOB->ODR = (GPIOB->ODR & ~(0x0F << 8)) | ((uint16_t)LONIBBLE(data) << 8);
0x080002A0 8AA2 LDRH r2,[r4,#0x14]
0x080002A2 4382 BICS r2,r2,r0
0x080002A4 0708 LSLS r0,r1,#28
0x080002A6 0D00 LSRS r0,r0,#20
0x080002A8 4302 ORRS r2,r2,r0
0x080002AA 82A2 STRH r2,[r4,#0x14]
76: break;
77: case 0x0600:
0x080002AC E026 B 0x080002FC
78: if (db & (0x01 << 4))
79: GPIOA->MODER &= ~(GPIO_MODER_MODER0 | GPIO_MODER_MODER1 | GPIO_MODER_MODER2 | GPIO_MODER_MODER3 |
80: GPIO_MODER_MODER4 | GPIO_MODER_MODER5 | GPIO_MODER_MODER6 | GPIO_MODER_MODER7);
81: else
0x080002AE 06C1 LSLS r1,r0,#27
82: GPIOA->MODER |= GPIO_MODER_MODER0_0 | GPIO_MODER_MODER1_0 | GPIO_MODER_MODER2_0 | GPIO_MODER_MODER3_0 |
83: GPIO_MODER_MODER4_0 | GPIO_MODER_MODER5_0 | GPIO_MODER_MODER6_0 | GPIO_MODER_MODER7_0;
0x080002B0 6819 LDR r1,[r3,#0x00]
0x080002B2 D502 BPL 0x080002BA
79: GPIOA->MODER &= ~(GPIO_MODER_MODER0 | GPIO_MODER_MODER1 | GPIO_MODER_MODER2 | GPIO_MODER_MODER3 |
80: GPIO_MODER_MODER4 | GPIO_MODER_MODER5 | GPIO_MODER_MODER6 | GPIO_MODER_MODER7);
81: else
82: GPIOA->MODER |= GPIO_MODER_MODER0_0 | GPIO_MODER_MODER1_0 | GPIO_MODER_MODER2_0 | GPIO_MODER_MODER3_0 |
83: GPIO_MODER_MODER4_0 | GPIO_MODER_MODER5_0 | GPIO_MODER_MODER6_0 | GPIO_MODER_MODER7_0;
0x080002B4 0C09 LSRS r1,r1,#16
0x080002B6 0409 LSLS r1,r1,#16
0x080002B8 E001 B 0x080002BE
0x080002BA 4A16 LDR r2,[pc,#88] ; @0x08000314
0x080002BC 4311 ORRS r1,r1,r2
0x080002BE 6019 STR r1,[r3,#0x00]
84: if (db & (0x01 << 3))
0x080002C0 0702 LSLS r2,r0,#28
85: GPIOA->MODER &= ~(GPIO_MODER_MODER8 | GPIO_MODER_MODER9 | GPIO_MODER_MODER10 | GPIO_MODER_MODER11);
86: else
0x080002C2 4915 LDR r1,[pc,#84] ; @0x08000318
87: GPIOA->MODER |= GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0 | GPIO_MODER_MODER10_0 | GPIO_MODER_MODER11_0;
0x080002C4 681A LDR r2,[r3,#0x00]
0x080002C6 D501 BPL 0x080002CC
0x080002C8 438A BICS r2,r2,r1
0x080002CA E002 B 0x080002D2
0x080002CC 2555 MOVS r5,#0x55
0x080002CE 042D LSLS r5,r5,#16
0x080002D0 432A ORRS r2,r2,r5
0x080002D2 601A STR r2,[r3,#0x00]
88: if (db & (0x01 << 1))
89: GPIOB->MODER &= ~(GPIO_MODER_MODER5 | GPIO_MODER_MODER6);
90: else
0x080002D4 0782 LSLS r2,r0,#30
91: GPIOB->MODER |= GPIO_MODER_MODER5_0 | GPIO_MODER_MODER6_0;
0x080002D6 6822 LDR r2,[r4,#0x00]
0x080002D8 D503 BPL 0x080002E2
89: GPIOB->MODER &= ~(GPIO_MODER_MODER5 | GPIO_MODER_MODER6);
90: else
91: GPIOB->MODER |= GPIO_MODER_MODER5_0 | GPIO_MODER_MODER6_0;
0x080002DA 230F MOVS r3,#0x0F
0x080002DC 029B LSLS r3,r3,#10
0x080002DE 439A BICS r2,r2,r3
0x080002E0 E002 B 0x080002E8
0x080002E2 2305 MOVS r3,#0x05
0x080002E4 029B LSLS r3,r3,#10
0x080002E6 431A ORRS r2,r2,r3
0x080002E8 6022 STR r2,[r4,#0x00]
92: if (db & 0x01)
93: GPIOB->MODER &= ~(GPIO_MODER_MODER8 | GPIO_MODER_MODER9 | GPIO_MODER_MODER10 | GPIO_MODER_MODER11);
94: else
0x080002EA 07C0 LSLS r0,r0,#31
95: GPIOB->MODER |= GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0 | GPIO_MODER_MODER10_0 | GPIO_MODER_MODER11;
96: break;
97: }
98: }
0x080002EC 6820 LDR r0,[r4,#0x00]
0x080002EE D001 BEQ 0x080002F4
93: GPIOB->MODER &= ~(GPIO_MODER_MODER8 | GPIO_MODER_MODER9 | GPIO_MODER_MODER10 | GPIO_MODER_MODER11);
94: else
95: GPIOB->MODER |= GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0 | GPIO_MODER_MODER10_0 | GPIO_MODER_MODER11;
96: break;
97: }
98: }
0x080002F0 4388 BICS r0,r0,r1
0x080002F2 E002 B 0x080002FA
0x080002F4 21D5 MOVS r1,#0xD5
0x080002F6 0409 LSLS r1,r1,#16
0x080002F8 4308 ORRS r0,r0,r1
0x080002FA 6020 STR r0,[r4,#0x00]
99: EXTI->PR = EXTI_PR_PR8;
0x080002FC 20FF MOVS r0,#0xFF
0x080002FE 4907 LDR r1,[pc,#28] ; @0x0800031C
0x08000300 3001 ADDS r0,r0,#0x01
0x08000302 6148 STR r0,[r1,#0x14]
100: }
0x08000304 BC30 POP {r4-r5}
0x08000306 4770 BX lr
0x08000308 0800 DCW 0x0800
0x0800030A 4800 DCW 0x4800
0x0800030C 0000 DCW 0x0000
0x0800030E 4800 DCW 0x4800
0x08000310 0400 DCW 0x0400
0x08000312 4800 DCW 0x4800
0x08000314 5555 DCW 0x5555
0x08000316 0000 DCW 0x0000
0x08000318 0000 DCW 0x0000
0x0800031A 00FF DCW 0x00FF
0x0800031C 0400 DCW 0x0400
0x0800031E 4001 DCW 0x4001


Цитата(jcxz @ Jun 21 2016, 16:57) *
Которая у автора наверное тоже во флешь находится. Можно её тож в ОЗУ перетащить.

Подтверждаю, сейчас вектора размещаются дефолтно, т.е. во флэше.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 22 2016, 05:16
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Влад Р. @ Jun 22 2016, 01:39) *
Что подразумевается под сохранением контекста? Я думал, это и есть стэкирование РОН (PUSH) и, что оно включено в те самые 16 тактов.
На сколько я знаю, кэша в этих МК нет. Может ли влиять Prefetch Buffer (сейчас включен)?

Именно оно и подразумевается.
Буфер предвыборки должен выбрать из памяти начало ISR перед их выполнением.

Ну а чего-ж Вы хотите??? У Вас от входа в ISR до установки пина такая куча команд выполняется:
CODE
0x08000240 B430 PUSH {r4-r5}
62: uint16_t db = GPIOC->IDR & 0x1FFF;
0x08000242 4831 LDR r0,[pc,#196] ; @0x08000308
0x08000244 8A00 LDRH r0,[r0,#0x10]
0x08000246 04C0 LSLS r0,r0,#19
0x08000248 0CC0 LSRS r0,r0,#19
63: uint8_t data = db;
64:
0x0800024A B2C1 UXTB r1,r0
65: if (!(db & (0x01 << 12))) {
0x0800024C 04C2 LSLS r2,r0,#19
61: {
62: uint16_t db = GPIOC->IDR & 0x1FFF;
63: uint8_t data = db;
64:
65: if (!(db & (0x01 << 12))) {
0x0800024E D455 BMI 0x080002FC
66: switch (db & (0x03 << 9)) {
67: case 0x0000:
0x08000250 2203 MOVS r2,#0x03
0x08000252 0252 LSLS r2,r2,#9
68: GPIOA->ODR = (GPIOA->ODR & ~0xFF) | data;
69: break;
70: case 0x0200:
0x08000254 4B2D LDR r3,[pc,#180] ; @0x0800030C
0x08000256 4002 ANDS r2,r2,r0
0x08000258 D00D BEQ 0x08000276
71: GPIOB->ODR = (GPIOB->ODR & ~(0x03 << 5)) | (data & (0x03 << 5));
0x0800025A 3AFF SUBS r2,r2,#0xFF
0x0800025C 4C2C LDR r4,[pc,#176] ; @0x08000310
0x0800025E 3AFF SUBS r2,r2,#0xFF
0x08000260 1E92 SUBS r2,r2,#2
0x08000262 D00E BEQ 0x08000282
0x08000264 3AFF SUBS r2,r2,#0xFF
0x08000266 3AFF SUBS r2,r2,#0xFF
0x08000268 1E92 SUBS r2,r2,#2
0x0800026A D011 BEQ 0x08000290
0x0800026C 3AFF SUBS r2,r2,#0xFF
0x0800026E 3AFF SUBS r2,r2,#0xFF
0x08000270 2A02 CMP r2,#0x02
0x08000272 D143 BNE 0x080002FC
0x08000274 E01B B 0x080002AE
...
0x080002AE 06C1 LSLS r1,r0,#27
82: GPIOA->MODER |= GPIO_MODER_MODER0_0 | GPIO_MODER_MODER1_0 | GPIO_MODER_MODER2_0 | GPIO_MODER_MODER3_0 |
83: GPIO_MODER_MODER4_0 | GPIO_MODER_MODER5_0 | GPIO_MODER_MODER6_0 | GPIO_MODER_MODER7_0;
0x080002B0 6819 LDR r1,[r3,#0x00]
0x080002B2 D502 BPL 0x080002BA
79: GPIOA->MODER &= ~(GPIO_MODER_MODER0 | GPIO_MODER_MODER1 | GPIO_MODER_MODER2 | GPIO_MODER_MODER3 |
80: GPIO_MODER_MODER4 | GPIO_MODER_MODER5 | GPIO_MODER_MODER6 | GPIO_MODER_MODER7);
81: else
82: GPIOA->MODER |= GPIO_MODER_MODER0_0 | GPIO_MODER_MODER1_0 | GPIO_MODER_MODER2_0 | GPIO_MODER_MODER3_0 |
83: GPIO_MODER_MODER4_0 | GPIO_MODER_MODER5_0 | GPIO_MODER_MODER6_0 | GPIO_MODER_MODER7_0;
0x080002B4 0C09 LSRS r1,r1,#16
0x080002B6 0409 LSLS r1,r1,#16
0x080002B8 E001 B 0x080002BE
0x080002BA 4A16 LDR r2,[pc,#88] ; @0x08000314
0x080002BC 4311 ORRS r1,r1,r2
0x080002BE 6019 STR r1,[r3,#0x00]


Хотя-бы под отладчиком прошлись бы по командам и посмотрели сколько команд.
Если нужно такое время реакции - пишите на асм. Ну или аппаратно.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 22 2016, 05:35
Сообщение #14


Универсальный солдатик
******

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



Измените переменные на 32-битовые. Везде, где можно.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Jun 22 2016, 05:49
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(jcxz @ Jun 21 2016, 16:44) *
Обычно флеш в МК типа Cortex-M работает на частотах около 20МГц, так что 0-wait-states уже не получается.
Плюс ещё - какая ширина шины предвыборки в этом МК? Можно кстати выровнять начало ISR на границу 128бит - может помочь предвыборке.

Да посмотрел, там 0 ws до 24МГц и 1ws выше. Ширина шины флэш 32 бита всего, правда есть prefetch bufer небольшой... В целом достаточно убого, по ускорению выборки.
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 22 2016, 06:13
Сообщение #16


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(jcxz @ Jun 22 2016, 08:16) *
Ну а чего-ж Вы хотите??? У Вас от входа в ISR до установки пина такая куча команд выполняется:


Прошу прощения. Установка пина выполнялась исключительно для того, чтобы понять сколько времени занимает вход в прерывание и первое считывание порта. В выложенном листинге ее нет. Было примерно так:
Код
void EXTI4_15_IRQHandler(void)
{
  uint16_t db = GPIOC->IDR & 0x1FFF;
  uint8_t data;
  
  GPIOB->BSRR = GPIO_BSRR_BS_12;
  
  data = db;
  ...
}
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 22 2016, 06:28
Сообщение #17


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(SasaVitebsk @ Jun 22 2016, 11:49) *
Да посмотрел, там 0 ws до 24МГц и 1ws выше. Ширина шины флэш 32 бита всего, правда есть prefetch bufer небольшой... В целом достаточно убого, по ускорению выборки.

Ну вот, а это означает, что хоть и установлена 48МГц, но код, состоящий из последовательности 4-байтовых команд, будет выполняться со скоростью 24MIPS. Так что перенос в ОЗУ должен помочь.
Если будет поток из одних 4-байтовых команд, то prefetch buffer никак не поможет. Хотя у ТС в данном случае команды в основном 2-байтные.

Цитата(Влад Р. @ Jun 22 2016, 12:13) *
Прошу прощения. Установка пина выполнялась исключительно для того, чтобы понять сколько времени занимает вход в прерывание и первое считывание порта. В выложенном листинге ее нет. Было примерно uint16_t db = GPIOC->IDR & 0x1FFF;
uint8_t data;
GPIOB->BSRR = GPIO_BSRR_BS_12;
data = db;

А теперь посмотрите листинг - сколько там команд, просуммируйте со временем стекинга и прочими временами. Как раз и получите, что имеете.
Как уже Вам советовали - не стоит использовать 8-и и 16-битные переменные где ни попадя на 32-битном CPU. Это приводит к лишним командам в коде.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 22 2016, 06:39
Сообщение #18


Универсальный солдатик
******

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



Цитата(jcxz @ Jun 22 2016, 09:28) *
Хотя у ТС в данном случае команды в основном 2-байтные.

Ага. Все! biggrin.gif И неспроста.
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 22 2016, 06:42
Сообщение #19


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(jcxz @ Jun 22 2016, 09:28) *
А теперь посмотрите листинг - сколько там команд, просуммируйте со временем стекинга и прочими временами. Как раз и получите, что имеете.
Как уже Вам советовали - не стоит использовать 8-и и 16-битные переменные где ни попадя на 32-битном CPU. Это приводит к лишним командам в коде.


Можно ли как-то отключить стекинг РОН или это делается аппаратно? К примеру, не использовать РОН в обработчике прерывания.
Не понятно, включено ли время стекинга (PUSH) во время Interrupt Latency (16 циклов)?
Переменные заменил на intы, обработчик положил в ОЗУ.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 22 2016, 06:45
Сообщение #20


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Влад Р. @ Jun 22 2016, 12:42) *
Можно ли как-то отключить стекинг РОН или это делается аппаратно?

нельзя.

Цитата(Влад Р. @ Jun 22 2016, 12:42) *
К примеру, не использовать РОН в обработчике прерывания.

Можно избавиться от PUSH, написав ISR на асме.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 22 2016, 06:55
Сообщение #21


Универсальный солдатик
******

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



Цитата(Влад Р. @ Jun 22 2016, 09:42) *
Не понятно, включено ли время стекинга (PUSH) во время Interrupt Latency (16 циклов)?

Включено. Иначе, что бы там делалось целых 16 тактов?
Читайте Джозефа Ю.
Цитата
When an exception is accepted on the Cortex-M0 processor, some of the registers in the
register banks (R0 to R3, R12, R14), the return address (PC), and the Program Status Register
(xPSR) are pushed to the current active stack memory automatically.

Если ограничить количество переменных, можно уложиться в те регистры, что сохраняются аппаратно.
Компилятор сам лишних регистров не сохраняет. Я так думаю.
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 22 2016, 07:16
Сообщение #22


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(ViKo @ Jun 22 2016, 09:55) *
Включено. Иначе, что бы там делалось целых 16 тактов?

Если ограничить количество переменных, можно уложиться в те регистры, что сохраняются аппаратно.
Компилятор сам лишних регистров не сохраняет. Я так думаю.


Это бы много объяснило. Часть регистров помещается в стек аппаратно и отключить это невозможно. Время за которое это происходит составляет минимальное время реакции на прерывание (Interrupt Latency - 16 cycles).
PUSH в начале обработчика помещает дополнительно еще парочку РОН и от этого можно уйти, написав обработчик на асме.

Цитата(ViKo @ Jun 22 2016, 09:39) *
Ага. Все! biggrin.gif И неспроста.

Поясните, пожалуйста.
Go to the top of the page
 
+Quote Post
HHIMERA
сообщение Jun 22 2016, 07:55
Сообщение #23


Местный
***

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



Цитата(Влад Р. @ Jun 22 2016, 10:16) *
Это бы

А в чём сыр-бор??? Чего добиться то хотите???
Go to the top of the page
 
+Quote Post
Obam
сообщение Jun 22 2016, 07:57
Сообщение #24


Знающий
****

Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663



Цитата(Влад Р. @ Jun 22 2016, 11:16) *
PUSH в начале обработчика помещает дополнительно еще парочку РОН и от этого можно уйти, написав обработчик на асме.


Можно, если использовать только R0 - R3, R12, а в случае дополнительной нужды в регистрах (не забываем - RISC - все действия только с регистрами, кроме загрузки-выгрузки)
без PUSH/POP не обойтись.
И кстати, bitbanding по регистрам периферии может помочь уменьшить число команд.


--------------------
Пролетарий умственного труда.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 22 2016, 08:04
Сообщение #25


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Obam @ Jun 22 2016, 13:57) *
И кстати, bitbanding по регистрам периферии может помочь уменьшить число команд.

Или наоборот - увеличить wink.gif
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 22 2016, 08:07
Сообщение #26


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Obam @ Jun 22 2016, 10:57) *
И кстати, bitbanding по регистрам периферии может помочь уменьшить число команд.

Мысль, конечно, интересная, но у STM32F0 этой фичи нет.
Go to the top of the page
 
+Quote Post
Obam
сообщение Jun 22 2016, 08:24
Сообщение #27


Знающий
****

Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663



Цитата(scifi @ Jun 22 2016, 12:07) *
Мысль, конечно, интересная, но у STM32F0 этой фичи нет.


Cortex-M0, тогда да, пардону просим. Всё время упускаю, что есть ARMv6

Цитата(jcxz @ Jun 22 2016, 12:04) *
Или наоборот - увеличить wink.gif


Личный опыт показывает, что число команд R-M-W уменьшается wink.gif


--------------------
Пролетарий умственного труда.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 22 2016, 08:51
Сообщение #28


Универсальный солдатик
******

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



Цитата(Влад Р. @ Jun 22 2016, 10:16) *
Поясните, пожалуйста.

Я так понимаю, ARM стремилась в Cortex-M0 использовать преимущественно 16-битовые команды, ради экономии памяти.

Цитата(Влад Р. @ Jun 22 2016, 10:16) *
PUSH в начале обработчика помещает дополнительно еще парочку РОН и от этого можно уйти, написав обработчик на асме.

Попробуйте сделать что-то совсем простое, инвертировать бит, например. И без asm ненужные регистры в стек запихиваться не будут.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 22 2016, 08:51
Сообщение #29


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Obam @ Jun 22 2016, 11:13) *
Cortex-M0, тогда да, пардону просим. Всё время упускаю, что есть ARMv6

Вы будете смеяться, но Cortex-M0 и ARMv6 тут совершенно ни чём.
Bit-banding - это опция на процессорах M0, M3 и M4. Так уж получилось, что она чаще встречается у M3 и M4, чем у M0. См. тут.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 22 2016, 09:03
Сообщение #30


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Obam @ Jun 22 2016, 14:24) *
Личный опыт показывает, что число команд R-M-W уменьшается wink.gif

Если код типа:
u32 i = GPIOC->IDR & 0x1FFF;
*BITBAND_IO(&GPIOC->ODR, bitX) = 1;
то может увеличиться, так как народ часто использует команды RMW там где они реально не нужны (а периферия GPIO во многих МК как правило имеет регистры позволяющие установку/сброс отдельных битов просто командами записи, а не чтения-модификации-записи). А обращение к региону bitband требует дополнительной загрузки указателя на него.
К тому же например IAR почему-то плохо компилит код с обращением к битбанд-области - получается куча лишних команд даже при полной оптимизации. sad.gif((

Цитата(ViKo @ Jun 22 2016, 14:51) *
Я так понимаю, ARM стремилась в Cortex-M0 использовать преимущественно 16-битовые команды, ради экономии памяти.

Не правильно пояснили sm.gif
Потому, что в коде из листинга используются регистры R0-R7 и только простые режимы адресации (без автоинкрементов, длинных смещений и т.п.) и формы команд влияющие на флаги (MOVS, LSLS, ...) и т.п.
Поэтому все команды короткие.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 22 2016, 09:21
Сообщение #31


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Может крамолу скажу, но если основной цикл пустой, то зачем использовать прерывание? В основном цикле все и делать, а события ждать по WFI/WFE. Сэкономится время на переход по вектору и на сохранение контекста, а также подготовительные операции компилятор может вставить перед WFI/WFE...


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 22 2016, 09:41
Сообщение #32


Универсальный солдатик
******

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



Цитата(jcxz @ Jun 22 2016, 12:03) *
Не правильно пояснили sm.gif
Потому, что в коде из листинга используются регистры R0-R7 и только простые режимы адресации (без автоинкрементов, длинных смещений и т.п.) и формы команд влияющие на флаги (MOVS, LSLS, ...) и т.п.
Поэтому все команды короткие.

Открываем книгу The Definitive Guide to ARM® Cortex®-M0 and Cortex-M0+ Processors, Second Edition
на стр 10, смотрим рис. 1.4 с командами, и восхищаемся, что 32-битовых команд у Cortex-M0/M0+/M1 всего 6. rolleyes.gif Причем, без разницы, старшие или младшие регистры используются.

(номер поправил)

Цитата
If we look at the instruction set in a bit more details (Figure 1.4), we can see that the
Cortex-M0, Cortex-M0ю, and Cortex-M1 processors only support a small instruction set
(56 instructions). Most of these instructions are 16 bit, thus provide a very good code
density - which means it need a smaller program memory require for the same task
compared to many architecture.
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 22 2016, 09:51
Сообщение #33


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(Сергей Борщ @ Jun 22 2016, 12:21) *
Может крамолу скажу, но если основной цикл пустой, то зачем использовать прерывание? В основном цикле все и делать, а события ждать по WFI/WFE. Сэкономится время на переход по вектору и на сохранение контекста, а также подготовительные операции компилятор может вставить перед WFI/WFE...



Сейчас необходимо добиться минимального времени срабатывания. В дальнейшем программа будет разрастаться и будут добавлены другие прерывания, а в основном цикле будут добавлены другие действия.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 22 2016, 09:51
Сообщение #34


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(ViKo @ Jun 22 2016, 12:41) *
Открываем книгу The Definitive Guide to ARM® Cortex®-M0 and Cortex-M0+ Processors, Second Edition

На каком языке написано? На олбанском китайско-английском? Ржака biggrin.gif
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 22 2016, 10:05
Сообщение #35


Универсальный солдатик
******

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



Цитата(scifi @ Jun 22 2016, 12:51) *
На каком языке написано? На олбанском китайско-английском? Ржака biggrin.gif

Википедия лучше? Прикрепленное изображение
Go to the top of the page
 
+Quote Post
Obam
сообщение Jun 22 2016, 12:12
Сообщение #36


Знающий
****

Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663



Цитата(scifi @ Jun 22 2016, 12:51) *
Вы будете смеяться, но Cortex-M0 и ARMv6 тут совершенно ни чём.
Bit-banding - это опция на процессорах M0, M3 и M4. Так уж получилось, что она чаще встречается у M3 и M4, чем у M0. См. тут.


Смеяться я не стану, но в ARM DDI 0484B (TechRefManual на v6) на Bit-banding даже намёка нет.


--------------------
Пролетарий умственного труда.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 22 2016, 12:54
Сообщение #37


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Obam @ Jun 22 2016, 15:12) *
Смеяться я не стану, но в ARM DDI 0484B (TechRefManual на v6) на Bit-banding даже намёка нет.

Ну, значит мне показалось: AHB bit-band wrapper for Cortex-M0 processor.
Go to the top of the page
 
+Quote Post
Obam
сообщение Jun 22 2016, 14:37
Сообщение #38


Знающий
****

Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663



Цитата(scifi @ Jun 22 2016, 16:54) *
Ну, значит мне показалось: AHB bit-band wrapper for Cortex-M0 processor.


Смайлики не надо забывать: вы использовали Technical Reference Manual (TRM) for the Cortex-M System Design Kit, я для Cortex-M0+.


--------------------
Пролетарий умственного труда.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 22 2016, 17:08
Сообщение #39


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Obam @ Jun 22 2016, 17:37) *
Смайлики не надо забывать: вы использовали Technical Reference Manual (TRM) for the Cortex-M System Design Kit, я для Cortex-M0+.

Слив защщитан biggrin.gif
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 22 2016, 18:03
Сообщение #40


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Цитата(scifi @ Jun 22 2016, 12:51) *
Bit-banding - это опция на процессорах M0, M3 и M4. Так уж получилось, что она чаще встречается у M3 и M4, чем у M0.

Можете огласить список СМ0 с этой опцией?


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 22 2016, 18:08
Сообщение #41


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(GetSmart @ Jun 22 2016, 21:03) *
Можете огласить список СМ0 с этой опцией?

Увы, не могу. Лицензиаты арма передо мной не отчитываются crying.gif
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 22 2016, 18:19
Сообщение #42


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Те же лицензиаты издавали рекламные обзоры, из которых следовало, что Bit-banding в СМ0 нет и не ожидается (без намёков). Точнее, подчеркивали что эта фича характерна для СМ3 и выше. И, как уже сказано, её не было в описании ARMv6-М от самого АРМа. В Architecture Reference Manual на какое-то ядро обазано быть данное описание.

Цитата(scifi @ Jun 22 2016, 22:08) *
Увы, не могу. Лицензиаты арма передо мной не отчитываются crying.gif

Когда сможете, тогда будет корректно и "чаще встречаются" и слив.

Сообщение отредактировал GetSmart - Jun 22 2016, 18:49


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 22 2016, 19:28
Сообщение #43


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(GetSmart @ Jun 22 2016, 21:19) *
Когда сможете, тогда будет корректно и "чаще встречаются" и слив.

Ой, да ради бога: How to Use Bit-band and BME on the KE04 and KE06 Subfamilies.
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 22 2016, 21:32
Сообщение #44


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Цитата(scifi @ Jun 22 2016, 23:28) *
Ой, да ради бога:

Пока всё ещё утверждение ложно/некорректно.
Там речь о Фрискейловом СМ0+. BME реализовано на уровне ядра. Но первое же преджложение "Т.к. bit-banding есть опция СМ0+" на каких документах от АРМ основано - не ясно.

Разработчик описал в документах ядра ARMv6-M что там есть обязательное, что опциональное. Ни там, ни там не было Bit-banding. Всегда отсутствующие фичи можно не указывать вообще. Либо апдейтить документацию. В TRM CM0+ (на сайте арма) тоже нет ни слова о Bit-banding. Если в документации ARMv6-M или TRM CM0+ появится Bit-banding, то утверждения станут корректны для CM0+. С оговоркой, что опцию добавили с какой-то даты. Наличие опции в ките ничего не значит, т.к. кит напоминает сборку запчастей для разных кортексов.

Сообщение отредактировал GetSmart - Jun 23 2016, 14:22


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 23 2016, 05:52
Сообщение #45


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Появилась новая проблема - написание обработчика прерывания на асме.
Мои знания в асме близки к нулю, тем более под ARMы.
Кто-то может поделиться полезными ссылками, вроде каких-нибудь уроков, курсов в сети. Возможно есть проекты в свободном доступе, где прерывания тоже реализовывались на асме и работали с сишным кодом. Тоже будет полезно.
Go to the top of the page
 
+Quote Post
Forger
сообщение Jun 23 2016, 08:12
Сообщение #46


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(Влад Р. @ Jun 23 2016, 08:52) *
Появилась новая проблема - написание обработчика прерывания на асме.
Абсолютно тупиковый путь, особенное, если планируется расширять проект (код)!
Я бы просто заново спроектировал проект.
Скорее всего нужно переходить на ртос, тогда число всяких обработчиков прерываний резко сократиться - ведь не на все события нужно реагировать с точность до мкс, опрашивать кнопки тоже нет смысла чаще, чем раз в 50мс. Т.е. для таких вещей хватает одного системного таймера оси (у меня такт в основном 1мс).
Короче, самописный асм на ARMе в своем коде - это крайне опасная и нежелательная вещь, ее нужно всячески избегать и исключать еще на этапе проектирования кода.





--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
Obam
сообщение Jun 23 2016, 08:12
Сообщение #47


Знающий
****

Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663



Цитата(scifi @ Jun 22 2016, 21:08) *
Слив защщитан biggrin.gif


Из оффсайда…

Так что ни разу wink.gif

Сообщение отредактировал Obam - Jun 23 2016, 08:18


--------------------
Пролетарий умственного труда.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 23 2016, 08:19
Сообщение #48


Универсальный солдатик
******

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



Цитата
Измените переменные на 32-битовые. Везде, где можно.

Это уже сделали? Где листинг?

Цитата(Влад Р. @ Jun 23 2016, 08:52) *
Появилась новая проблема - написание обработчика прерывания на асме.

Только в качестве обучающего занятия. Примеры можно найти в книжках Дж. Ю, на одну из которых я ссылался.
Go to the top of the page
 
+Quote Post
Obam
сообщение Jun 23 2016, 08:27
Сообщение #49


Знающий
****

Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663



Цитата(GetSmart @ Jun 22 2016, 22:19) *
… Bit-banding в СМ0 нет и не ожидается (без намёков). Точнее, подчеркивали что эта фича характерна для СМ3 и выше. И, как уже сказано, её не было в описании ARMv6-М от самого АРМа. В Architecture Reference Manual на какое-то ядро обазано быть данное описание.


Справедливости ради в Architecture Reference Manual этой темы нет, она отражена в Technical Reference Manual.

Цитата(Влад Р. @ Jun 23 2016, 09:52) *
Появилась новая проблема - написание обработчика прерывания на асме.

Кто-то может поделиться полезными ссылками, вроде каких-нибудь уроков, курсов в сети. Возможно есть проекты в свободном доступе, где прерывания тоже реализовывались на асме и работали с сишным кодом. Тоже будет полезно.


Прикрепленный файл  Vincent_Mahout_AssemblyLanguageProgramming_ARM_CortexM3.pdf ( 4.06 мегабайт ) Кол-во скачиваний: 164



--------------------
Пролетарий умственного труда.
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 23 2016, 08:54
Сообщение #50


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(Forger @ Jun 23 2016, 11:12) *
Абсолютно тупиковый путь, особенное, если планируется расширять проект (код)!
Я бы просто заново спроектировал проект.
Скорее всего нужно переходить на ртос, тогда число всяких обработчиков прерываний резко сократиться - ведь не на все события нужно реагировать с точность до мкс, опрашивать кнопки тоже нет смысла чаще, чем раз в 50мс. Т.е. для таких вещей хватает одного системного таймера оси (у меня такт в основном 1мс).
Короче, самописный асм на ARMе в своем коде - это крайне опасная и нежелательная вещь, ее нужно всячески избегать и исключать еще на этапе проектирования кода.

По-моему RTOS сейчас только замедлит код, а основное требование сейчас - это максимальное быстродействие и минимальное число "лишних" команд. Сейчас задействовано всего одно внешнее прерывание. Почему под ARMы нужно избегать самописного ассемблерного кода, вроде как ASM-код - это эталон быстродействия для любой платформы?

Цитата(ViKo @ Jun 23 2016, 11:19) *
Это уже сделали? Где листинг?

Только в качестве обучающего занятия. Примеры можно найти в книжках Дж. Ю, на одну из которых я ссылался.

А для более широких задач почему не подойдет?
Заменил на fastы. stdint вместо них подставляет int. Вот листинг:
CODE
68: {
0x08000240 B430 PUSH {r4-r5}
69: uint_fast16_t db = GPIOC->IDR & 0x1FFF;
70: uint_fast8_t data/* = db & 0xFF*/;
71:
0x08000242 481D LDR r0,[pc,#116] ; @0x080002B8
0x08000244 8A00 LDRH r0,[r0,#0x10]
72: GPIOB->BSRR = GPIO_BSRR_BS_12;
73:
0x08000246 2201 MOVS r2,#0x01
0x08000248 04C1 LSLS r1,r0,#19
0x0800024A 0CC9 LSRS r1,r1,#19
0x0800024C 481B LDR r0,[pc,#108] ; @0x080002BC
0x0800024E 0312 LSLS r2,r2,#12
0x08000250 6182 STR r2,[r0,#0x18]
74: data = db & 0xFF;
75:
0x08000252 B2CB UXTB r3,r1
76: if (!(db & (0x01 << 12))) {
0x08000254 04CA LSLS r2,r1,#19
68: {
69: uint_fast16_t db = GPIOC->IDR & 0x1FFF;
70: uint_fast8_t data/* = db & 0xFF*/;
71:
72: GPIOB->BSRR = GPIO_BSRR_BS_12;
73:
74: data = db & 0xFF;
75:
76: if (!(db & (0x01 << 12))) {
0x08000256 D429 BMI 0x080002AC
77: switch (db & (0x03 << 9)) {
78: case 0x0000:
0x08000258 2203 MOVS r2,#0x03
0x0800025A 0252 LSLS r2,r2,#9
0x0800025C 4011 ANDS r1,r1,r2
79: GPIOA->ODR = (GPIOA->ODR & ~0xFF) | data;
0x0800025E 4A18 LDR r2,[pc,#96] ; @0x080002C0
0x08000260 D008 BEQ 0x08000274
0x08000262 39FF SUBS r1,r1,#0xFF
0x08000264 39FF SUBS r1,r1,#0xFF
0x08000266 1E89 SUBS r1,r1,#2
0x08000268 D00A BEQ 0x08000280
0x0800026A 39FF SUBS r1,r1,#0xFF
0x0800026C 39FF SUBS r1,r1,#0xFF
0x0800026E 2902 CMP r1,#0x02
0x08000270 D11C BNE 0x080002AC
0x08000272 E00C B 0x0800028E
0x08000274 8A90 LDRH r0,[r2,#0x14]
0x08000276 0A00 LSRS r0,r0,#8
0x08000278 0200 LSLS r0,r0,#8
0x0800027A 4318 ORRS r0,r0,r3
0x0800027C 8290 STRH r0,[r2,#0x14]
80: break;
81: case 0x0200:
0x0800027E E015 B 0x080002AC
82: GPIOB->ODR = (GPIOB->ODR & ~(0x03 << 5)) | (data & (0x03 << 5));
0x08000280 8A82 LDRH r2,[r0,#0x14]
0x08000282 2160 MOVS r1,#0x60
0x08000284 438A BICS r2,r2,r1
0x08000286 400B ANDS r3,r3,r1
0x08000288 431A ORRS r2,r2,r3
0x0800028A 8282 STRH r2,[r0,#0x14]
83: break;
84: case 0x0400:
0x0800028C E00E B 0x080002AC
85: GPIOA->ODR = (GPIOA->ODR & ~(0x0F << 8)) | ((uint16_t)HINIBBLE(data) << 8);
0x0800028E 8A91 LDRH r1,[r2,#0x14]
0x08000290 240F MOVS r4,#0x0F
0x08000292 0224 LSLS r4,r4,#8
0x08000294 031D LSLS r5,r3,#12
0x08000296 0C2D LSRS r5,r5,#16
0x08000298 43A1 BICS r1,r1,r4
0x0800029A 022D LSLS r5,r5,#8
0x0800029C 4329 ORRS r1,r1,r5
0x0800029E 8291 STRH r1,[r2,#0x14]
86: GPIOB->ODR = (GPIOB->ODR & ~(0x0F << 8)) | ((uint16_t)LONIBBLE(data) << 8);
87: break;
88: case 0x0600:
89: break;
90: }
91: }
0x080002A0 8A81 LDRH r1,[r0,#0x14]
0x080002A2 071A LSLS r2,r3,#28
0x080002A4 43A1 BICS r1,r1,r4
0x080002A6 0D12 LSRS r2,r2,#20
0x080002A8 4311 ORRS r1,r1,r2
0x080002AA 8281 STRH r1,[r0,#0x14]
92: EXTI->PR = EXTI_PR_PR8;
0x080002AC 20FF MOVS r0,#0xFF
0x080002AE 4905 LDR r1,[pc,#20] ; @0x080002C4
0x080002B0 3001 ADDS r0,r0,#0x01
0x080002B2 6148 STR r0,[r1,#0x14]
93: }
0x080002B4 BC30 POP {r4-r5}
0x080002B6 4770 BX lr
0x080002B8 0800 DCW 0x0800
0x080002BA 4800 DCW 0x4800
0x080002BC 0400 DCW 0x0400
0x080002BE 4800 DCW 0x4800
0x080002C0 0000 DCW 0x0000
0x080002C2 4800 DCW 0x4800
0x080002C4 0400 DCW 0x0400
0x080002C6 4001 DCW 0x4001



Цитата(Obam @ Jun 23 2016, 11:27) *
Vincent_Mahout_AssemblyLanguageProgramming_ARM_CortexM3.pdf

Похоже, то что нужно. Спасибо!
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 23 2016, 09:13
Сообщение #51


Универсальный солдатик
******

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



Что-то не впечатляет результат... Надо бы не просто переменные сделать int, а саму логику работы перевести на int.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 23 2016, 09:13
Сообщение #52


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Влад Р. @ Jun 23 2016, 11:54) *
Заменил на fastы. stdint вместо них подставляет int. Вот листинг:

Такой код, конечно, можно ускорить, если вылизать на ассемблере. Правда, не очень благодарное это занятие.
Кстати, сишный код неоптимальный. К примеру, вместо
GPIOA->ODR = (GPIOA->ODR & ~0xFF) | data;
лучше написать
GPIOA->BSRR = 0x00FF0000 | data;
Ну и ещё что-то там наверняка есть.
Go to the top of the page
 
+Quote Post
Forger
сообщение Jun 23 2016, 09:26
Сообщение #53


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(Влад Р. @ Jun 23 2016, 11:54) *
По-моему RTOS сейчас только замедлит код, а основное требование сейчас - это максимальное быстродействие и минимальное число "лишних" команд.
Лишних команд не бывает, а бывают деньги, заплаченные закачиком на разработку впустую crying.gif
Заказчику как правило совершенно до лампочки как внутри реализована задача, главное цена - и время (время = деньги), разумеется, изделие должно соотв. ТЗ.
Я лично никогда не буду экономить на цене МК в изделии, которое стоит как минимум в сотню раз дороже, чем этот МК, и
поэтмоу заложу такой МК, которого хватит с запасом! В крайнем случае его можно заменить и перенести код на него со старого МК.
Кстати, если код был написан через одно место (ASM-вставки, отсутствует система именования, не испоьзуются SVN и т.п.), то это создаст огромную проблему.
Более того, крайне затруднительно использование такого кривого разового кода в других проектах, а это тоже адская потеря времени и денег.

Цитата
Сейчас задействовано всего одно внешнее прерывание.

Сколько всего прерываний в коде?

Цитата
Почему под ARMы нужно избегать самописного ассемблерного кода,
См. выше.
Не только под ARM, а везде подобный колхоз = зло. Пройдет полгода и попробуйте в нем разобраться или не дай бог кто-то другой будет за вами это делать...
Проклянут до 10го колена sm.gif


Цитата
вроде как ASM-код - это эталон быстродействия для любой платформы?
Это - величайший миф всех времен и народов! sm.gif

Мы щас отклоняемся от темы в сторону классических и бессмысленных холиваров типа ASM vs C и т.п. Это бессмыслено.

Еще раз: для каждой коммерческой задачи существут бюджет!
Вполне возможно, что для примитивных, но очень крупносерийных изделиях есть смысл использовать ASM (в крайне редких случаях), но я не участвовал в таких проектах.


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 23 2016, 09:33
Сообщение #54


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(scifi @ Jun 23 2016, 12:13) *
Кстати, сишный код неоптимальный. К примеру, вместо
GPIOA->ODR = (GPIOA->ODR & ~0xFF) | data;
лучше написать
GPIOA->BSRR = 0x00FF0000 | data;
Ну и ещё что-то там наверняка есть.


Да, этот момент я упустил. Сомневался нормально ли отработает установка/сброс одних и тех же битов. Перечитал мануал и переделал:
CODE
68: {
0x08000240 B410 PUSH {r4}
69: uint_fast16_t db = GPIOC->IDR & 0x1FFF;
70: uint_fast8_t data/* = db & 0xFF*/;
71:
0x08000242 481A LDR r0,[pc,#104] ; @0x080002AC
0x08000244 8A00 LDRH r0,[r0,#0x10]
72: GPIOB->BSRR = GPIO_BSRR_BS_12;
73:
0x08000246 4A1A LDR r2,[pc,#104] ; @0x080002B0
0x08000248 04C1 LSLS r1,r0,#19
0x0800024A 0CC9 LSRS r1,r1,#19
0x0800024C 2001 MOVS r0,#0x01
0x0800024E 0300 LSLS r0,r0,#12
0x08000250 6190 STR r0,[r2,#0x18]
74: data = db & 0xFF;
75:
0x08000252 B2C8 UXTB r0,r1
76: if (!(db & (0x01 << 12))) {
0x08000254 04CB LSLS r3,r1,#19
68: {
69: uint_fast16_t db = GPIOC->IDR & 0x1FFF;
70: uint_fast8_t data/* = db & 0xFF*/;
71:
72: GPIOB->BSRR = GPIO_BSRR_BS_12;
73:
74: data = db & 0xFF;
75:
76: if (!(db & (0x01 << 12))) {
0x08000256 D423 BMI 0x080002A0
77: switch (db & (0x03 << 9)) {
78: case 0x0000:
0x08000258 2303 MOVS r3,#0x03
0x0800025A 025B LSLS r3,r3,#9
0x0800025C 4019 ANDS r1,r1,r3
79: GPIOA->BSRR = (0xFF << 16) | data;
0x0800025E 4B15 LDR r3,[pc,#84] ; @0x080002B4
0x08000260 D008 BEQ 0x08000274
0x08000262 39FF SUBS r1,r1,#0xFF
0x08000264 39FF SUBS r1,r1,#0xFF
0x08000266 1E89 SUBS r1,r1,#2
0x08000268 D009 BEQ 0x0800027E
0x0800026A 39FF SUBS r1,r1,#0xFF
0x0800026C 39FF SUBS r1,r1,#0xFF
0x0800026E 2902 CMP r1,#0x02
0x08000270 D116 BNE 0x080002A0
0x08000272 E00A B 0x0800028A
0x08000274 21FF MOVS r1,#0xFF
0x08000276 0409 LSLS r1,r1,#16
0x08000278 4308 ORRS r0,r0,r1
0x0800027A 6198 STR r0,[r3,#0x18]
80: break;
81: case 0x0200:
0x0800027C E010 B 0x080002A0
82: GPIOB->BSRR = (0x03 << 21) | (data & (0x03 << 5));
0x0800027E 2160 MOVS r1,#0x60
0x08000280 4008 ANDS r0,r0,r1
0x08000282 0409 LSLS r1,r1,#16
0x08000284 1840 ADDS r0,r0,r1
0x08000286 6190 STR r0,[r2,#0x18]
83: break;
84: case 0x0400:
0x08000288 E00A B 0x080002A0
85: GPIOA->BSRR = (0x0F << 24) | ((uint16_t)HINIBBLE(data) << 8);
0x0800028A 0301 LSLS r1,r0,#12
0x0800028C 0C09 LSRS r1,r1,#16
0x0800028E 020C LSLS r4,r1,#8
0x08000290 210F MOVS r1,#0x0F
0x08000292 0609 LSLS r1,r1,#24
0x08000294 1864 ADDS r4,r4,r1
0x08000296 619C STR r4,[r3,#0x18]
86: GPIOB->BSRR = (0x0F << 24) | ((uint16_t)LONIBBLE(data) << 8);
87: break;
88: }
89: }
0x08000298 0700 LSLS r0,r0,#28
0x0800029A 0D00 LSRS r0,r0,#20
0x0800029C 1840 ADDS r0,r0,r1
0x0800029E 6190 STR r0,[r2,#0x18]
90: EXTI->PR = EXTI_PR_PR8;
0x080002A0 20FF MOVS r0,#0xFF
0x080002A2 4905 LDR r1,[pc,#20] ; @0x080002B8
0x080002A4 3001 ADDS r0,r0,#0x01
0x080002A6 6148 STR r0,[r1,#0x14]
91: }
0x080002A8 BC10 POP {r4}
0x080002AA 4770 BX lr
0x080002AC 0800 DCW 0x0800
0x080002AE 4800 DCW 0x4800
0x080002B0 0400 DCW 0x0400
0x080002B2 4800 DCW 0x4800
0x080002B4 0000 DCW 0x0000
0x080002B6 4800 DCW 0x4800
0x080002B8 0400 DCW 0x0400
0x080002BA 4001 DCW 0x4001


Цитата(Forger @ Jun 23 2016, 12:26) *
Лишних команд не бывает, а бывают деньги, заплаченные закачиком на разработку впустую crying.gif
Заказчику как правило совершенно до лампочки как внутри реализована задача

Заказчику действительно все равно как будет реализована задача, но в данном конкретном случае требование заказчика состоит в реализации задачи на имеющейся аппаратной базе, а дальше крутись как хочешь.

Цитата(Forger @ Jun 23 2016, 12:26) *
Сколько всего прерываний в коде?

В данный момент в коде включена обработка только ОДНОГО прерывания.
Go to the top of the page
 
+Quote Post
Forger
сообщение Jun 23 2016, 09:54
Сообщение #55


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(Влад Р. @ Jun 23 2016, 12:33) *
В данный момент в коде включена обработка только ОДНОГО прерывания.

Если уже в данный момент уперлись в производительность (приходится лезть в асм), то потом будет только хуже. Вас это не пугает? laughing.gif
Лично я бы в подобной ситуации уже забил тревогу и начал напрягать железячников, а пока они исправляют железо, ковырял бы это... Так сказать, "подстелить соломки" sm.gif


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 23 2016, 10:17
Сообщение #56


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(scifi @ Jun 23 2016, 15:13) *
Такой код, конечно, можно ускорить, если вылизать на ассемблере. Правда, не очень благодарное это занятие.
Кстати, сишный код неоптимальный. К примеру, вместо
...

Там много неоптимального, куча лишних операций, даже на си. Такое ощущение что старались написать как можно более тормозной код...
Например if (!(db & (0x01 << 12))) { - совершенно лишнее. Нужно убрать, а следующую строку заменить на switch (db & (3 << 9 | 1 << 12)) {.
Операция & 0x1FFF в первой строке тоже совершенно не нужная, генерит две лишних ассемблерных команды.
Операция ((uint16_t)HINIBBLE(data) << 8) - как будто специально написано, так чтобы было как можно тормознее - она генерит 3 команды + 1 команда предварительно:
Код
0x08000252 B2C8      UXTB     r0,r1
...
0x0800028A 0301      LSLS     r1,r0,#12
0x0800028C 0C09      LSRS     r1,r1,#16
0x0800028E 020C      LSLS     r4,r1,#8

Если не создавать отдельной переменной data и убрать операцию & 0x1FFF из первой строки, то достаточно будет 2-х команд, а не 4, да и кол-во используемых регистров сократится, а значит - меньше контекста надо сохранять/восстанавливать. Хотя это наверное на си не сделать, а только на асм.
И ещё куча мест.
Вобщем: код писал какой-то школьник, плохо дружащий с алгоритмизацией и программированием. sm.gif

Цитата(Влад Р. @ Jun 23 2016, 11:52) *
Появилась новая проблема - написание обработчика прерывания на асме.
Мои знания в асме близки к нулю, тем более под ARMы.

Берёте полученный листинг (лучше сделанный с полной оптимизацией), описание команд Cortex-M0 и разбираетесь.
Команды отсюда (для своего ядра):
http://infocenter.arm.com/help/index.jsp

Цитата(Forger @ Jun 23 2016, 15:26) *
Вполне возможно, что для примитивных, но очень крупносерийных изделиях есть смысл использовать ASM (в крайне редких случаях), но я не участвовал в таких проектах.

Да ладно Вам утрировать! Всё уместно в меру. И никакой сложности в написании асм-функции в десяток строк нет. И с поддержкой такого кода тож.
Сильно сомневаюсь что потребуется куда-то это переносить "в будущие проекты", так как это часть - аппаратно-зависима (ногодрыг) и в новом проекте будет делаться всё равно по-новой.
К тому-же - переносить на какие-то другие ядра - крайне маловероятно.
Даже ОС, за которые Вы так горячо пропагандируете, не обходятся без асм-вставок для переключения контекста и т.п.
А то что аппаратная реализация и, возможно, МК выбраны неправильно - я с Вами соглашусь.

Цитата(Forger @ Jun 23 2016, 15:54) *
Лично я бы в подобной ситуации уже забил тревогу и начал напрягать железячников, а пока они исправляют железо, ковырял бы это... Так сказать, "подстелить соломки" sm.gif

Вы не задумывались что этого железа может быть выпущено уже вагон + маленькая тележка? А может уже и у заказчиков многих стоит. sm.gif
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 23 2016, 10:20
Сообщение #57


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Цитата(Obam @ Jun 23 2016, 12:27) *
Справедливости ради в Architecture Reference Manual этой темы нет, она отражена в Technical Reference Manual.

Arch RM описывает более общую группу. Tech RM описывает конкретное ядро (CM0, CM0+ и пр.) с ревизией и патчем. Указывать bit-banding логично в более общем документе, если опция относится ко всем элементам группы. Или ко многим.

Сообщение отредактировал GetSmart - Jun 23 2016, 14:35


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
Forger
сообщение Jun 23 2016, 10:34
Сообщение #58


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(jcxz @ Jun 23 2016, 13:17) *
Даже ОС, за которые Вы так горячо пропагандируете, не обходятся без асм-вставок для переключения контекста и т.п.
Они пишутся один раз и разработчиком этой оси, пользователю оси туда соваться не нужно, даже я бы сказать нельзя.
Я же сую ОСь даже в простые проекты, поскольку ОСб - это однажды отлаженный кусок кода, который предварительно скомпилирован в отдельную либу (у меня так).
И дает возможность сразу грамотно спроектировать проект и очень быстро его оживить. А отладка и вылизывание (наведение лоска) - это уже дело десятое.
Если же очень нужно, то ничто не мешает это делать уже после того, как выпущена пробная партий изделий и идет наработка косяков и недочетов.
Т.е. параллельно выполняют две задачи (опять возвращаясь к оси sm.gif, экономится масса времени.


Цитата
Вы не задумывались что этого железа может быть выпущено уже вагон + маленькая тележка? А может уже и у заказчиков многих стоит. sm.gif

Я бы пробовал все варианты, которые только приходят в голову и не только в коде, но и копнул железо, а то может оказаться, что железо вообще никуда не годится wink.gif

Впрочем, мы тут сидим, гадаем, ничего не зная о проекте... sm.gif


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 23 2016, 10:34
Сообщение #59


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(jcxz @ Jun 23 2016, 16:17) *
Например if (!(db & (0x01 << 12))) { - совершенно лишнее. Нужно убрать, а следующую строку заменить на switch (db & (3 << 9 | 1 << 12)) {.

А ещё лучше заменить switch (db & (3 << 9 | 1 << 12)) { на switch (db >> 9 & (3 | 1 << 12 - 9)) { скорректировав соответствующим образом все case. Судя по листингу это уменьшит кол-во команд.
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 23 2016, 11:15
Сообщение #60


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(jcxz @ Jun 23 2016, 13:17) *
Например if (!(db & (0x01 << 12))) { - совершенно лишнее. Нужно убрать, а следующую строку заменить на switch (db & (3 << 9 | 1 << 12)) {.

if (!(db & (0x01 << 12))) необходима, чтобы в случае невыполнения условия, как можно быстрее выйти из прерывания.

Цитата(jcxz @ Jun 23 2016, 13:17) *
Операция & 0x1FFF в первой строке тоже совершенно не нужная, генерит две лишних ассемблерных команды.

Да, Вы правы. Осталась после предыдущих версий кода. Сейчас не нужна. Но на сколько я могу судить, компилятор ее проигнорировал (в дизассемблере ее не нашел, обычное считывание регистра). Сейчас и из Си убрал.

Остальное переделал:
CODE
68: {
0x08000240 B410 PUSH {r4}
69: uint_fast16_t db = GPIOC->IDR;
70:
0x08000242 4819 LDR r0,[pc,#100] ; @0x080002A8
0x08000244 8A00 LDRH r0,[r0,#0x10]
71: GPIOB->BSRR = GPIO_BSRR_BS_12;
72:
0x08000246 2101 MOVS r1,#0x01
0x08000248 4A18 LDR r2,[pc,#96] ; @0x080002AC
0x0800024A 0309 LSLS r1,r1,#12
0x0800024C 6191 STR r1,[r2,#0x18]
73: if (!(db & (0x01 << 12))) {
0x0800024E 04C1 LSLS r1,r0,#19
68: {
69: uint_fast16_t db = GPIOC->IDR;
70:
71: GPIOB->BSRR = GPIO_BSRR_BS_12;
72:
73: if (!(db & (0x01 << 12))) {
0x08000250 D424 BMI 0x0800029C
74: switch (db & (0x03 << 9)) {
75: case 0x0000:
0x08000252 2103 MOVS r1,#0x03
0x08000254 0249 LSLS r1,r1,#9
76: GPIOA->BSRR = (0xFF << 16) | (db & 0xFF);
0x08000256 4B16 LDR r3,[pc,#88] ; @0x080002B0
0x08000258 4001 ANDS r1,r1,r0
0x0800025A D008 BEQ 0x0800026E
0x0800025C 39FF SUBS r1,r1,#0xFF
0x0800025E 39FF SUBS r1,r1,#0xFF
0x08000260 1E89 SUBS r1,r1,#2
0x08000262 D00A BEQ 0x0800027A
0x08000264 39FF SUBS r1,r1,#0xFF
0x08000266 39FF SUBS r1,r1,#0xFF
0x08000268 2902 CMP r1,#0x02
0x0800026A D117 BNE 0x0800029C
0x0800026C E00B B 0x08000286
0x0800026E 21FF MOVS r1,#0xFF
0x08000270 B2C0 UXTB r0,r0
0x08000272 0409 LSLS r1,r1,#16
0x08000274 1840 ADDS r0,r0,r1
0x08000276 6198 STR r0,[r3,#0x18]
77: break;
78: case 0x0200:
0x08000278 E010 B 0x0800029C
79: GPIOB->BSRR = (0x03 << 21) | (db & (0x03 << 5));
0x0800027A 2160 MOVS r1,#0x60
0x0800027C 4008 ANDS r0,r0,r1
0x0800027E 0409 LSLS r1,r1,#16
0x08000280 1840 ADDS r0,r0,r1
0x08000282 6190 STR r0,[r2,#0x18]
80: break;
81: case 0x0400:
0x08000284 E00A B 0x0800029C
82: GPIOA->BSRR = (0x0F << 24) | ((db & 0xF0) << 4);
0x08000286 21F0 MOVS r1,#0xF0
0x08000288 4001 ANDS r1,r1,r0
0x0800028A 010C LSLS r4,r1,#4
0x0800028C 210F MOVS r1,#0x0F
0x0800028E 0609 LSLS r1,r1,#24
0x08000290 1864 ADDS r4,r4,r1
0x08000292 619C STR r4,[r3,#0x18]
83: GPIOB->BSRR = (0x0F << 24) | ((db & 0x0F) << 8);
84: break;
85: }
86: }
0x08000294 0700 LSLS r0,r0,#28
0x08000296 0D00 LSRS r0,r0,#20
0x08000298 1840 ADDS r0,r0,r1
0x0800029A 6190 STR r0,[r2,#0x18]
87: EXTI->PR = EXTI_PR_PR8;
0x0800029C 20FF MOVS r0,#0xFF
0x0800029E 4905 LDR r1,[pc,#20] ; @0x080002B4
0x080002A0 3001 ADDS r0,r0,#0x01
0x080002A2 6148 STR r0,[r1,#0x14]
88: }
0x080002A4 BC10 POP {r4}
0x080002A6 4770 BX lr
0x080002A8 0800 DCW 0x0800
0x080002AA 4800 DCW 0x4800
0x080002AC 0400 DCW 0x0400
0x080002AE 4800 DCW 0x4800
0x080002B0 0000 DCW 0x0000
0x080002B2 4800 DCW 0x4800
0x080002B4 0400 DCW 0x0400
0x080002B6 4001 DCW 0x4001


Цитата(jcxz @ Jun 23 2016, 13:17) *
Берёте полученный листинг (лучше сделанный с полной оптимизацией), описание команд Cortex-M0 и разбираетесь.

Сейчас как раз этим и занимаюсь. Не подскажите где посмотреть длительность каждой команды в машинных циклах?
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 23 2016, 13:24
Сообщение #61


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Влад Р. @ Jun 23 2016, 17:15) *
Сейчас как раз этим и занимаюсь. Не подскажите где посмотреть длительность каждой команды в машинных циклах?

Я уже Вам приводил ссылку. Там всё есть, и циклы тоже.
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 23 2016, 13:54
Сообщение #62


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(jcxz @ Jun 23 2016, 16:24) *
Я уже Вам приводил ссылку. Там всё есть, и циклы тоже.


Описание команд там есть. По нем и разбираюсь. Но где указана длительность не заметил. Можете тыкнуть носом? laughing.gif
Go to the top of the page
 
+Quote Post
Obam
сообщение Jun 23 2016, 14:25
Сообщение #63


Знающий
****

Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663



Цитата(Влад Р. @ Jun 23 2016, 17:54) *
Описание команд там есть. По нем и разбираюсь. Но где указана длительность не заметил.

Прикрепленный файл  DDI0432C_cortex_m0_r0p0_trm.pdf ( 461.17 килобайт ) Кол-во скачиваний: 101

Столбец Cycles
раздел 3.3 стр 3-4 и до горизонта


--------------------
Пролетарий умственного труда.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 23 2016, 14:26
Сообщение #64


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Влад Р. @ Jun 23 2016, 16:54) *
Можете тыкнуть носом? laughing.gif

Могу: тут.
Но имейте в виду: задержки флеша и доступа к периферии (GPIO) там не указаны.
Go to the top of the page
 
+Quote Post
IJAR
сообщение Jun 24 2016, 12:57
Сообщение #65


Местный
***

Группа: Свой
Сообщений: 232
Регистрация: 26-02-07
Из: г. Зеленоград
Пользователь №: 25 669



http://electronix.ru/forum/index.php?showt...869&hl=IJAR


--------------------
Вяжешь - вой, а поедешь - песни пой.
Между "хочу" и "можно" всегда есть дистанция
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 24 2016, 13:46
Сообщение #66


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(scifi @ Jun 23 2016, 17:26) *
Могу: тут.
Но имейте в виду: задержки флеша и доступа к периферии (GPIO) там не указаны.

При текущей частоте задержка флэш составляет 1 Wait State. Это значит что при выполнении кода из флеша к длительности всех команд можно добавить 1 машинный цикл? Как оценить на сколько в такой ситуации ускоряет выполнение буфер предварительной выборки? Задержка доступа к периферии определяется исключительно частотой шины, на которой она сидит, и собственными предделителями конкретной периферии? Или есть еще влияющие факторы?

Цитата(IJAR @ Jun 24 2016, 15:57) *

Спасибо за ссылку! Фейспалм мне, что ненагуглил эту тему раньше.

Написал в отдельном файле простой обработчик, который для начала будет просто устанавливать пин в единицу и сбрасывать флаг прерывания. Среда компилирует файл. Но не могу понять как задействовать его в основной программе?
CODE
EXTI_BASE EQU 0x40010400
GPIOA_BASE EQU 0x48000000
GPIOB_BASE EQU 0x48000400
GPIOC_BASE EQU 0x48000800

EXTI_PR_OFFSET EQU 0x14
GPIO_IDR_OFFSET EQU 0x10
GPIO_BSRR_OFFSET EQU 0x18

AREA EXTI, CODE, READONLY
EXTI4_15_IRQHandler PROC
LDR r0, =GPIOB_BASE ; загрузить в регистр r0 адрес порта GPIOB
MOVS r1, #0x01 ; копировать в регистр r1 значение 0x01
LSLS r2, r1, #12 ; логический сдвиг влево на 12 бит значения в регистре r1 и сохранение результата в регистр r2
STR r2, [r0, #GPIO_BSRR_OFFSET] ; сохранить слово из регистра r2 в регистр GPIOB->BSRR
LDR r0, =EXTI_BASE ; загрузить в регистр r0 адрес модуля EXTI
LSLS r1, #8 ; логический сдвиг влево на 8 бит значения в регистре r1
STR r1, [r0, #EXTI_PR_OFFSET] ; сохранить слово из регистра r1 в регистр EXTI->PR
BX LR
ENDP
END
Go to the top of the page
 
+Quote Post
Obam
сообщение Jun 24 2016, 13:56
Сообщение #67


Знающий
****

Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663



IARом пользуетесь? Тогда "IAR C/C++ Development Guide" главу "Assembler language interface" курить до просветления wink.gif


--------------------
Пролетарий умственного труда.
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 24 2016, 14:00
Сообщение #68


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(Obam @ Jun 24 2016, 16:56) *
IARом пользуетесь? Тогда "IAR C/C++ Development Guide" главу "Assembler language interface" курить до просветления wink.gif


Keil
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 24 2016, 15:58
Сообщение #69


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Прошу прощения за отклонение от темы беседы. Но поправлюсь рядом со своим же постом.

Цитата(GetSmart @ Jun 23 2016, 01:32) *
Но первое же преджложение "Т.к. bit-banding есть опция СМ0+" на каких документах от АРМ основано - не ясно.
Точнее будет перевод "Т.к. bit-band регион есть опция ARM CM0+...". Но в открытой документации от ARM не было bit-band региона для этих ядер и эта формулировка тоже некорректна. Во многих реализациях ARMv6-M от NXP в регионе 0x200000000 было ОЗУ с дополнительными фичами самого NXP. Например IOHandler, USB буфер и прочее. У Фрискейла там тоже ОЗУ с дополнительной логикой. Похожей на bit-band. Написали бы <опция Кортексов или ARM>, а не так спорно.

На счёт ядра ошибся. SRAM работают с ядром через локальные шины. NVIC, MPU, кэш (которого нет у v6-M) и (какие-то) отладочные узлы встроены в ядро.

Ради эксперимента взял LPC435x, у которого на блок-схеме нарисованы отдельные ядра CM4 и CM0 (без плюса), а вся память и периферия общая. Ядро CM0 при обращении к региону 0x22000000 (bit-band) падает в Hard Fault. Хотя почти без накладных расходов и для удобства юзера логичнее было сделать этот регион общим. Но и тогда bit-banding было бы опцией (любого) процессора, а не архитектуры ARMv6-M или (под)группы.

Цитата
Но имейте в виду: задержки флеша и доступа к периферии (GPIO) там не указаны.

Можно сказать шире: в инструкциях чтения и записи внеядерного адресного пространства могут быть дополнительные такты задержек. Которые ARM не знает и не может указывать. И сами разработчики кристаллов все нюансы часто не описывают.

Сообщение отредактировал GetSmart - Jun 25 2016, 00:32


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 24 2016, 20:25
Сообщение #70


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Влад Р. @ Jun 24 2016, 19:46) *
При текущей частоте задержка флэш составляет 1 Wait State. Это значит что при выполнении кода из флеша к длительности всех команд можно добавить 1 машинный цикл? Как оценить на сколько в такой ситуации ускоряет выполнение буфер предварительной выборки?

Нет. Задержка добавляется при отсутствии следующей для выполнения команды в буфере предвыборки.
Например: после перехода буфер опустошается. Через 2 такта он будет заполнен 4-мя байтами (если верно, что ширина шины выборки команд == 32 бита как тут ранее писали).
Если в этих 4-х байтах 2 команды и нет перехода, то за время пока они выполняются, буфер предвыборки может успеть прочитать ещё 32 бита (если шина к данной области памяти не занята).
Если же в этих 4-байтах команда 4-байтовая и её длительность в циклах ==1 (не знаю - есть-ли такие в M0?), то тогда да - опять будет опустошение предвыборки и приостановка на такт декодера команд.
Или если буфер предвыборки не успел прочитать след. байты из-за занятости шины (если был доступ CPU к данным в этом-же регионе памяти, или был доступ к данному региону другого bus-mastera по этой-же шине).
В общем - на линейном коде без ветвлений и если в данном регионе находится только исполняемый код, скорей всего никаких дополнительных тактов ожидания не будет.
На переходах будут приостановки. Хотя - может в Вашем МК буфер предыворки содержит несколько строк кеша? Но в Вашем вряд-ли. В некоторых МК буфер предвыборки имеет ёмкость в неск. сток кеша (в Tiva например).
Ещё дополнительные приостановки предвыборки могут быть если целевой адрес перехода не кратен 4. Имхо - буфер предвыборки скорей всего работает с выровненными адресами, а значит при невыровненном на 4 целевом адресе перехода, за первый доступ считает только максимум одну 2-байтовую команду, и если её длительность ==1 икл, то опять будет stall на дополнительный цикл на выборку следующих 32 бит.
Хотя всё это я описал для M3/M4, но думаю в M0 - аналогично.

Совет: там где у Вас switch, используйте табличный переход LDR PC,[Rx] - это сделает все ветвления case одинаковой длительности и избавит от необходимости if (!(db & (0x01 << 12))) {.
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 24 2016, 21:18
Сообщение #71


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(jcxz @ Jun 24 2016, 23:25) *
Нет. Задержка добавляется при отсутствии следующей для выполнения команды в буфере предвыборки.
Например: после перехода буфер опустошается. Через 2 такта он будет заполнен 4-мя байтами (если верно, что ширина шины выборки команд == 32 бита как тут ранее писали).

В Reference manual сказано так: "The prefetch buffer is 3 blocks wide where each block consists of 4 bytes." Видимо как раз те самые 32 бита.

Цитата(jcxz @ Jun 24 2016, 23:25) *
На переходах будут приостановки. Хотя - может в Вашем МК буфер предыворки содержит несколько строк кеша? Но в Вашем вряд-ли. В некоторых МК буфер предвыборки имеет ёмкость в неск. сток кеша (в Tiva например).

В STM32F0 кэша точно нет.

Цитата(jcxz @ Jun 24 2016, 23:25) *
Ещё дополнительные приостановки предвыборки могут быть если целевой адрес перехода не кратен 4. Имхо - буфер предвыборки скорей всего работает с выровненными адресами, а значит при невыровненном на 4 целевом адресе перехода, за первый доступ считает только максимум одну 2-байтовую команду, и если её длительность ==1 икл, то опять будет stall на дополнительный цикл на выборку следующих 32 бит.

Тут типа намекают, что адреса переходов лучше делать кратными 8 байтам:
"The implementation of this prefetch buffer makes a faster CPU execution possible as the CPU fetches one word at a time with the next word readily available in the prefetch buffer. This implies that the acceleration ratio will be of the order of 2 assuming that the code is aligned at a 64-bit boundary for the jumps."

Цитата(jcxz @ Jun 24 2016, 23:25) *
Совет: там где у Вас switch, используйте табличный переход LDR PC,[Rx] - это сделает все ветвления case одинаковой длительности и избавит от необходимости if (!(db & (0x01 << 12))) {.

ОК, как слеплю окончательный код, выложу на суд.

Пока разобрался как задействовать код из asm-файла. Не хватало всего одной директивы:
EXPORT EXTI4_15_IRQHandler
Очень помогло: Mixing C, C++, and Assembly Language
Вот, целиком в текущем виде:
CODE
EXTI_BASE EQU 0x40010400
GPIOA_BASE EQU 0x48000000
GPIOB_BASE EQU 0x48000400
GPIOC_BASE EQU 0x48000800

EXTI_PR_OFFSET EQU 0x14
GPIO_IDR_OFFSET EQU 0x10
GPIO_BSRR_OFFSET EQU 0x18

AREA ASMEXTI, CODE, READONLY
EXTI4_15_IRQHandler PROC
EXPORT EXTI4_15_IRQHandler
LDR r0, =GPIOB_BASE ; загрузить в регистр r0 адрес порта GPIOB
MOVS r1, #0x01 ; копировать в регистр r1 значение 0x01
LSLS r2, r1, #12 ; логический сдвиг влево на 12 бит значения в регистре r1 и сохранение результата в регистр r2
STR r2, [r0, #GPIO_BSRR_OFFSET] ; сохранить слово из регистра r2 в регистр GPIOB->BSRR
LDR r0, =EXTI_BASE ; загрузить в регистр r0 адрес модуля EXTI
LSLS r1, #8 ; логический сдвиг влево на 8 бит значения в регистре r1
STR r1, [r0, #EXTI_PR_OFFSET] ; сохранить слово из регистра r1 в регистр EXTI->PR
BX lr
ENDP
END
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 25 2016, 02:07
Сообщение #72


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Цитата(jcxz @ Jun 25 2016, 00:25) *
Хотя всё это я описал для M3/M4, но думаю в M0 - аналогично.

У СМ0 один канал подгрузки данных (шина), У СМ3 (и старше) две или даже три. СМ0 выполняя инструкцию обращения к памяти будет отнимать эту шину от подгрузки кода.

Цитата(Влад Р. @ Jun 25 2016, 01:18) *
Пока разобрался как задействовать код из asm-файла.

После сброса периферии, вызвавшей обработчик нужно несколько тактов ожидания. Можно просто NOP-ов. Если после STR выполнить сразу BX lr, то будет сразу же повторный "залёт" в обработчик. Обычно нужно 3-10 тактов ожидания. Сколько конкретно - ведомо разве что разработчику всего чипа. Можно определить тестируя в железе. Лучше делать с запасом. Можно использовать инструкции DSB, т.к. у СМ0 DSB всегда константной длительности. Но инструкция шириной как два NOPa (32 bit).

Сообщение отредактировал GetSmart - Jun 25 2016, 02:08


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 25 2016, 04:15
Сообщение #73


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(GetSmart @ Jun 25 2016, 05:07) *
После сброса периферии, вызвавшей обработчик нужно несколько тактов ожидания. Можно просто NOP-ов. Если после STR выполнить сразу BX lr, то будет сразу же повторный "залёт" в обработчик. Обычно нужно 3-10 тактов ожидания. Сколько конкретно - ведомо разве что разработчику всего чипа. Можно определить тестируя в железе. Лучше делать с запасом. Можно использовать инструкции DSB, т.к. у СМ0 DSB всегда константной длительности. Но инструкция шириной как два NOPa (32 bit).

Что-то я подобного не замечал. Написал то же самое на Си и скомпилировал, никакие дополнительные регистры не стекируются (только те, что автоматом). При этом в полученном коде инструкция BX следует сразу за STR.
Go to the top of the page
 
+Quote Post
GetSmart
сообщение Jun 25 2016, 15:38
Сообщение #74


.
******

Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753



Цитата(Влад Р. @ Jun 25 2016, 08:15) *
Что-то я подобного не замечал. Написал то же самое на Си и скомпилировал, никакие дополнительные регистры не стекируются (только те, что автоматом). При этом в полученном коде инструкция BX следует сразу за STR.

Компилятор делает оптимально. Суть не в этом. Если у Вас в асм-коде вторая STR сбрасывает сигнал, идущий от перефирии к NVIC, то в общем случае (хоть в Си хоть в асм) нежелательно это делать в самом конце IRQ. Можно либо нопы вставлять, либо какое-то другое действие обработчика в самый конец перенести, особенно когда на асме (видны все инструкции).

Но за STM32 не берусь утверждать. На NXP (17хх, 13хх) эти дополнительные задержки нужны были точно. Странно, если NXP сделал свою часть чипа так, что от периферии сигнал снятия запроса прерывания доходил до NVIC с большой задержкой, которой нет у STM32. В доках NXP нужность задержек даже не описана. Так что приходилось их использовать для большей безопасности портирования кода. Может они эту граблю специально продемонстрировали чтобы программер был осторожней и сбрасывал запрос чуть раньше выхода из IRQ.

Сообщение отредактировал GetSmart - Jun 26 2016, 04:16


--------------------
Заблуждаться - Ваше законное право :-)
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 27 2016, 04:57
Сообщение #75


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Влад Р. @ Jun 25 2016, 03:18) *
В Reference manual сказано так: "The prefetch buffer is 3 blocks wide where each block consists of 4 bytes." Видимо как раз те самые 32 бита.
В STM32F0 кэша точно нет.

Ну собственно эти "3 blocks" по 32 бита и есть миникеш. Пока из одного блока идёт декодирование команды, другие могут заполняться.
В Tiva так же примерно, только размер блока ==256бит (по ширине шины предвыборки) и их кол-во больше. И в LPC17xx так же.

Цитата(Влад Р. @ Jun 25 2016, 03:18) *
Тут типа намекают, что адреса переходов лучше делать кратными 8 байтам:
"The implementation of this prefetch buffer makes a faster CPU execution possible as the CPU fetches one word at a time with the next word readily available in the prefetch buffer. This implies that the acceleration ratio will be of the order of 2 assuming that the code is aligned at a 64-bit boundary for the jumps."

Хм... похоже что ширина шины предвыборки скорей всего == 64 бита всё-таки. Раз за такт выбирается одно слово + второе слово оказывается уже в буфере предвыборки за тот же такт.

Цитата(Влад Р. @ Jun 25 2016, 03:18) *
Пока разобрался как задействовать код из asm-файла. Не хватало всего одной директивы:
EXPORT EXTI4_15_IRQHandler

Обычно чтобы символьные имена из асм-файла были видимы в других исходных файлах (си и асм), нужно это символьное имя объявить в директиве PUBLIC.
Ну и, естественно, прописать прототип в си-хидере.
И наоборот: чтобы в асм-файле были видимы имена из других объектных файлов, нужно их указать в директиве EXTERN.
EXPORT я не использую нигде.

Цитата(GetSmart @ Jun 25 2016, 08:07) *
После сброса периферии, вызвавшей обработчик нужно несколько тактов ожидания. Можно просто NOP-ов. Если после STR выполнить сразу BX lr, то будет сразу же повторный "залёт" в обработчик. Обычно нужно 3-10 тактов ожидания. Сколько конкретно - ведомо разве что разработчику всего чипа. Можно определить тестируя в железе. Лучше делать с запасом. Можно использовать инструкции DSB, т.к. у СМ0 DSB всегда константной длительности. Но инструкция шириной как два NOPa (32 bit).

Можно это квитирование прерывания просто поставить в начале ISR, сразу после входа. Я так и делаю обычно.
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 27 2016, 12:05
Сообщение #76


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(jcxz @ Jun 27 2016, 07:57) *
Обычно чтобы символьные имена из асм-файла были видимы в других исходных файлах (си и асм), нужно это символьное имя объявить в директиве PUBLIC.
Ну и, естественно, прописать прототип в си-хидере.
И наоборот: чтобы в асм-файле были видимы имена из других объектных файлов, нужно их указать в директиве EXTERN.
EXPORT я не использую нигде.

Тут случай особый. Это функция-обработчик прерывания. И её прототип указывается в ASM-файле начальной инициализации, который трогать нежелательно. Поэтому в определении функции необходимо директива EXPORT или её синоним GLOBAL.

Цитата(jcxz @ Jun 27 2016, 07:57) *
Можно это квитирование прерывания просто поставить в начале ISR, сразу после входа. Я так и делаю обычно.

В моей ситуации необходимо как можно быстрее после входа в обработчик считать регистр порта в/в. Но в любом случае, это лишнее. Сброс флага внешнего прерывания нормально отрабатывает и непосредственно перед выходом из обработчика.

Написал обработчик на ASMе. Время входа в прерывание удалось сократить до 500 нс. Этого пока достаточно. Как сделать табличные переходы не соображу. Вот, что получилось:
CODE
EXTI_BASE EQU 0x40010400
GPIOA_BASE EQU 0x48000000
GPIOB_BASE EQU 0x48000400
GPIOC_BASE EQU 0x48000800

EXTI_PR_OFFSET EQU 0x14
GPIO_IDR_OFFSET EQU 0x10
GPIO_BSRR_OFFSET EQU 0x18
GPIO_BRR_OFFSET EQU 0x28

MACRO
asmexti_exit
LDR r0, =EXTI_BASE ; загрузить в регистр r0 адрес модуля EXTI
MOVS r1, #0x01 ; загрузить в регистр r1 значение 0x01
LSLS r1, #8 ; логический сдвиг влево на 8 бит значения в регистре r1
STR r1, [r0, #EXTI_PR_OFFSET] ; сохранить слово из регистра r1 в регистр EXTI->PR
BX lr ; возврат из функции
ALIGN
MEND

AREA ASMEXTI, CODE, READONLY
EXTI4_15_IRQHandler PROC
EXPORT EXTI4_15_IRQHandler
LDR r0, =GPIOC_BASE ; загрузить в регистр r0 адрес порта GPIOC
LDRH r0, [r0, #GPIO_IDR_OFFSET] ; загрузить в регистр r0 полуслово из регистра GPIOC->IDR
LSRS r1, r0, #9 ; логический сдвиг вправо на 9 бит значения в регистре r0 и сохранение результата в регистр r1
MOVS r2, #0x0B ; загрузить в регистр r2 значение 0x0B
ANDS r1, r2 ; побитовое И регистра r1 с регистром r2
CMP r1, #0x02 ; сравнить вычитанием из регистра r1 значения 0x02
BEQ C ; условный переход на метку C, если результат операции нулевой
CMP r1, #0x00 ; сравнить вычитанием из регистра r1 значения 0x00
BEQ A ; условный переход на метку A, если результат операции нулевой
CMP r1, #0x01 ; сравнить вычитанием из регистра r1 значения 0x01
BEQ B ; условный переход на метку B, если результат операции нулевой
asmexti_exit
A
MOVS r1, #0xFF ; загрузить в регистр r1 значение 0xFF
ANDS r0, r1 ; побитовое И регистра r0 с регистром r1
LSLS r1, #16 ; логический сдвиг влево на 16 бит значения в регистре r1
ORRS r0, r1 ; побитовое ИЛИ регистра r0 с регистром r1
LDR r2, =GPIOA_BASE ; загрузить в регистр r2 адрес порта GPIOA
STR r0, [r2, #GPIO_BSRR_OFFSET] ; сохранить слово из регистра r0 в регистр GPIOA->BSRR
asmexti_exit
B
MOVS r1, #0x60 ; загрузить в регистр r1 значение 0x60
ANDS r0, r1 ; побитовое И регистра r0 с регистром r1
LSLS r1, #16 ; логический сдвиг влево на 16 бит значения в регистре r1
ORRS r0, r1 ; побитовое ИЛИ регистра r0 с регистром r1
LDR r2, =GPIOB_BASE ; загрузить в регистр r2 адрес порта GPIOB
STR r0, [r2, #GPIO_BSRR_OFFSET] ; сохранить слово из регистра r0 в регистр GPIOB->BSRR
asmexti_exit
C
MOVS r1, #0x0F ; загрузить в регистр r1 значение 0x0F
LSLS r2, r1, #4 ; логический сдвиг влево на 4 бита значения в регистре r1 и сохранение результата в регистр r2
ANDS r2, r0 ; побитовое И регистра r2 с регистром r0
LSLS r2, #4 ; логический сдвиг влево на 4 бита значения в регистре r2
LSLS r3, r1, #24 ; логический сдвиг влево на 24 бита значения в регистре r0 и сохранение результата в регистр r3
ORRS r2, r3 ; побитовое ИЛИ регистра r2 с регистром r3
LDR r3, =GPIOA_BASE ; загрузить в регистр r2 адрес порта GPIOA
STR r2, [r3, #GPIO_BSRR_OFFSET] ; сохранить слово из регистра r2 в регистр GPIOA->BSRR
ANDS r0, r1 ; побитовое И регистра r0 с регистром r1
LSLS r0, #8 ; логический сдвиг влево на 8 бит значения в регистре r0
LSLS r2, r1, #24 ; логический сдвиг влево на 24 бита значения в регистре r0 и сохранение результата в регистр r3
ORRS r0, r2 ; побитовое ИЛИ регистра r0 с регистром r2
LDR r1, =GPIOB_BASE ; загрузить в регистр r1 адрес порта GPIOB
STR r0, [r1, #GPIO_BSRR_OFFSET] ; сохранить слово из регистра r0 в регистр GPIOB->BSRR
asmexti_exit
ENDP
END
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 27 2016, 12:51
Сообщение #77


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Влад Р. @ Jun 27 2016, 15:05) *
Сброс флага внешнего прерывания нормально отрабатывает и непосредственно перед выходом из обработчика.
Инженеры ARM с вами не согласны, поэтому придумали инструкции барьеров (DSB, DMB, IMB). Но вы можете лично наступить на грабли.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 27 2016, 13:12
Сообщение #78


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(Сергей Борщ @ Jun 27 2016, 15:51) *
Инженеры ARM с вами не согласны, поэтому придумали инструкции барьеров (DSB, DMB, IMB). Но вы можете лично наступить на грабли.

Буду иметь в виду, перенесу сброс флага ближе к началу обработчика. Однако в функции EXTI_ClearITPendingBit() из STM32F0xx SPL этих инструкций нет. И доках от ST об этом тоже ничего.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 27 2016, 14:03
Сообщение #79


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Влад Р. @ Jun 27 2016, 18:05) *
Тут случай особый. Это функция-обработчик прерывания. И её прототип указывается в ASM-файле начальной инициализации, который трогать нежелательно. Поэтому в определении функции необходимо директива EXPORT или её синоним GLOBAL.

Не понял в чём именно проблема. Не обязательно ISR впихивать в файл начальной инициализации, можно создать отдельный файл.
Но впрочем - Ваше дело.

Цитата(Влад Р. @ Jun 27 2016, 18:05) *
Как сделать табличные переходы не соображу.

А что там соображать?
Код
;исходно в R0 - номер ветки ветвления
;допустим - на каждую ветку кода достаточно 32 байт
  LSLS   R0, #5
  ADR    R1, table00
  ADDS  PC, R1, R0

table00: ;ветка для значения 0
  ...
  BX LR
  NOP;добиваем NOP-ами до 32 байт
table01: ;ветка для значения 1
  ...
  BX LR
  NOP;добиваем NOP-ами до 32 байт
table02: ;ветка для значения 2
...

Не уверен что все использованные команды допустимы я ядре M0 (не имею с ним опыта), то думаю - можно заменить на эквиваленты.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 27 2016, 14:12
Сообщение #80


Универсальный солдатик
******

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



Код
CMP R0, #3; Compare input to maximum valid choice
BHI default_case; Branch to default case if higher than 3
MOVS R2, #4; Multiply branch table offset by 4
MULS R0, R2, R0; (size of each entry)
LDR R1,=BranchTable; Get base address of branch table
LDR R2,[R1,R0]; Get the actual branch destination
BX R2; Branch to destination
ALIGN 4; Alignment control. The table has
; to be word aligned to prevent unaligned read
BranchTable; table of each destination addresses
DCD Dest0
DCD Dest1
DCD Dest2
DCD Dest3
default_case
.; Instructions for default case
Dest0
.; Instructions for case ‘ 0 ’
Dest1
.; Instructions for case ‘ 1 ’
Dest2
.; Instructions for case ‘ 2 ’
Dest3
.; Instructions for case ‘ 3 ’

Из все той же книги. Пора бы, наконец, за ум взяться!
P.S. scifi-ю читать не надо, там на китайско-английском ржака. lol.gif
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 27 2016, 15:22
Сообщение #81


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(ViKo @ Jun 27 2016, 20:12) *
MULS R0, R2, R0; (size of each entry)
...

Однако такой вариант будет даже тормознее switch/case. laughing.gif
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jun 27 2016, 15:27
Сообщение #82


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(jcxz @ Jun 27 2016, 17:03) *
Не понял в чём именно проблема. Не обязательно ISR впихивать в файл начальной инициализации, можно создать отдельный файл.
Но впрочем - Ваше дело.

На сколько я понял PUBLIC - это аналог EXPORT и GLOBAL, но из других компиляторов. Потому как в Keil его нет. Чтобы показать линковщику откуда брать код, нужно либо прототип функции указать с директивой EXTERN, либо определение функции с директивой GLOBAL. Так? Startup-файл с прототипом функции-обработчика прерывания я трогать не хочу. Вот и указываю определение с директивой EXPORT (она же GLOBAL). Обработчик сейчас и так в отдельном файле.

С табличными переходами логика понятна. Спасибо!
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 27 2016, 15:41
Сообщение #83


Универсальный солдатик
******

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



Цитата(jcxz @ Jun 27 2016, 18:22) *
Однако такой вариант будет даже тормознее switch/case. laughing.gif

Какого switch/case? Сишного? Таким же и будет. rolleyes.gif
А, ну да, для команд умножения количество тактов написано 1 or 32, Depends on multiplier implementation, в этом документе. http://infocenter.arm.com/help/index.jsp?t...c/CHDCICDF.html
Видимо, Джозеф Ю скопипастил из предыдущей книжки.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 27 2016, 15:59
Сообщение #84


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Влад Р. @ Jun 27 2016, 21:27) *
На сколько я понял PUBLIC - это аналог EXPORT и GLOBAL, но из других компиляторов. Потому как в Keil его нет.

Сорри. У меня почему-то отложилось в голове, что у Вас IAR.
Go to the top of the page
 
+Quote Post

6 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 29th July 2025 - 08:46
Рейтинг@Mail.ru


Страница сгенерированна за 0.02638 секунд с 7
ELECTRONIX ©2004-2016