Да ничего. Подход рабочий, но неэффективный. Если хватает ~10 FPS (украдём от озвученных ранее 13 немного на другой код помимо отрисовки) - то и хорошо.
Я и сам первоначально так же делал - обновлял из видеобуфера дисплей в конце главного цикла. Но можно буквально совсем немного переделать, то что уже есть - и станет намного шустрее всё.
У Вас там в любом случае есть код вроде такого: Спойлер
update_display() { for (int i = 0; i < W; i++) { char cmd; // позиционирование WR = 0; write_display(cmd1); write_display(cmd2); write_display(cmd3); WR = 1; // посылка данных for (int i = 0; i < H / 8; i++) { index = ...; char data = buffer[index]; write_display(data); } }
Его очень легко переделать на конечный автомат, по сути сделав i, j статическими переменными. Так, чтобы каждый вызов update_display() посылал ровно один байт данных. Тогда, дёргая этот вызов из прерывания таймера раз в 60мкс и убрав в коде обычную задержку получим ровно то же самое по сути, только дисплей будет обновляться автоматически, без использования главного цикла. А задачей самого же главного цикла останется только подкладывание нужных байтов в видеобуфер.
То есть, весь конечный автомат построен на двух переменных (i, j). Переменная j на каждом прерывании таймера инкрементируется (от 0 до 31), записывая последовательно данные в выбранный ряд. Следующая фаза - j=32 - установка номера страницы, за который отвечает i. Следующая фаза j=33 - установка адреса начало страницы в ноль и сразу же перевод дисплея в режим чтения. Следующая фаза j = 34 - читается состояние на порту дисплея. Ну а дальше - переход в фазу 0 и всё по кругу - в выбранную страницу записывается пачка данных (32 байта) из буфера.
То есть, помимо того, что запись в дисплей идёт "в фоне", практически не задерживая главный цикл, наличие таймера позволяет параллельно регулировку яркости через ШИМ и периодом 34 * 60 = ~2мс (500Гц) опрашивать состояние ножек на линии данных дисплея. То есть, там ещё могут висеть до 8 кнопок (замыкающихся на землю через резистор)
Вот, у Вас ещё и чтение из буфера неоптимально сделано - на каждой процедуре записи запускается цикл на 8 элементов, собирающих байт для записи в дисплей из разных битов в буфере.
Лучше биты раскладывать на этапе записи в буфер, а читать сразу готовые байты последовательно из массива.
P.S. Вот я попробовал на примере показать, как я бы постепенно (main1.c => main5.c) перешёл на возможность вызывать Ваш код так, чтобы задержка была не внутри него, а извне. Ну, или по таймеру в уже самом последнем варианте.
main1.c - исходный вариант
main2.c - добавляю фазы -2 и -1 для переменной x, чтобы единообразно отправлять low_WrComDat в одном цикле
main3.c - избавляюсь от внутреннего цикла по y, вынося его наружу, запоминая текущую фазу y в уже глобальной переменной (в принципе, её можно и внутри функции статической оставить)
main4.c - избавляюсь от внутреннего цикла по x, вынося его также наружу. Это позволяет также задержку изнутри low_WrComDat() вынести наружу.
Теперь ничто не мешает вызывать Screen_Update откуда угодно. Можно оставить как есть, полностью имитируя старое поведение (вызывать в конце главного цикла 34*32 раз) с задержками. Можно вызывать в конце главного цикла всего лишь 1 раз с одной задержкой - то есть, каждый проход главного цикла будет обеспечивать запись лишь 1 байта в экран (а команды или данных - конечный автомат на x/y сам разберётся), лишь с 1 задержкой на 60мкс
main5.c - а также можно теперь Screen_Update просто вызывать из прерывания таймера, вообще избавившись от любых задержек в главном цикле.
биты раскладывать на этапе записи в буфер, а читать сразу готовые байты последовательно из массива.
просто я тогда не стал заморачиваться и оставил организацию буфера как у KS0107, для универсальности. В реале на паялке оно выдает 15 фпс, на спекруме конечно меньше, т.к. там идет активный обмен по кв.шине, но меня вполне устраивает не вижу смысла переделывать, разве что для спортивного интереса тем более, еще не измерена инерционность самого стекла
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
не вижу смысла переделывать, разве что для спортивного интереса
Ну так в спортивном-то интересе самый смак. Мне и самому было бы интересно узнать, что из этого бы получилось, тем более что идею - что имнно и в каком порядке делать - для ST7920 я расписал. Для KS0108 принцип был бы тот же - постепенно избавиться от циклов, вынеся их переменные наружу.
Технически, до самого последнего момента (переноса в прерывание) всё должно отрабатывать фактически с той же скоростью (поскольку задержки всё ещё присутствуют), и только на последнем этапе ожидается резкий скачок FPS
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
Скачка ФПС не будет. Ибо 80 мкс на команду никуда не денутся. А вот скачок idle - будет. И это хорошо. А более правильно этот дисплей переводить на камушек с ДМА. Я пробовал на СТМ - удобно. Хватает времени на всё. А вообще - для большинства задач взаимодействия с пользователем и 10 фпс хватит. И времени на обработку действий юзера. Или вообще - обновление только по требованию. Возникло событие - перерисовали и обновили.
Скачка ФПС не будет. Ибо 80 мкс на команду никуда не денутся.
Может, я не так выразился. Говоря о FPS, я имел в виду, сколько главных циклов в секунду может выполнять программа. Тут число вполне может поменяться с 15 на, например, 2000, если нет каких-то тяжёлых вычислений. Если есть (типа Фурье анализа того же) - может поменяться с 15 до, скажем например, 50. А обновление дисплея - да, быстрее не станет. Но оно будет сконцентрировано не в одном месте (в конце главного цикла), а "размазано" равномерно по времени выполнения.
slav0n писал(а):
при выводе текста никакой разницы. выигрыш, казалось бы, при выводе графики, но, учитывая тормознутость матрицы, он тоже под вопросом.
В целом, да. Я просто на основании своего опыта рассуждаю, когда в проекте анализатора спектра такое небольшое, казалось бы, изменение в коде позволило раза в 2 увеличить FPS. Грубо, если для обновления дисплея требуется 50мс, и на расчёты (Фурье) - те же 50мс, то Ваш подход даст 100мс общей задержки - т.е. обработка сигнала будет возможна только 10 раз в секунду. А обновление по таймеру как раз даст возможность обработать сигнал 20 раз в секунду, невзирая на то, насколько быстрый или медленный дисплей.
зачем мне оно, если у меня на мега32 единственное прерывание ISR(TIMER0_OVF_vect) вызывается с периодом 0.781 ms при этом: дисплей, 3 ШИМа, 2 ПИДа, энкодер, музыка... все работает даже TIMER1 не задействован
попробовал ЭТО, типа, оптимизировать, а компилятор совершенно не отреагировал на изменения
Код:
void Screen_Update(void) { static u8 y = 0; static s8 x = -2; u16 s = (y * 16) & 0x0180;//0b110000000 const u8 mask = shift_1_left[y % 8]; u8 com = 1; u8 d = 0x80; if (x == -2) { d += y;//com } else if (x == -1) { // d = 0x80 + 0;//com } else { com = 0; d = 0; if (x == 16) s += 512; u16 p = (x % 16) * 8 + s; u8 m = 0b10000000; for (u8 i = 0; i < 8; i++) { if (VIDEObuf[p + i] & mask) d += m; m >>= 1; } } low_WrComDat(d, com);
if (++x >= 32) { x = -2; ++y; y %= 32; } }
Добавлено after 19 minutes 9 seconds: а вот так, минус 12 байт бинарника
Код:
void Screen_Update(void) { static u8 y = 0; static s8 x = -2; u16 s = (y * 16) & 0x0180;//0b110000000 const u8 mask = shift_1_left[y % 8]; u8 com = 1; u8 d = 0x80; if (x >= 0){ com = 0; d = 0; if (x == 16) s += 512; u16 p = (x % 16) * 8 + s; u8 m = 0b10000000; for (u8 i = 0; i < 8; i++) { if (VIDEObuf[p + i] & mask) d += m; m >>= 1; } } else if (x == -2) { d += y;//com } low_WrComDat(d, com);
if (++x >= 32) { x = -2; ++y; y %= 32; } }
Добавлено after 5 hours 18 minutes 56 seconds: осталось позагонять в статики игрик икс зависимые переменные, но НАХУЯ?!!
Нет смысла. Для x и y нужно сохранять своё значение между вызовами функции, поэтому static. Остальные переменные всё равно через них рассчитываются, и делать ещё и их static смысла нет.
идея такая, размазываем вычислительные сопли по прерыванию
Код:
void Screen_Update(void) { static u8 y = 0; static s8 x =-2; static u16 s = 0; static u8 mask = 1; u8 com = 1; u8 d = 0x80; if (x >= 0){ com = 0; d = 0; if (x == 16) s += 512; u16 p =(x % 16)* 8 + s; u8 m = 0b10000000; for (u8 i = 0; i < 8; i++, m >>= 1) if (VIDEObuf[p++]& mask) d += m; } else if (x ==-2){ d += y;//com } low_WrComDat(d, com); if (++x >= 32){ x =-2; ++y; y %= 32; s =(y * 16)& 0x0180;//0b110000000 mask = 1 <<(y % 8); } }
Ну.. это всё пока выглядит просто как попытки сэкономить пару байтов прошивки. Хотя по скорости, может быть, и медленнее будет, чем без лишних static-ов.
Но вообще оно у Вас, как я понимаю, в целом заработало? Именно при вызове из прерывания, а не основного цикла? Если да, то дало ли эффект видимый? Ведь ради этого всё затеивалось...
Подскажите плз: Начал разбираться с дисплеем сначала в текстовом режиме. Проблема в том, что все символы кроме иероглифов выводятся сразу по 2 в знакоместо 16х16. Можно ли как-то изменить сетку? Или иначе отрисовывать стандартные символы по одному? Или это только в граф. режиме?
UDP: разобрался. лишний строб E приводил к задвоению всего и вся.
Товарищи! Откопал дисплей 12832. При попытке опознать, наткнулся на st7920. На моём выведена колодка 16 контактов с очень похожей распиновкой. Но есть отличие. Нет на плате подстроечника контрастности. Из мануала на контроллер нашел схему, где не используется удвоитель и все питается от VCC На моей плате все так же, кроме того, что все резисторы R1-R5 на 4.7 кОма (в мануале почему-то R3 указан 2к2), а также вместо R10 у меня установлен не потенциометр, а простой резистор и номинал его 51 Ом! Сигнал V0 с контроллера идёт и на этот резистор и на колодку на 3 контакт. Пока не подключал дисплей к МК, но при подаче питания 5В все пиксели темные. Подсветка странная. Подавать 5В на нее побоялся, так как резистор там стоит 15 Ом всего. Пробовал на режиме диода замер сделать - ничего. Возможно, подсветка на нескольких последовательных диодах сделана.
может кому пригодится: st7920 перевёрнутый, шрифты русский и английский. Компилятор Bascom 2.0.8.3 адресация по y - 0-7, по x парами! прикрепляю файл шрифтов, так некоторые не нужные МНЕ символы заменены иными. Всё расписано внутри! Символы только заглавные, для экономии памяти МК.
Добавлено after 2 minutes 58 seconds: Прямой вывод, крупный шрифт 16*16 точек Компилятор Баском 2.0.8.3
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 31
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения