WiseLord писал(а):Забавно... Прогуглив этот вопрос наткнулся на одно своего рода исследование:
У автора получился вариант с PORTx |= (1<<bit) самым быстрым. Вдвое быстрее чем запись в PINx.
автор делал не запись PINх, а модификацию, т.е. использовал лишние операции считывания значения регистра и изменения значения, хотя на самом деле нужно было делать именно запись единицы в нужный разряд
Но только всё равно интересно, работает ли это на популярных ATmega8/16/32(A). В их даташитах такая фича не описана. У ATmega48/88/168, ATtiny2313 - описана.
WiseLord, спецификация на то она и есть, чтобы описывать то что есть.
Чего нет - в ней не описывают.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
#define KeeLoq_NLF 0x3A5C742E
#define bit(x,n) (((x)>>(n))&1)
#define g5(x,a,b,c,d,e) (bit(x,a)+bit(x,b)*2+bit(x,c)*4+bit(x,d)*8+bit(x,e)*16)
/// шифрование
uint32_t KeeLoq_Encrypt (uint32_t dattta,uint64_t key){ //uint32_t data, uint64_t key
uint32_t x = dattta, r;
for (r = 0; r < 528; r++){
x = (x>>1)^((bit(x,0)^bit(x,16)^( uint32_t)bit(key,r&63)^bit(KeeLoq_NLF,g5(x,0,9,20,26,31)))<<31);
}
return x;
}
/// дешифровка
uint32_t KeeLoq_Decrypt ( uint32_t dattta, uint64_t key){
uint32_t x = dattta, r;
for (r = 0; r < 528; r++)
x = (x<<1)^bit(x,31)^bit(x,15)^( uint32_t)bit(key,(15-r)&63)^bit(KeeLoq_NLF,g5(x,0,8,19,25,30));
return x;
}
Конечно очень мудрёный код,по крайне мере для меня, так вот на функцию шифратора компилятор ругается, а на дешифратора нет. Вроде код почти одинаковый. Что не так подскажите? А это WinAvr выдаёт ошибку
Make_data.c:26: error: unable to find a register to spill in class 'POINTER_REGS'
Make_data.c:26: error: this is the insn:
(insn 52 50 53 3 Make_data.c:22 (set (reg:SI 24 r24 [63])
(and:SI (subreg:SI (reg:DI 62 [+1 ]) 0)
(const_int 1 [0x1]))) 43 {andsi3} (nil))
Make_data.c:26: confused by earlier errors, bailing out
Вероятно выражение получилось слишком большим для разбора для данного компилятора и на каком-то этапе не хватило регистров... За что я не люблю такие "краткие" записи выражений, что их фиг потом разберешь даже вручную.
Если вместо data1 в функции пишу 0,1,2 , т.е. display_buffer = ascii_5x7[i+((0)*5)] , то символ отображается нормально, т.е. восклицательный знак и далее символы ascii.
Но если передаю эти данные через функцию Load_Data (0) в программе, то какая-то билиберда выходит на дисплее. Т.е. копирование происходит уже как-то не так. Подозреваю, что что-то совсем простое я упустил...
Вопрос снят, таблица ascii занимала всю память МК (в моём верхнем примере я её укоротил) и display_buffer не помещался, подправил-уменьшил таблицу ascii и все заработало.
Решил немножко переписать код своего проекта в том стиле, чтобы подключать кнопки/дисплеи и т.п. можно было бы к любым портам в любом порядке.
Т.е. что-то типа #define DISPLAY_DATA_DDR DDRA с жёстким требованием подключения 8 портов данных дисплея к одному порту МК в том же порядке, превратилось в отдельные определения DISPLAY_DATA_0, DISPLAY_DATA_1, .. DISPLAY_DATA_7, которые можно было бы подключать уже к любым портам МК.
Функции переписаны под новый вариант, и всё работает. Но мне интересно, можно ли как-то упростить эти однотипные записи во втором варианте до однострочных (содержащих в аргументах , например, префикс KS0108_RES и номер 7), чтобы уже препроцессор развернул их до четырёх определений каждую?
я сделал (и периодически пополняю его) файлик с полезными макросами (прилагаю).
и в вашем случае сделал бы с его помощью определил бы макросом только БУКВУ порта и номер ножки для каждой линии дисплея
PORT(DI_PORT) |= _BV(DI_PIN); // выдать единицу в DI
DDR(RW_PORT) |= _BV(RW_PIN); // настроить линию ввода-вывода
uint8_t tmp = PIN(DI_PORT) & _BV(DI_PIN); // считать состояние линии DI
и так далее.
то есть свести описательную часть дефайнов только к необходимомому минимуму, а остальное перенести в часть реализации. ну, если вам совсем невмоготу, можно и дополнить в вашем стиле:
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реализовал в итоге так определения, а так - работу с портом.
Код, конечно, немножко вырос в размере. Но совсем немножко, и это небольшая плата за то, что сейчас проект можно легко портировать на любую другую достаточную для него AVR-ку не заморачиваясь потом с разводкой платы.
Я решение такое же применяю, единственное что я определения не в одном месте описываю (как у вас - дисплей, кнопки, энкодер и прочее...), а в хедерах библиотек, поэтому в каждой либе есть немного своих определений, и их небольшое количество - не напрягают в обычном виде... т.е. все таки по 2 - 3 определения на линию...
Только порт и линию называю по другому... вот так - ST7920_PORT0, ST7920_DDR0, ST7920_PIN0, ST7920_LINE0... вроде все однотипно, никаких лишних макросов (я их не долюбливаю), записи получаются - короче некуда, и сразу понятно что за операция... в общем - я балдю со своего стиля ...
data = 0;
if (ST7920_PIN0 & ST7920_LINE0) data | (1<<0);
if (ST7920_PIN1 & ST7920_LINE1) data | (1<<1);
if (ST7920_PIN2 & ST7920_LINE2) data | (1<<2);
if (ST7920_PIN3 & ST7920_LINE3) data | (1<<3);
if (ST7920_PIN4 & ST7920_LINE4) data | (1<<4);
if (ST7920_PIN5 & ST7920_LINE5) data | (1<<5);
if (ST7920_PIN6 & ST7920_LINE6) data | (1<<6);
if (ST7920_PIN7 & ST7920_LINE7) data | (1<<7);
Вот например управление сдвиговым регистром:
Спойлер
shads писал(а):Я решение такое же применяю, единственное что я определения не в одном месте описываю
Я, вообще, тоже. Но тут просто решил в данном конкретном случае всё вынести в одно место для более лёгкого возможного портирования.
shads писал(а): вот так - ST7920_PORT0, ST7920_DDR0, ST7920_PIN0, ST7920_LINE0
LINE - это хороший вариант. Я никак всё не мог придумать синоним, так и оставил PIN, что, действительно, создаёт некоторую путаницу. Но вот насчёт остального - в том-то и был смысл, чтобы заменить три необходимых для вашего случая определения
и вызов PORT/PIN/DDR через общий макрос PORT(ST7920_D0)/PIN(ST7920_D0)/DDR(ST7920_D0), что значительно уменьшает количество строк, нужных для этих определений, с трёх до одной.
А PIN в LINE я, пожалуй, действительно переименую.
И при компиляции вылезает "... error: #error "F_CPU not defined" равно как и "... warning: #warning "F_CPU not defined". Можно как-то не писать еррор еоррор и варнинг варнинг два раза два раза?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]