Какой способ быстрее инициализировать регистры в микроконтроллере? - PullRequest
5 голосов
/ 18 июня 2019

Этот вопрос возник у меня во время написания некоторой прошивки для микроконтроллера PIC.

Есть два метода, которые я знаю для инициализации регистров в микроконтроллере.Скажем для примера, если мы инициализируем порт как выходные данные, один из способов - написать команду, подобную следующей, и она назначит 1 каждому биту в регистре TRISx

Метод 1

TRISX = 0xFF;

То же самое можно сделать, назначив биты индивидуально.

Метод 2

_TRISX0 = 1;
_TRISX1 = 1;
_TRISX2 = 1;
...
_TRISX7 = 1;

У меня вопрос, так ли это?компилятор лечит вас одинаково, а время, затрачиваемое на выполнение обеих операций, одинаково?Или метод 1 занимает один такт, а метод 2 - 8 (я имею в виду примерно в 8 раз медленнее)?

Я попытался прочитать Руководство по компилятору X16 , но не смог найти никаких подсказок.

Ответы [ 3 ]

11 голосов
/ 18 июня 2019

Аппаратные регистры всегда квалифицированы volatile, и компилятору не разрешено оптимизировать код, содержащий volatile доступ. Так что, если вы напишите им 8 раз, то вы получите 8 записей. Это, конечно, намного медленнее, чем 1 запись.

Кроме того, очень плохо записывать в регистры несколько раз подряд, как если бы они были временной переменной в ОЗУ. Аппаратные регистры, как правило, имеют различные побочные эффекты. Они могут иметь атрибут «однократная запись» или принимать записи только в определенных режимах. Записывая их в несколько этапов, вы приобретаете привычку создавать всевозможные сумасшедшие, тонкие проблемы, вызванные неправильными настройками регистра.

Правильная практика - записывать в регистры один или несколько раз по мере необходимости.

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

Предположим, REGISTER - это имя аппаратного регистра, сопоставленного с памятью, volatile, затем ...

Не делай этого:

MASK1 = calculation();
REGISTER |= MASK1;
MASK2 = calculation();
REGISTER |= MASK2;

Сделайте это:

uintx_t reg_val=0; // temp variable in RAM
MASK1 = calculation();
reg_val |= MASK1;
MASK2 = calculation();
reg_val |= MASK2;
REGISTER = reg_val; // single write to the actual register
7 голосов
/ 18 июня 2019

Это будет зависеть от набора команд процессора и компилятора.Например, для PIC18F45K20 компилятор sdcc компилирует следующие значения

TRISDbits.TRISD0 = 1;

в

BSF _TRISDbits, 0

, а компиляцию

TRISD = 0xFF;

в

MOVLW   0xff
MOVWF   _TRISD

Таким образом, в этом случае установка отдельного бита происходит быстрее, поскольку не требует помещения временного значения в рабочий регистр.

Однако не все наборы команд включают инструкцию BSF, инекоторые архитектуры не требуют использования рабочего регистра для последней задачи.

PS Приведенные выше примеры основаны на выводе компилятора sdcc, но я думаю, что компиляторы xc8 и xc16 дают аналогичныеРезультаты.

PPS При проверке сгенерированной сборки помните, что некоторые инструкции потребляют больше тактов процессора, чем другие.Подробнее см. Таблицу данных.

1 голос
/ 18 июня 2019

Во-первых, вы не предоставили C-код, чтобы показать, как эти биты действительно ссылаются. Но скажем, это через объединение и структуру битовых полей.

Наилучшим способом является проверка ASM, который генерирует компилятор. Вам действительно нужно знать свою hw arch, но вам все равно нужно взглянуть на сгенерированный ASM, чтобы действительно знать.

Чтобы назначить только один бит, скажем _TRISX0 = 1; vs TRISX = 0x01; в зависимости от арки и компилятора возможно, что компилятор может сгенерировать более эффективный (меньше циклов и может быть меньше команд) код только для однобитового назначения, чем весь регистр. Существует по крайней мере один такой процессор и компилятор MCU / DSP от TI, для которого я знаю, что это правда.

Для случая, когда у вас есть несколько (> 1) операторов, ваш метод 2 с отдельными битовыми назначениями, вероятно, что ваше однострочное регистровое назначение будет более или менее эффективным: если компилятор выводит - неправильно или нет - то все эти битовые присвоения присваивают одному и тому же регистру в последовательности, он может заменить их однострочными, как вы могли бы сделать в методе 1.

Я не имею в виду ПИК. Я советую проверить ASM для любого MCU, когда вы заботитесь.

...