Я когда-то задавался вопросом, можно ли выводить на порты по индексу. Я не знаю, когда добавили эту плюшку, но в то время мне говорили, что это на AVR невозможно. Я попробую ваш пример. Что из того получится. ARV, Reflector кто там еще. Предлагаю добить. Задачи: Произвольные порты, выбор активного уровня. Вы мне тут показали, что вроде как можно по индексу на порты вывести. Покажите макросы и добиваем совместными усилиями. Результат выложим тут.
Этот топик на этом форуме впервые за долгое время очень информативен и плодотворен.
Demiurg писал(а):мне говорили, что это на AVR невозможно
меньше надо глупости слушать.
со времен WinAVR это работает, поскольку у AVR порты ввода-вывода отображены на адреса ОЗУ, и нет таких портов, к которым не разрешен доступ командами lds-sts, (наоборот - есть: бывают порты, к которым нельзя обратиться командами in-out).
ARV, не могу понять, где в вашем примере условие, по которому заканчивается цикл for? Заработало, теперь осталось сделать на основе вашего примера выбор активного уровня. Если честно, такой (как у вас) способ впервые вижу...
[uquote="Demiurg",url="/forum/viewtopic.php?p=3883190#p3883190"]Предлагаю добить. Задачи: Произвольные порты, выбор активного уровня. Вы мне тут показали, что вроде как можно по индексу на порты вывести. Покажите макросы и добиваем совместными усилиями.[/uquote]
Шаблоны так не работают... Допустим есть такой список пинов:
В этот момент создает экземпляр класса и в первую очередь внутри него из первоначального списка формируются индексированный список, т.е. пины нумеруются, потому что потом они будут из списков удаляться, а индекс будет нужен. Кроме того списки могут вместо пинов принимать другие списки, но в индексированном списке уже все разворачивается до одних пинов. Также создается список портов присутствующих в списке, проверяется наличие дубликатов пинов и вычисляет размер развернутого списка. Все эти дополнительные списки существуют чисто виртуально на этапе компиляции. Но основные расчеты начинаются когда дело доходит непосредственно до write(), там компилятор сортирует пины по портам и для каждого порта ищет последовательности пинов которые можно было бы получить за один заход по вычисленной маске. В данном случае для порта PA будет получена маска 0x16(для PA4, PA2, PA1), 0x40(для PA6) и еще одна специфическая маска для портов STM32. Для AVR, насколько помню, получилось бы что-то типа такого:
void handle_segments_2 (void)
{
u08 data = table_7_segm_char [dsp_buf [cnt_commons]];
volatile u08 *p;
for(u08 i=0, m=1; m; i++, m<<=1)
{
p = segments_pins[i].port;
/*
if (segments_level == HI)
*p = (*p & (~segments_pins[i].mask)) | (data & m ? segments_pins[i].mask : 0);
else
*p = (*p & (~segments_pins[i].mask)) | (data & m ? 0 : segments_pins[i].mask);
*/
*p = (*p & (~segments_pins[i].mask));
if (segments_level == HI)
*p |= (data & m ? segments_pins[i].mask : 0);
else
*p |= (data & m ? 0 : segments_pins[i].mask);
}
}
А теперь господа об эффективности. Код короче. Спору нет. Но расплата - разворот в дизасме. Эффектно в коде, неэффективно в дизасме.
Я знал об этом, но мне интересно было, как реализовать доступ к портам и пинам по индексу.
Как бы то ни было, считаю этот топик успешным.
это, в принципе, не факт. во всяком случае, совсем не очевидно: сдвиги компенсируют наличие условных переходов, так что будет ли выигрыш - вопрос.
Demiurg писал(а):где в вашем примере условие, по которому заканчивается цикл for?
как это где? где ему и положено быть: на втором месте в теле оператора for:
ARV писал(а):for(uint8_t i=0, m=1; m; i++, m<<=1)
специльно выделил
Demiurg писал(а):Но расплата - разворот в дизасме.
как я уже говорил, не такая уж и большая расплата: у вас было
Demiurg писал(а):133 такта, 8.31 мкс при тактовой частоте 16 мгц.
При втором методе 545 тактов и 34 мкс
по моим оценкам у меня ровно посредине между вашими результатами: порядка 300 тактов. так что вполне приемлемо, имхо. но по восприятию кода - и сравнивать не возьмусь
[uquote="ARV",url="/forum/viewtopic.php?p=3883183#p3883183"]по листингу у меня вышло около 235 тактов на вывод символа, не считая пролога-эпилога обработчика прерывания.[/uquote]
Значит и мой вариант вполне себе ничего… у меня тоже вышло 235 тактов на вывод цифры, начиная с момента вызова прерывания и выхода из него.
Самсусамыч писал(а):начиная с момента вызова прерывания и выхода из него
у меня без учета этого.
я уже неоднократно свою позицию говорил: если нет острой необходимости, то для чего экономить такты/байты? гораздо правильнее, имхо, облегчить свою участь, т.е. написать просто, легко, понятно и быстро, а уж будет оно 5 мкС или 10 мкС исполняться - не важно. и вот как раз в этом случае есть смысл делать универсальные библиотеки - лишь бы все просто и легко.
а когда нужда заставляет - тогда в руки ассемблер, и вперед! но у меня нужды давно не возникало в этом...
[uquote="ARV",url="/forum/viewtopic.php?p=3883235#p3883235"]...[/uquote]
Я на сегодня закончил. Что у меня получилось с вашим примером. IAR, максимальная оптимизация balanced. Более 300 тактов. И это только вывод сегментов. А у вас в примере только он и есть. Вывода общих выводов нет. Кстати, получилось сделать выбор активного сигнала.
Завтра ещё поэкспериментирую, сделаю вывод общих выводов. Отпишусь.
[uquote="ARV",url="/forum/viewtopic.php?p=3883235#p3883235"]это, в принципе, не факт. во всяком случае, совсем не очевидно: сдвиги компенсируют наличие условных переходов, так что будет ли выигрыш - вопрос.[/uquote]
Да ладно... В первом случае одно чтение из регистра, одна запись, 5 бинарных операций и 3 сдвига(может и 2), итого ~10 тактов.
Во-втором случае одно чтение/запись, 5 бинарных операций, 4 двухтактовых перехода и потом еще опционально 3+3+3+3, итого минимум 15 тактов, максимум - 27, в среднем - 21.
[uquote="ARV",url="/forum/viewtopic.php?p=3883254#p3883254"]и чо?[/uquote]
Чо по китайский (_._). Конечно, спасибо за пример. В будущем пригодится, давно искал вывод в порты по индексу.
Но, но... Расплата высока. Проще в лоб. По первому способу. Да, писанины порядочно. Но выхлоп эффективен.
У вас легко, просто, выхлоп же... А диалог разгорелся про эффективность.
Там "легко, просто", там. В итоге набирается по тактам при таком подходе.
Так что, диалог про эффективность считаю закрытым.
Краткость кода, "легко и просто" - не равно эффективность.
у меня абсолютно ничего не разгоралось. для меня важна эффективность моего труда, а микроконтроллер - он кремниевый, не потеет и не устаёт, ему до лампочки, что делать: в главном цикле nop-ы исполнять или расчеты сегментов делать.
у меня тоже получилось нарисовать эффект (какой автор в начале рисовал) и циферки
даже в протеусе работает Спойлер/*****************************************************
#include <mega8.h>
#include <delay.h>
unsigned char digit_out[4], // буфер экрана (нумерация от 0 до 4 разрядa)
cur_dig; // тек.высвечиваемый символ (позиция)
unsigned int ff=200, // время кадра c шим
f=500, // время кадра
h=1, // число повторов эффекта
yarkost; // яркость
[uquote="ARV",url="/forum/viewtopic.php?p=3883259#p3883259"]для меня важна эффективность моего труда, а микроконтроллер - он кремниевый, не потеет и не устаёт, ему до лампочки, что делать: в главном цикле nop-ы исполнять или расчеты сегментов делать.[/uquote]
Про микроконтроллер абсолютно согласен. Про эффективность мы опять пришли в тупик. Вы о своём, я о своём. На этом закончим. Тем более, что я ещё не закончил эксперименты.
Добавлено after 3 minutes 38 seconds:
[uquote="Serzh2000",url="/forum/viewtopic.php?p=3883267#p3883267"]...[/uquote]
Видео в студию.
Я закончил с экспериментами. Выкладываю окончательный вариант. Реализовано: произвольный выбор портов и пинов. Выбор логики управления сегментами и разрядами. За идею обращения к портам по индексу ARV отдельная благодарность.
Проект проверен на отладочной плате STK-500.
В текущей версии проекта прогон вывода сегментов и разрядов занимает 566 тактов. 35.38 мкс. Когда я чуток изменил логику, получилось - 507 тактов. 31.69 мкс. При тактовой частоте 16 МГц.
Спойлер