Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Ответить

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Ср окт 06, 2021 15:50:20

ну, и шо?
Да ничего. Подход рабочий, но неэффективный. Если хватает ~10 FPS (украдём от озвученных ранее 13 немного на другой код помимо отрисовки) - то и хорошо.

Я и сам первоначально так же делал - обновлял из видеобуфера дисплей в конце главного цикла. Но можно буквально совсем немного переделать, то что уже есть - и станет намного шустрее всё.

У Вас там в любом случае есть код вроде такого:
Спойлер
Код:
write_display(char data)
{
      PORTB = data;
      strob();
      big_delay_us(60);
}

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мкс и убрав в коде обычную задержку получим ровно то же самое по сути, только дисплей будет обновляться автоматически, без использования главного цикла. А задачей самого же главного цикла останется только подкладывание нужных байтов в видеобуфер.

P.S. Если интересно, применение озвученного подхода можно глянуть здесь: https://github.com/WiseLord/ampcontrol/ ... rc/display - файлы st7920.c/h.

То есть, весь конечный автомат построен на двух переменных (i, j). Переменная j на каждом прерывании таймера инкрементируется (от 0 до 31), записывая последовательно данные в выбранный ряд. Следующая фаза - j=32 - установка номера страницы, за который отвечает i. Следующая фаза j=33 - установка адреса начало страницы в ноль и сразу же перевод дисплея в режим чтения. Следующая фаза j = 34 - читается состояние на порту дисплея. Ну а дальше - переход в фазу 0 и всё по кругу - в выбранную страницу записывается пачка данных (32 байта) из буфера.

То есть, помимо того, что запись в дисплей идёт "в фоне", практически не задерживая главный цикл, наличие таймера позволяет параллельно регулировку яркости через ШИМ и периодом 34 * 60 = ~2мс (500Гц) опрашивать состояние ножек на линии данных дисплея. То есть, там ещё могут висеть до 8 кнопок (замыкающихся на землю через резистор)

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Ср окт 06, 2021 16:54:11

малі діти...
WiseLord писал(а):У Вас там в любом случае есть код вроде такого:
лично мой код вроде такого, самодостаточный, без статиков
не требует прерываний
Код:
void Screen_Update(void)
{
#ifdef ST7920
//ST7920
   for(u8 y=0; y<32; y++){   
      low_WrComDat(0x80 + y, 1);//com
      low_WrComDat(0x80 + 0, 1);//com
      u16 s = (y * 16) & 0x0180;//0b110000000
      
      const u8 mask = shift_1_left[y % 8];
      
      for(u8 x=0; x<32; x++){
         if(x == 16) s += 512;//0x0200
         u16 p = (x % 16) * 8 + s;
         u8 d = 0;
         u8 m = 0b10000000;
         for(u8 i=0; i<8; i++){
            if(VIDEObuf[p + i] & mask) d += m;
            m >>= 1;
         }
         
         low_WrComDat(d,0);//dat
      }
   }
#else
   //KS0108
   for(u8 y=0; y<8 ;y++){
      low_WrComDat(0xb8+y, LCD_CS1, 1), low_WrComDat(0x40, LCD_CS1, 1);
      
      for(u8 x=0; x<128; x++){
         if(x == 64) low_WrComDat(0xb8+y, LCD_CS2, 1), low_WrComDat(0x40, LCD_CS2, 1);
         low_WrComDat(VIDEObuf[y*128 + x], 0, 0);
      }
   }
#endif
}

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Ср окт 06, 2021 18:48:20

Вот, у Вас ещё и чтение из буфера неоптимально сделано - на каждой процедуре записи запускается цикл на 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 просто вызывать из прерывания таймера, вообще избавившись от любых задержек в главном цикле.
Вложения
testfb.7z
(1.26 KiB) Скачиваний: 148
Последний раз редактировалось WiseLord Чт окт 07, 2021 11:46:30, всего редактировалось 1 раз.

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Чт окт 07, 2021 09:01:17

WiseLord писал(а):биты раскладывать на этапе записи в буфер, а читать сразу готовые байты последовательно из массива.
просто я тогда не стал заморачиваться и оставил организацию буфера как у KS0107, для универсальности.
В реале на паялке оно выдает 15 фпс, на спекруме конечно меньше, т.к. там идет активный обмен по кв.шине, но меня вполне устраивает
не вижу смысла переделывать, разве что для спортивного интереса
тем более, еще не измерена инерционность самого стекла

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Чт окт 07, 2021 11:50:08

slav0n писал(а):не вижу смысла переделывать, разве что для спортивного интереса
Ну так в спортивном-то интересе самый смак. Мне и самому было бы интересно узнать, что из этого бы получилось, тем более что идею - что имнно и в каком порядке делать - для ST7920 я расписал. Для KS0108 принцип был бы тот же - постепенно избавиться от циклов, вынеся их переменные наружу.

Технически, до самого последнего момента (переноса в прерывание) всё должно отрабатывать фактически с той же скоростью (поскольку задержки всё ещё присутствуют), и только на последнем этапе ожидается резкий скачок FPS

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Чт окт 07, 2021 12:31:41

Скачка ФПС не будет. Ибо 80 мкс на команду никуда не денутся.
А вот скачок idle - будет. И это хорошо.
А более правильно этот дисплей переводить на камушек с ДМА.
Я пробовал на СТМ - удобно. Хватает времени на всё.
А вообще - для большинства задач взаимодействия с пользователем и 10 фпс хватит. И времени на обработку действий юзера.
Или вообще - обновление только по требованию.
Возникло событие - перерисовали и обновили.

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Чт окт 07, 2021 12:39:17

WiseLord писал(а):Ну так в спортивном-то интересе самый смак.
давай разложим по полкам запись-чтение видеобуфера.

мой вариант:
чтение - побитно
запись
знакогенератор - побайтно
графика - побитно

твой вариант:
чтение - побайтно
запись
знакогенератор - побитно
графика - побитно

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

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Чт окт 07, 2021 13:33:48

GoldenAndy писал(а):Скачка ФПС не будет. Ибо 80 мкс на команду никуда не денутся.
Может, я не так выразился. Говоря о FPS, я имел в виду, сколько главных циклов в секунду может выполнять программа. Тут число вполне может поменяться с 15 на, например, 2000, если нет каких-то тяжёлых вычислений. Если есть (типа Фурье анализа того же) - может поменяться с 15 до, скажем например, 50.
А обновление дисплея - да, быстрее не станет. Но оно будет сконцентрировано не в одном месте (в конце главного цикла), а "размазано" равномерно по времени выполнения.
slav0n писал(а):при выводе текста никакой разницы.
выигрыш, казалось бы, при выводе графики, но, учитывая тормознутость матрицы, он тоже под вопросом.
В целом, да. Я просто на основании своего опыта рассуждаю, когда в проекте анализатора спектра такое небольшое, казалось бы, изменение в коде позволило раза в 2 увеличить FPS.
Грубо, если для обновления дисплея требуется 50мс, и на расчёты (Фурье) - те же 50мс, то Ваш подход даст 100мс общей задержки - т.е. обработка сигнала будет возможна только 10 раз в секунду. А обновление по таймеру как раз даст возможность обработать сигнал 20 раз в секунду, невзирая на то, насколько быстрый или медленный дисплей.

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Сб окт 09, 2021 22:37:37

прикинь, ЭТО пихать в прерывание каждые 60 мкс?..
тануегонах!
Код:
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 = 0;
   if (x == -2) {
      d = 0x80 + y;//com
   } else if (x == -1) {
      d = 0x80 + 0;//com
   } else {
      com = 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;
   }
}
далеко и надолго

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Вс окт 10, 2021 09:18:00

Почему я выше и писал про то, что читать из буфера желательно как можно проще - по байту. А все манипуляции битами отдать на запись в этот буфер.

Но даже и сейчас, то что есть, с циклом по битам, вполне успеет выполниться за несколько (до 10) микросекунд.

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Пн окт 11, 2021 14:12:41

зачем мне оно, если у меня на мега32 единственное прерывание ISR(TIMER0_OVF_vect) вызывается с периодом 0.781 ms
при этом: дисплей, 3 ШИМа, 2 ПИДа, энкодер, музыка... все работает
даже TIMER1 не задействован

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Вт окт 12, 2021 17:02:16

попробовал ЭТО, типа, оптимизировать, а компилятор совершенно не отреагировал на изменения
Код:
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:
осталось позагонять в статики игрик икс зависимые переменные, но НАХУЯ?!!

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Вт окт 12, 2021 17:47:02

Нет смысла. Для x и y нужно сохранять своё значение между вызовами функции, поэтому static. Остальные переменные всё равно через них рассчитываются, и делать ещё и их static смысла нет.

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Вт окт 12, 2021 18:50:36

ну, да
онлайн расчет указателя буфера все бессмысленнее и бессмысленнее и бессмысленнее...

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Ср окт 13, 2021 13:06:39

идея такая, размазываем вычислительные сопли по прерыванию
Код:
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 (>= 0){
        com = 0;
        d = 0;
        if (== 16) s += 512;
        u16 p = (% 16) * 8 + s;
        u8 m = 0b10000000;
        for (u8 i = 0; i < 8; i++, m >>= 1) if (VIDEObuf[p++] & mask) d += m;
    } else if (== -2) {
        d += y;//com
    }
    low_WrComDat(d, com);
    
    if 
(++>= 32) {
        x = -2;
        ++y; y %= 32;
        s = (* 16) & 0x0180;//0b110000000
        mask = 1 << (% 8);
    }


Добавлено after 1 hour 2 minutes 29 seconds:
бу

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Ср окт 13, 2021 16:36:59

Ну.. это всё пока выглядит просто как попытки сэкономить пару байтов прошивки. Хотя по скорости, может быть, и медленнее будет, чем без лишних static-ов.

Но вообще оно у Вас, как я понимаю, в целом заработало? Именно при вызове из прерывания, а не основного цикла? Если да, то дало ли эффект видимый? Ведь ради этого всё затеивалось...

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Ср окт 13, 2021 17:43:48

нет, у меня оно пока не заработало, ибо я пару фпс всегда готов пожертвовать в угоду алгоритма.
а это чисто спорт, тяга к оптимизации кода

Добавлено after 57 minutes 26 seconds:

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Сб ноя 04, 2023 13:45:08

Подскажите плз:
Начал разбираться с дисплеем сначала в текстовом режиме. Проблема в том, что все символы кроме иероглифов выводятся сразу по 2 в знакоместо 16х16. Можно ли как-то изменить сетку? Или иначе отрисовывать стандартные символы по одному?
Или это только в граф. режиме?

UDP: разобрался. лишний строб E приводил к задвоению всего и вся. :facepalm:

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Вт фев 27, 2024 20:51:27

Товарищи! Откопал дисплей 12832.
При попытке опознать, наткнулся на st7920. На моём выведена колодка 16 контактов с очень похожей распиновкой. Но есть отличие. Нет на плате подстроечника контрастности. Из мануала на контроллер нашел схему, где не используется удвоитель и все питается от VCC
Изображение
На моей плате все так же, кроме того, что все резисторы R1-R5 на 4.7 кОма (в мануале почему-то R3 указан 2к2), а также вместо R10 у меня установлен не потенциометр, а простой резистор и номинал его 51 Ом! Сигнал V0 с контроллера идёт и на этот резистор и на колодку на 3 контакт.
Пока не подключал дисплей к МК, но при подаче питания 5В все пиксели темные. Подсветка странная. Подавать 5В на нее побоялся, так как резистор там стоит 15 Ом всего. Пробовал на режиме диода замер сделать - ничего. Возможно, подсветка на нескольких последовательных диодах сделана.

Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920

Чт мар 14, 2024 18:55:02

может кому пригодится: st7920 перевёрнутый, шрифты русский и английский. Компилятор Bascom 2.0.8.3
адресация по y - 0-7, по x парами!
прикрепляю файл шрифтов, так некоторые не нужные МНЕ символы заменены иными. Всё расписано внутри!
Символы только заглавные, для экономии памяти МК.

Добавлено after 2 minutes 58 seconds:
Прямой вывод, крупный шрифт 16*16 точек
Компилятор Баском 2.0.8.3
Вложения
14x14.zip
(5.75 KiB) Скачиваний: 7
ST7920 перевёрнутый.zip
(4.47 KiB) Скачиваний: 7
Ответить