Задача такая. Есть цикл критичный по времени и внутри него нет возможности опроса глобальных переменных. При нормальном процессе цикл отрабатывает свои 1 сек и выходит. А если нажать на кнопку (прерывание) , хотелось бы быстрее выйти из этого цикла. Задумка была заменить адрес возврата из прерывания в стеке адресом за циклом.
Добрый день. Есть функция . В ней метка к примеру aaa: . В Си (не переходя в asm) есть возможность определить ее адрес и присвоить глобальной переменной? &aaa не работает. Пишу в IAR.
Код:
void *l;
int main(){ printf("1\n"); l = &&aaa; goto *l; printf("2\n"); aaa: printf("%p\n", l); }
Правда, применений этому я не вижу. И оптимизации все попортят, и пролог-эпилог у функций, и вообще высокоуровневость языка. Вы же не знаете, в какие команды развернется код до метки и после.
Задумка была заменить адрес возврата из прерывания в стеке адресом за циклом.
Скорее всего, не сработает. Мало ли какие переменные компилятор успеет положить на стек в промежутке. Лучше покажите как организован сам цикл и что же за такая задача, что нужно отсчитывать секунду, но при этом нельзя проверять переменные.
Задумка была заменить адрес возврата из прерывания в стеке адресом за циклом.
А если адрес возврата не в стеке? В ARM адрес возврата изначально находится в LR и в стек попадает не всегда. Учите матчасть архитектуру ARM!
Если уж так хочется выскочить из цикла при помощи ISR, то можно: 1) до вызова (CALL) процедуры с циклом, сохранить регистры R4-R11,LR,SP(соответствующий) в глобальную переменную; 2) найти начало стека прерываний, найти адрес возврата в нём; 3) если он - внутри прерываемой функции - подменить его на адрес кода, который восстановит сохранённые ранее регистры и сделает переход на команду за CALL. Это если не используется FPU. Если используется - регистров сохранять/восстанавливать нужно больше.
Это всё для случая, если процессор работает в режиме с двумя стеками. Если же режим - с одним стеком, да ещё с вложенными прерываниями - всё будет намного сложнее. И сомневаюсь, что начинающий, не понимающий как в деталях работает процессор - осилит такую задачу.
PS: В качестве простого решения, доступного даже начинающему, можно посоветовать для того мега-цикла создать отдельную задачу ОС. Когда нужно преждевременно выйти из цикла: из ISR активируем другую задачу (управляющую), с более высоким приоритетом, и в ней - убиваем прерываемую задачу. Всё. Ну или можно даже не убивать, а из управляющей задачи отредактировать контекст задачи мега-цикла.
p_stek=(uint32_t*)__get_MSP(); // текущий адрес вершины стека flag_stek=1; // флаг
.....здесь заполнение регистров данными. Стек не меняется. Смотрел в asm листинге.
do{ Нет переходов на другие функции. Работа только с регистрами. Стек не меняется. Смотрел в asm листинге. Накопление данных. Если прерывание, то данные не нужны. n--; } while (n!=0) ;
... сохранение данных из регистров. Стек не меняется.
Переменные, с которыми идёт работа в разных процессах (например - в фоновой задаче и в ISR), следует объявлять с квалификатором 'volatile'. Это следует запомнить как "Отче наш".
Вы не поняли. Вас попросили показать сам цикл, из которого нет возможности выйти по какому-нибудь флагу.
Пусть для примера будет программный DDS генератор. Программа крутиться во while(1){} и нужно как-то выйти. Просто это уход в сторону от поставленной задачи. Куда поставить в цикл 3 строчки кода (чтение, сравнение, переход), которые при правильном расположении займут 3 такта у меня опыт есть. Можно сделать и счетчик цикла глобальной переменной, то тогда можно обойтись и 2 доп. тактами (чтение, запись). Из минусов: дополнительно занят 1 регистр для адреса счетчика цикла.
если прямо максимально быстро нужно, тогда и обработчик прерываний и таблицу векторов в CCM пихайте, а не только свою функцию.
Таблица там, как некоторые обработчики, от которых требуется быстродействие. А обработка кнопки может и во флеши сидеть. Нужно дождаться окончания дребезга. Основное быстродействие нужно в цикле.
Есть функция . В ней метка к примеру aaa: . В Си (не переходя в asm) есть возможность определить ее адрес и присвоить глобальной переменной? &aaa не работает. Пишу в IAR.
за то, по какому физическому адресу располагается тот или иной код, отвечает не компилятор, а компоновщик. про и IAR ничего не скажу, но в gcc можно вставить директиву __attribute__((section(".my_section"))) и дальше код пойдет с определенного адреса. обычно используется для размещения таблицы векторов. т.е. через скрипт компоновщика жестко привязать код к определенному адресу, полагаю, что можно.
Куда поставить в цикл 3 строчки кода (чтение, сравнение, переход), которые при правильном расположении займут 3 такта у меня опыт есть. Можно сделать и счетчик цикла глобальной переменной, то тогда можно обойтись и 2 доп. тактами (чтение, запись). Из минусов: дополнительно занят 1 регистр для адреса счетчика цикла.
Так если дополнительные пара тактов в теле цикла - не проблема, то зачем тогда весь этот огород? Сделать:
Код:
static u8 volatile flag = 0; do { ... if (flag) break; } while (--n);
Это добавит в код цикла всего две дополнительные команды: LDRB Rx, Rbase; CBNZ Rx,... которые в цикле будут занимать 2 или 3 такта (в зависимости от спаривания с соседними командами). Эту проверку лучше расположить ближе к концу цикла (чтобы была использована именно единственная CBNZ, а не пара CMP+BNE).
Если переменная 'flag' не находится в сегменте данных, в котором находятся рабочие переменные остального кода цикла, то конечно добавится ещё одна команда - предварительная загрузка Rbase указателем на 'flag' из секции кода: LDR Rbase, [PC, ...]. Но можно расположить 'flag' возле данных, обрабатываемых циклом. Тогда эта дополнительная LDR не будет нужна.
в gcc можно вставить директиву __attribute__((section(".my_section"))) и дальше код пойдет с определенного адреса. обычно используется для размещения таблицы векторов. т.е. через скрипт компоновщика жестко привязать код к определенному адресу, полагаю, что можно.
В компоновщике IAR такое тоже можно.
Кстати: Расположение и исполнение кода из ОЗУ даёт возможность адресовать через PC не только константы, но и переменные. И за счёт этого оптимизировать код (если можно адресоваться к переменным через PC, то не нужно будет грузить и держать в регистре указатель на секцию статических данных).
Таблица там, как некоторые обработчики, от которых требуется быстродействие. А обработка кнопки может и во флеши сидеть. Нужно дождаться окончания дребезга. Основное быстродействие нужно в цикле.
Выше вы писали, что если нажать на кнопку, то хотелось бы быстрее выйти из этого цикла...
Нужно дождаться окончания дребезга. Основное быстродействие нужно в цикле.
Если нужно "выходить из цикла по нажатию кнопки", то зачем "дожидаться окончания дребезга"? Как только с кнопки получен первый импульс нажатия - значит очевидно её начали нажимать. И неважно сколько она затем будет дребезжать. Можно вообще обойтись без прерывания: читать в цикле сразу регистр GPIO ноги кнопки и выходить из цикла по первому импульсу дребезга. А "дожидаться окончания дребезга" - уже вне цикла.
Добавлено after 9 minutes 30 seconds: PS: Пришёл в голову ещё более короткий и быстрый вариант выхода из цикла:
Код:
static s32 volatile flag = 1; s32 n = N - 1; //N - штатное кол-во проходов цикла do { ... } while ((n -= flag) >= 0);
В ISR для прерывания цикла нужно просто записать во 'flag' значение == N. Такой код должен добавить к циклу только одну дополнительную команду LDR Rx,[flag]. Которая займёт 1 или 2 такта.
Так если дополнительные пара тактов в теле цикла - не проблема
Проблема. Так получилось, что процессор должен работать на частотах кратным 2. С этими 2 тактами приходиться работать на 65,536 МГц. Без них на 32,768МГц.
Если нужно "выходить из цикла по нажатию кнопки", то зачем "дожидаться окончания дребезга" ?Как только с кнопки получен первый импульс нажатия ...
Идея понятна. В каких вариантах наверно можно применить. Но после выхода из цикла прога обновляет новые входные параметры и опять уходит в заплыв в этот цикл. Сделать загрузку входных данных во время дребезга, а прерывание включать перед входом в цикл.
Заголовок сообщения: Re: STM32 новичку в ARM что к чему
Добавлено: Ср сен 10, 2025 09:18:31
Держит паяльник хвостом
Карма: 16
Рейтинг сообщений: 205
Зарегистрирован: Вс дек 02, 2012 16:58:33 Сообщений: 936 Откуда: от туда
Рейтинг сообщения:0
ИМХО вы пытаетесь натянуть сову на глобус. Или другими словами АТмеловский подход с подсчётом тактов на АРМ процессор с конвейером. Займитесь чем-нибудь полезным. Подсчёт тактов при 160МГц тактовой и периоде процесса 1 секунда, и нажатии кнопки... За сколько тысяч тактов процессора вы нажмёте кнопку? Невозможность читать глобальные переменные в прерывании при едином адресном пространстве? Пишите исчо!
Невозможность читать глобальные переменные в прерывании при едином адресном пространстве? Пишите исчо!
Ну если бы они были, то и диспута не было. Разговор шел сделать без них з.ы. По поводу тактов возник вопрос. Команда LDR R0,[R1, #+0]; лежит уже в конвейере. До нее и после команд чтения и записи нет. За сколько тактов должна обработаться? За 2 или 3? процессор STM32G431.
Команда LDR R0,[R1, #+0]; лежит уже в конвейере. До нее и после команд чтения и записи нет. За сколько тактов должна обработаться? За 2 или 3? процессор STM32G431.
на разных частотах одни и те же инстркуции могут выполняться за разное количесво тактов. зависит от flash latency для данной частоты.
Она уже загружена в контейнер и ждет своего выполнения т.е. уже "flash latency" программа уже прошла. Идет процесс без задержек, линейное выполнение программы, без переходов.
Для портативного устройства или проц. работает на 128МГц или на 32МГц разница есть.
Когда-то занимался портативными приборами, использовал ADuC8xx. Когда ждал нажатия кнопки на приборе, тактировал ядро 32кГц (килогерц). Когда работал АЦП, вообще отключал тактирование всего, кроме АЦП. А вот для выполнения расчётов выводил ядро на максимальные 12МГц (мегагерц). В МК на ARM очень гибкая система тактирования, позволяющая управлять частотой не только процессора, но и шин, и периферии. Если занимаетесь портативной техникой, то без этого никак не обойтись.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения