Электронная книга своими руками на STM32H750 от А до Э



    В этой статье я хочу поделиться опытом разработки электронной книги с использованием недорогого контроллера STM32H750VB, распространенных дискретных компонентов и относительно недорогого дисплея E-Ink. Статья будет большой, так как приведены будут все процессы от постановки задачи до получения первой версии устройства, способного выполнять поставленную задачу. Все будет снабжено схемами, трассировками, кодом и комментариями. Почему в названии от «от А до Э»? Потому что нельзя просто так взять и сделать конечный продукт без ошибок и недоделок.


    Постановка задачи


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

    Все просто. Главное — потому что интересно, иногда хочется в свободное время изобрести велосипед.
    Если люди перестанут периодически изобретать велосипеды, то велосипеды превратятся в непознаваемое наследие предков.

    Дополнительно к велосипеду – хочется сделать книжку, которая не будет разряжаться за месяц, валяясь в шкафу, а будет тратить энергию только на обновление экрана (пара книг из бюджетного сектора, которыми я пользовался, грешила именно этим). Исполнение книги можно сделать под свои руки (я имею в виду кнопки под пальцами руки, которая держит саму книгу). Ну и как ни странно, бюджет самоделки вышел ниже, чем продаваемые электронные книги из сектора 8 дюймов (если не считать затраченных человеко-часов, но хобби на то и хобби, что время бесплатно).

    Итак


    • Необходимо разработать электронную книгу с экраном около 8 дюймов (по моему личному мнению это самый удобный для чтения размер).
    • Книга не должна требовать предварительной конвертации файлов электронных книг перед загрузкой, то есть отображать формат .FB2 как есть.
    • Файлы читать с SD-карты.
    • Воспринимать кириллицу.
    • После обновления страницы уходить в режим потребления сравнимым с саморазрядом аккумулятора.
    • Навигацию по пунктам меню сделать светодиодами. Имеется в виду, что отображенные на экране списки для выбора (файлы, список действий) будут статичными, и навигация по ним не будет заставлять перерисовывать экран. Выбор производится включением светодиода напротив списка.

      фото реализации для наглядности
    • для управления книгой 4 кнопки — «вперед(вверх)», «назад(вниз)», «меню», «функция»
    • различать на кнопках длинное и короткое нажатие. Кнопку «вперед(вверх)» разместить под пальцем левой руки держащей книгу, чтобы для перехода на следующую страницу не требовалось перехватывать книгу (это я совсем под себя делаю)

      фото реализации для наглядности

    • корпус из ореха

    • Железо для всего этого.

      Экран E-ink — Waveshare 7.5inch E-Ink raw display 800×480. Самый дорогой компонент. Покупал на Алике примерно за 2700 руб.
      Контроллер — STM32H750VBT6. Несмотря на топовую серию, это самая бюджетная модель микроконтроллера в своем сегменте ( у того же Алика – 240 руб). Отличается малым количеством FLASH (128 Кбайт), но в остальном соответствует параметрам всей серии.
      Также потребуется энергонезависимое хранилище для запоминания служебной информации. Их будет два — EEPROM — AT24C02D и FLASH — W25Q64 (стоимостью 60 руб за обе).
      Надо предусмотреть возможность подключения дополнительных блоков, чтобы использовать книгу в задачах не свойственным другим электронным книгам (погодной станции, логического анализатора…).

    Тестом работоспособности первой версии книги (а также логическим финалом этой статьи и материалов к ней) будет возможность прочитать на устройстве трилогию «Властелин колец». К моменту написания статьи я был на середине и первом месяце использования девайса.
    Если DIY`щик берет в руки контроллер, то у него получается либо погодная станция, либо будильник
    Вопрос «почему не взять для этого Малину, Апельсинку… и не париться», рассматриваться не будет.

    Разработка схемы


    Подключение дисплея

    Дисплей выглядит следующим образом:


    Работает по SPI (3 или 4 линии). Схема включения доступна в мануале. Мануал лежит на сайте продавца дисплея. Делаем все по мануалу:



    Есть изменение относительно мануала — катушка L1 по мануалу 10мкГн, но с такой индуктивностью пиксели в дисплее включаются нестабильно и дисплей идет непропечатанными пятнами. Индуктивность 47-68мкГн всё исправляет. Информация взята из описания универсального шильда под e-Paper для одноплатников от этого же производителя. Схема содержит транзистор SI1308, это оказался самый «уникальный» компонент, который пришлось отдельно заказывать и ждать месяц.

    Подключается E-Ink к микроконтроллеру по SPI1:

    PA5 – SCK
    PA7 — DIN
    и линии управления
    PA1 — BUSY
    PA2 — RST
    PA3 — DC
    PA4 — CS

    В мануале утверждается, что при обновлении картинки матрицы дисплея, а это около 2 секунд, дисплей потребляет 12mA. На самом деле оказалось чуть-чуть не так – 38mA. С другой стороны, там же указано время обновления: 4-8 секунд, что на самом деле составляет 2, максимум 3 секунды.
    Китайская система мер и весов понятие растяжимое, как и улыбка
    Подключение SDкарты, и микросхем энергонезависимой памяти типовое.

    общая схема


    FLASH — W25Q64
    подключена к SPI2
    и PD8 в качестве сигнала CS

    EEPROM -AT24C02D
    подключена I2C2

    SD-card
    подключена к SDMMC1
    и PD5 — SD-card insert

    Представленная схема доступна в конце статьи. Схема разработана в Proteus. Файл для Куба (CubeMX) — аналогично.

    Система питания. На ней остановлюсь подробнее


    Основное состояние электронное книги – выключенное. Включение производится только для обновления экрана. Изначально рассматривалось использование режимов сна на всех компонентах схемы, Но когда начал делать замеры потребления, оказалось, что у микросхем FLASH памяти W25QXX есть проблемы с паспортным режимом Standby/ Power-down.

    Потребление, в нем должно быть несколько десятков микроампер. Фактически из 11 микросхем W25QXX, которые были у меня, только две соответствовали паспорту (одна в корпусе SOIC-16, а вторая откуда-то выпаянная) остальные (недавно купленные) кушали минимально 5-8 миллиампер. STM`ка, кстати, тоже не блещет соответствием цифрам, которые показывает Куб в расчетах потребления. В итоге предварительно собранная схема кушала 12 mA в режиме сна. В основном из-за потребления FLASH`ки и SD карты.

    Исходя из вышеописанного, решил делать менеджер питания, который будет запускаться от внешнего импульса, работать несколько секунд, после чего отключать шину питания. Если внешний импульс повторить до отключения, то работа продолжается на эти самые несколько секунд.

    Использование готовых менеджеров питания было отклонено, так как под необходимые функции подходят только специфичные от BQ, но они все в BGA корпусах, а плату (как будет видно ниже) я буду делать под ЛУТ.

    В итоге реализация:



    Питание (5вольт) подается на точку OUT_POWER, питая контроллер заряда АКБ MAX1555 и закрывая транзистор Q6. Q6 – транзистор MOSFET P-канальный, то есть положительным напряжением (относительно истока), он закрывается. Закрываясь он отключает АКБ. При отсутствии питания на OUT_POWER, Транзистор открыт и АКБ подключена к схеме питания. На схеме стрелками показано движение тока. После транзистора, мы получаем питание забыв откуда оно пришло. На схеме есть два резисторных делителя напряжения. R47 и R48 дает логическую единицу (3.3V), если есть внешнее питание и логический ноль если его нет.

    Номинал резисторов не позволяет получить ток, способный запустить обесточенный контроллер через схему защиты от перенапряжения, поэтому сигнал «ADC1» можно смело кидать на свободную ногу контроллера. Делитель напряжения R50 и R49 служит для измерения напряжения на АКБ. Коэффициент деления = 2. Сигнал ADC2 можно подавать на АЦП процессора.

    Я вижу лес рук, у тех кто читает эти три предложения про пару R50 и R49.

    Действительно, это относительно тонкое место на схеме.

    Первое – это постоянная нагрузка на аккумулятор. Расчет с использованием закона Ома дает около 45 микроампер это 0.045 миллиампер. Сколько часов нужно чтобы разрядить АКБ емкостью 600 миллиампер можно посчитать самим. Меня эта цифра устроила. По желанию сопротивления можно взять до 90Ком

    Цифры фактического потребления всей схемы с номиналами, указанными на схеме


    Второе – Это процесс запуска АЦП микроконтроллера через делитель напряжения. Автор статьи знает про применение операционных усилителей, читал статьи про «демонов АЦП», но в данном конкретном случае считает оправданным такое упрощение схемы замера напряжения. Замер напряжения из-за больших номиналов резисторов, естественно, поплывет (физику никто не отменял, емкость УВХ в АЦП может не успеть получить нужный заряд за квант времени, а еще остаточный заряд…), но коррекцию я буду делать программно на основании тестовых замеров. В результате при номиналах R50 и R49 до 91Ком на каждый, получить прогнозируемый замер можно, а вот выше 100Ком уже нет.
    Главное в физике — это умение пренебрегать!
    -Лев Ландау
    Продолжу по самому менеджеру питания. Мы дошли до точки «Mid_Power» на схеме, где у нас либо ток от внешнего питания, либо с АКБ. Далее идет линейный преобразователь напряжения (LDO) LP2985 у которого есть сигнал ON\OFF который, соответственно, разрешает или запрещает преобразование, если на него подать выше 1,4 вольт, то LDO выдает 3.3 вольта на выходе, если прижать к земле, то ничего не выдает. На схеме этот сигнал «On_Power». Необходимо сделать так, чтобы внешний импульс держал не ниже 1,4 вольта несколько секунд на сигнале «On_Power». За это время микроконтроллер инициализируется и сам будет управлять своим выключением, держа логическую 1 на этом сигнале. Решение в лоб с использованием конденсатора на «On_Power» и землю не подошло по габаритам. Конденсатор нужен слишком большой емкости, LP2985 на этом сигнале относительно много потребляет и емкости 1000мкФ хватает меньше чем на секунду. В связи с этим будем использовать ключ на транзисторе — N канальном MOSFET. Сигнал «Mid_Power» замыкается ключом с сигналом «On_Power». Открывает транзистор внешний импульс от того же «Mid_Power» и «держится» парой C36 и R30. при номиналах, указанных на схеме транзистор открыт порядка 4 секунд, при C36 = 10мкФ – порядка 8 секунд. Резистор R29 служит для, скажем так, стабилизации процесса. Дело в том что, при закрытие транзистора происходит дребезг, то есть отключились, потом опять включение на несколько миллисекунд, а потом уже полное выключение. Причина тому может быть в прыжках напряжения при переходе АКБ на холостой ход, либо в том, что резистор имеет паразитную индуктивность и получается колебательный контур, а может еще в чем-то. Но R29 выправляет ситуацию тем, что обратная связь при открытом транзисторе чуть замедляет разряд C36, а при первом отключении помогает быстрее высаживать заряд C36 на сигнал «On_Power».

    В завершении необходимо организовать четыре независимых линии запуска менеджера питания. Три линии для кнопок на корпусе (нажатие листать вперед, назад и кнопка меню), которые будут пробуждать всю схему, и одну линию для микроконтроллера, который после пробуждения первым делом подаст 3.3 вольта на нее, чтобы его не отключили и прижмет к земле, когда закончит обновлять экран. Развязка сделана на диодах. Линии имеют контактные площадки J11, J8, J6,J5

    Отдельно необходимо сделать схему управления светодиодами пунктов меню. Всего будет 12 вариантов выбора, следовательно, 12 светодиодов. Чтобы не забирать под это 12 ног контроллера, сделано будет соединением (я не знаю, есть ли для такого соединения отдельное название), когда между каждой парой выводов есть два светодиода, соединенных анод к катоду:


    соединяются с
    PE2 — J1
    PE3 — J2
    PE4 — J3
    PE5 — J4
    (W5 — это перемычка)
    Для включения отдельного светодиода, необходимо на пару выводов подать «1» и «0» соответственно полярности включения, а остальные два перевести в режим входа.

    План В

    Забегая вперед скажу, что вариант с одноцветными светодиодами мне не подошел. Не подошел по цвету свечения :) под корпус из ореха, нужен теплый ламповый цвет свечения, и желтый или оранжевый не подходит. Поэтому в итоге я сделал на адресных RGB светодиодах в корпусе 2020. В исходниках есть функции для обоих вариантов.

    Нога PE5 – является выходом канала таймера TIM15_CH1
    Нога PE3 – управляет включением шины питания адресных светодиодов
    Отключать питание понадобилось из-за того, что диоды WS2812 от 3.3 вольт работают нестабильно и их пришлось подключить напрямую к сигналу «Mid_Power» через ключ

    Схема


    Три кнопки, которые «будят» менеджер питания, также ведут к ногам (через резистор 1К) контроллера. Плюс четвертая кнопка — только к контроллеру
    PB0 — key «вперед»
    PB1 — key «назад»
    PB2 — key «меню»
    PC5 — key «функция»

    В архиве, по ссылке внизу статьи схемотехника в трех файлах: схема устройства, схема LED линейки меню и схема линейки на WS2812. Схема устройства на трех листах (отдельно это указываю, так как в Протеусе явно не видно количество листов схемы)
    В конце описания схемотехники попрошу прощения за вольные изображения УГО, почти все они делались руками под себя, и именно из-за большой базы смоделированных компонентов пока не хочу уходить с Протеуса.

    Разводка и изготовление печатной платы


    Как я упоминал выше, разводить плату я буду с учетом того, что изготовлять ее буду в домашних условиях, то есть по древней технологии ЛУТ (Лазер, Утюг, Травление). На данной технологии останавливаться не буду (когда то писал статью об этом habr.com/ru/post/451314 ).

    Протеус позволяет выгрузить цепи, для трассировки в стороннем приложении (например, для Топора). Советовать, как и где удобнее не буду. Да и сам обычно начинаю в обоих, а там как пойдет. В данном случае разводил в Протеусе. Получилось так:



    Вверху разъем для дисплея, контактные площадки везде подписаны (медью), выведены дополнительные шины (UART,SPI,I2C) и выводы под дополнительное оборудование. Слева площадки под программатор (обычный свисток ST-LINK).

    Там где пресечения дорожек не избежать, использовал резисторы-перемычки в корпусе 0805, чтобы перепрыгнуть 1-2 дорожки и в корпусе 1206, чтобы перепрыгнуть 2-3 дорожки. На разводке их видно по зеленым линиям.

    Линии запуска менеджера питания K0-K3. метка MPW соответствует сигналу «Mid_Power». Vin – выход от резисторного делителя входного питания BAT_LVL – выход резисторного делителя от АКБ, соединяется с площадкой PA0. Остальные подписи – как на схеме.

    Берем текстолит и убираем все лишнее


    Текстолит черного цвета (это не маска)

    Сборка:



    Бонус :
    Я делал сразу две платы (на всякий случай), обе получились хорошо и работают. И готов одной штукой поделиться. Если кому-то нужно, кто в Питере может в рабочее время на Петроградке забрать, тот может написать в личку. Отдам безвозмездно, то есть даром (плата со всеми компонентами и проверена в работе, на фото она самая).

    Проверка на дым, проверка соединений и можно сказать что 80% работы сделано
    Не так страшны первые 80% проекта, как вторые 80% проекта
    Девиз PM

    Кодим


    Первый этап — настройка контроллера и драйвера для устройств


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

    Конфигурацию делаю в «CubeMX», проект генериться под «TrueSTUDIO for STM32», соответственно в оболочке у нас HAL. К HAL я отношусь вполне спокойно, ужасов расписанных про него на форумах не встречал, хотя иногда необходимо выходить из его рамок (ниже это будет упомянуто).

    Начнем с микроконтроллера.

    Частоту я поставил 300Mhz (исходя из соображений производительность\потребление), тактирование начинается от кварца в 16Mhz. Порты настраиваются согласно описанной выше схемотехнике. В ресурсах к статье файл куба в наличии, поэтому подробнее останавливаться не буду.

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

    Приступаем к распределению памяти.

    В STM32H750 доступно 1 мегабайт ОЗУ, вот только она лежит не одним куском, а разложена по разным банкам:



    DTCMRAM и ITCMRAM «близкая» ОЗУ с нулевыми таймингами доступа, то есть банки с быстрой памятью, а RAM_D1,RAM_D2,RAM_D3 просто ОЗУ. Причем HAL в проекте создал только адресное пространство для этих банков и подключил использование DTCMRAM.

    Нам 128 килобайт DTCMRAM не хватит.

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

    Итак, идем в файл * _FLASH.ld с трассировкой памяти (в приложенном проекте это STM32H750VB_FLASH.ld) он генерируется в корень проекта.

    Добавляем туда конструкцию с объявлением переменных, указывающих на наши банки:

    SECTIONS
    {
    …
     .bank1 : {} >RAM_D1
     .bank2 : {} >RAM_D2
     .bank3 : {} >RAM_D3 
    …
    }

    Выравнивание (ALIGN) или еще какие-то действия с этой памятью нам не потребуется, она нужна просто как набор свободных к использования байтов. Есть нюанс, файл _FLASH.ld не имеет User секций в разметке кода, поэтому после новых генераций проекта через Куб (если вдруг они понадобятся), наша запись удалится. В связи с этим не забываем это проверять и заново добавлять (На самом деле TrueSTUDIO умеет игнорировать перезапись, но это опасные настройки, поэтому советовать не буду).

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

    Дефайним команду компилятора(исключительно для удобства):

    #define _BANK1 __attribute__((section(".bank1")))
    #define _BANK2 __attribute__((section(".bank2")))
    #define _BANK3 __attribute__((section(".bank3")))

    а далее объявляем массивы:

    _BANK3 uint8_t BufferEink[48000]; // экранный буфер
    _BANK1 char Out_Text[327680];    // буфер текста
    _BANK2 char CurrFileDir[256];
    _BANK2 char CurrFileName[256];
    _BANK2 char Curr_Buffer_Info[1024];

    Теперь у нас в первом банке 320килобайт для текстов, в Третьем экранный буфер, а второй банк под все остальные массивы. DTCMRAM под текущие переменные, а также будет немного динамического выделения памяти (стек и куча осталась в DTCMRAM)



    Дисплей


    Задача к драйверу дисплея: Инициализация, рисование точки, рисование символа и строки символов, рисование линии и передача экранного буфера в сам дисплей

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

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

    Код функции

    
    	  uint16_t x = y1;
    	  uint16_t y = 480-x1;
    	  uint8_t p_x = (x>>3); // (разделить на 8 по целому = позиция в байтах)
    	  uint8_t px_x = x-(p_x<<3);  // (номер точки в байте)
    	  uint16_t IM_addres = y*100+p_x; // адресс точки в массиве
    	  uint8_t point = 0b10000000>>px_x; // точка в байте
    	  uint8_t lastPoint = BufferEink[IM_addres];
    	  BufferEink[IM_addres] = lastPoint|point; // ИЛИ

    Вначале идет переворачивание координат, так как по умолчанию дисплей не в портретном режиме, а дальше я все действия прокомментировал в коде.

    Функции работы с дисплеем собраны в файле EInk7inch.c (и описаны в EInk7inch.h)
    Функция печати символов и строки использует массив с битовыми описаниями изображения каждого символа, каждый символ 8x8 точек. Kодировка символов win-1251.

    Это будет служебный шрифт, читать им – глаза сломаешь.

    Для удобного чтения необходим шрифт в два раза больше, чем системный, у каждого символа нужно знать ширину, чтобы строка «iiiiiii» занимала меньше места чем «шшшшшшшш» при одинаковом количестве символов. С векторными шрифтами связываться не буду (не те масштабы, не те ресурсы), поэтому рисуем



    Матрица для шрифта 16x17 точек, то есть описание символа занимает 34 байта, плюс 1 байт с позицией конца символа (слайдер на рисунке). Для генерации пришлось быстро набросать программку, но приводить ее в ресурсах к статье не буду, так как там все просто, а написана она на коленке левой пяткой с массовой копипастой вместо функций.
    Если долго жать на Ctr+C, то Ctr+C нажмет тебя
    Таким образом готовится:

    • Стандартный шрифт
    • Курсив
    • Жирный
    • Крупный для заголовков
    • Мелкий для вспомогательных целей

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

    Чтобы начать работать, надо хорошенько заскучать, чтобы ничего больше не хотелось.
    Стругацкие
    В результате появилось несколько типовых функций собранных в файле my_fonts.с и my_fonts.h

    uint8_t My_char_standart(uint16_t f_x , uint16_t f_y , uint8_t type, uint8_t ascii );
    uint8_t My_char_italic(uint16_t f_x , uint16_t f_y , uint8_t type, uint8_t ascii );
    uint8_t My_char_bold(uint16_t f_x , uint16_t f_y , uint8_t type, uint8_t ascii );
    uint8_t My_char_big(uint16_t f_x , uint16_t f_y , uint8_t type, uint8_t ascii );
    uint8_t My_char_14px(uint16_t f_x , uint16_t f_y , uint8_t type, uint8_t ascii );

    Указываются координаты, символ, и тип вывода: 1 — печать, 0 -не печатать а только вернуть ширину (нужна будет позже).

    Возвращает ширину символа.

    К ним всем есть однотипные функции печати строки
    пример

    Print_standart(uint16_t x, uint16_t y, char* string);

    для печати имен файлов функция:

    void Print_big_scr_DOS(uint16_t x, uint16_t y, char* string);

    которая печатает в кодировке DOS. кодировка DOS мапиться через массив на кодировку WIN-1251

    Результат:



    Подключение энергонезависимой памяти и SD-карточки

    Все типовое, не один раз описано на просторах интернета.

    для выведения результатов сделал страницу с системной информацией:

    страница системной инфы


    LED Указатели меню


    Помните, я выше писал про то, что спокойно отношусь к HAL? Так, вот, к управлению GPIO это не относится! Я очень не понимаю, зачем на самую простую и быструю функцию навесили валидаторы входных значений (тем более они предифайнены) и создали монструозные структуры. Поэтому я буду дрыгать ножками по старому, регистрами.

    Для работы с 12 LED диодами нужно выдавать на 4 GPIO комбинации типа:
    1-0-Z-Z
    0-1-Z-Z
    0-Z-Z-1
    Где Z – нога сконфигурирована как вход, 1 – как выход с логической «1», 0 – соответственно логический «0»

    Делаем для каждого GPIO типовые функции:

     void PE2_1()
    {
    	GPIOE->MODER |= GPIO_MODER_MODE2_0;  // выход
    	GPIOE->PUPDR &= ~GPIO_PUPDR_PUPD2;  // без подтяжки
    	GPIOE->BSRR = GPIO_BSRR_BS2;       // HIGHT
    }
    void PE2_0()
    {
    	GPIOE->MODER |= GPIO_MODER_MODE2_0;  // выход
    	GPIOE->PUPDR &= ~GPIO_PUPDR_PUPD2;  // без подтяжки
    	GPIOE->BSRR = GPIO_BSRR_BR2;       //LOW
    }
    void PE2_Z()
    {
    	GPIOE->MODER &= ~ GPIO_MODER_MODE2; // вход
    	GPIOE->PUPDR &= ~GPIO_PUPDR_PUPD2;  // без подтяжки
    }
    

    и выводим общую:

    void Set_LEDs(uint8_t key)

    в которую подается пункт меню, а она зажигает нужный диод.

    В случае использования адресных диодов WS2812 есть два варианта реализации- через таймер TIM15 — ШИМ на первый канал (PE5) и через дрыганье ногами с равными промежутками времени. Конечно любой STM`шик скажет что – таймером, таймеры наше все! Но я, видно плохой STM`шик, так как таймер у меня периодически дает сбой. Изредка загорается произвольно последний в цепочке диод. Хотя на осциллографе картинка сигнала одинакова относительно реализации на задержках. Но об этом я подумаю позже, так как обходное решение есть, функция не критичная, а значит баг минорный.

    В приложенном проекте реализация на задержках, хотя схемотехника позволяет использовать таймер на выделенных под диоды пинах.

    Три функции:

    void WS2812_LOW();
    void WS2812_UP();
    void WS2812_LED_Set(uint8_t key);

    Последняя аналогично void Set_LEDs(uint8_t key) зажигает пункт меню, первые две формируют сигнал. Необходимая задержка организована обычным циклом с математическим выражением. Задержка определялась методом подбора счетчика цикла и созерцания кривой на осциллографе.

    кривая


    Ну и перед началом передачи сигнала на адресные диоды, выключаем прерывания, а потом опять включаем. (В HAL создается системный таймер для delay и остальных функций, который прерывает наш код и может сместить тайминги).

    Файлы


    Подключение SD-карты и библиотеки «fatfs» делает HAL, единственное, что нужно указать, что использоваться будут длинные имена файлов (LFN).

    Работа с SD-карточкой типовая. Но хочу описать – как храниться список файлов, и выбранный файл.

    Работа с файлами и их содержимом собрана в FileManager.с и соответственно в FileManager.h, также подключается файл «MyExtention.h».

    Функция:

    uint8_t FM_GetDIR(char* st_dir)

    читает указанную директорию и возвращает в случае успеха 0 или код ошибки.

    Для хранения состава директории определена структура:

    struct NData
    {
        int menu_cnt; //номер файла
        char* Name;   //имя файла или каталога
        unsigned long size;  //размер файла
        uint8_t type;   //директория =1 файл=0 
    };

    на базе которой построена структура для стека:

    typedef struct Node
    {
        struct NData value;
        struct Node *next;
    } Node;

    А также функции для работы с этим стеком


    Основные:

    void push(Node **head, struct NData data );
    struct NData pop(Node **head);

    При запросе директории, заполняется структура NData в количестве, равной количеству файлов.

    При этом для сохранения имени файла вызывается malloc для массива char в количестве, равному длине имени файла + 1 (завершающий ноль, для представления в виде строки)
    malloc пишет в банк DTCMRAM размер которого 128 килобайт и он примерно на 20% занят нужными данными. Поэтому у нас получается тонкий момент по памяти. Если в директории будет 100500 файлов, да еще с именами длинной близкой максимальной, то девайс уйдет в закат.

    Проверку у malloc на доступность выделения памяти я не использую, так как слабо могу представить, что буду по 200 книг хранить без разбивки по директориям.

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

    Функция:

    void FM_CurrListFile(int startpunkt)

    печатает на экран список файлов. Ей надо указать на каком пункте изначально зажечь диод
    Общая переменная Select_line_menu хранит выбранный пункт, который равен номеру файла+1 в структуре NData.

    Функция:

    FM_SelectFile(Select_line_menu-1);

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

    Кнопки


    Функция работы с кнопками синхронная, то есть пока идет ожидание нажатия, в девайсе ничего не происходит (кроме прерываний).

    Функция возврата нажатой кнопки:

     uint8_t FB_WaitKey()
    {
    uint32_t key_count = 0;
    uint8_t key = 0;
    
    while (key==0)
    {
    	if((GPIOC->IDR&(1<<5))==(1<<5))   {key=1;}   //dwn
    	if(GPIOB->IDR&1)                  {key=2;}   // up
    	if((GPIOC->IDR&(1<<4))==(1<<4))   {key=3;}   // меню
    	if((GPIOB->IDR&(1<<1))==(1<<1))   {key=4;}   // функция
    }
    
    while ( ((GPIOC->IDR&(1<<5))==(1<<5)) |(GPIOB->IDR&1)|((GPIOC->IDR&(1<<4))==(1<<4))|((GPIOB->IDR&(1<<1))==(1<<1)))
    {
    	key_count++;
    	HAL_Delay(1);
    }
    if (key_count>500) {key=key+10;};
    return key;
    }

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

    Если кнопка нажималась на время меньшее полусекунды, то это короткое нажатие, если больше, то длинное. Соответственно возвращается код от 1 до 4 при коротком нажатии и +10 к номеру, если нажатие длинное.

    На этом с подготовкой все.

    Все готово для непосредственной работы с файлом FB2.

    Второй этап — реализация непосредственной функции девайса


    Структура файла FB2 является структурой похожей на XML. Поля ограничиваются открывающими и закрывающими тегами, есть вложенные структуры. Теги маркируются угловыми скобками (это я объяснил своими словами, подробнее в сети). Весь файл грузить в ОЗУ ресурсов контроллера не хватит, поэтому вложенность раскручиваться не будет. В процессе разбора FB2 необходимо бежать по файлу, регистрировать текстовые теги и выводить текст из них. То есть будет представлена некая упрощенная модель разборки формата, для которой много памяти не требуется.

    Определю общие правила:

    • Текст в тегах «р» является основным текстом, выводится основным стилем №1 – начало тега с красной строки, далее вывод текста с учетом формата символов, определяемым внутри тега «p»
    • Текст в тегах «v» является подачей стихов, песен и подобного, выводится стилем№3 – каждая строка с отступом от левого края. Вывод текста с учетом формата символов, определяемым внутри тега «v»
    • Текст в серии тегов заголовков, выводится стилем №2 – печатается крупным шрифтом, формат символов игнорируется.
    • Теги, содержащие информацию, которая не является текстом книги – игнорируются или выводятся как исключение (автор, название книги, пустые линии)

    Алгоритм следующий.

    Курсор бежит по файлу, фиксирует теги, определяя угловые скобки.

    Зафиксированный текстовый тег копируется в буфер «Out_Text[]» и зафиксированным стилем в переменной «FB2Tag_Style». Внутри текста тега возможно переключение на курсив или жирный шрифт, которое тоже определяется тегами. Эти теги удаляются, а вместо них ставится символ с кодом ниже 32.
    28 – курсив
    29 – жирный
    30 – обычный

    Функция отвечающая за этот алгоритм (файл FileManager.c, FileManager.h):

    unsigned long FM_Into_file_FB2(unsigned long Cursor)

    на вход подается позиция курсора, откуда надо начать искать очередной (или первый) тег, на выход – позиция курсора конца тега. Результат работы функции – текст первого встреченного тега, содержащего текст, который положен в «Out_Text[]» и стилем в «FB2Tag_Style». Файл из которого читаем, закрывается.

    Да, имя файла и каталог лежат в общих переменных, в которые были записаны функцией, которую я привет в разделе Файлы выше.

    После чего тег можно напечатать на экране.

    Печатает функция:

    uint8_t FB2_Printing_Tag_on_Screen(int deltatag)

    на входе смещение относительно начала текста, которое необходимо вывести на экран, на выходе флаг был ли напечатан текст полностью не хватило экрана.

    В ходе печати меняется общая переменная FB2_CurrentTagStep, которая хранит позицию в массиве «Out_Text[]», то есть в тексте из тега.

    Переменная «deltatag» (смещение в теге) нужна в тех случаях, когда на экране места не хватило, и напечатана лишь часть текста. Остаток будет печататься на следующей странице, когда мы нажмем кнопку перелистывания с позиции указанной в «deltatag».

    По сути общая переменная «FB2_CurrentTagStep» и «deltatag» несут одинаковый смысл, но в ходе обработки текста могут указывать в разные места, поэтому и разделены, я допустил новую сущность в угоду меньшим вычислениям.
    Если долго множить сущности, то сущности объединятся и пожрут твой мозг
    Через последовательный вызов двух вышеуказанных функций проходиться вся книга.

    FB2_Printing_Tag_on_Screen – делает серию вызовов вспомогательных функций:

    uint8_t Estimation_String(int deltatag)

    – служит для оценки длинны строки. Отсекает по целым словам и дает длину пробела для выравнивания строки по правому краю (мы же привыкли, чтобы текст был ровным и справа и слева). Каждый символ имеет разную ширину, поэтому функция фактически проходит алгоритм печати, но без рисования точек на экране (для этого в функциях My_char_хххх есть параметр uint8_t type, о котором я говорил в разделе шрифтов).

    void PrintFormatString(int deltatag)

    – проводит уже настоящую печать с учетом данных от Estimation_String.
    int PrintUnicodeChar(int tagstep,uint8_t CurrFormatChar, uint8_t type)

    выводит символ на экран используя кодировку Юникода, с учетом типа шрифта (жирный, стандартный, курсив).

    По факту, последняя функция должна иметь сестру для печати в кодировке WIN-1251, так как такая кодировка допускается в FB2.

    int PrintWIN1251Char(int tagstep,uint8_t CurrFormatChar, uint8_t type)

    функция реализована, но в общий алгоритм не включена, так как пока у меня нет книги в такой кодировке.

    Вывод текста целой страницы выглядит следующим образом

    uint8_t Y_End = 1;
    if (FB2_CurrentTagStep>0) // выбор - продолжить печатать  незаконченный тег или начать новый
    {
    	FBCursor = FM_Into_file_FB2(FBCursorLastTag);
    }
    else
    {
    	FBCursor = FM_Into_file_FB2(FBCursor);
    }
    Y_End = FB2_Printing_Tag_on_Screen(FB2_CurrentTagStep);
    while (Y_End == 1)   // допечатать страницу до конца
    {
    	FBCursorLastTag = FBCursor;
    	FBCursor = FM_Into_file_FB2(FBCursor);
    	Y_End = FB2_Printing_Tag_on_Screen(FB2_CurrentTagStep);
    }
    

    Переменные которые использует и меняет данный алгоритм
    FBCursor — позиция курсора в файле на начале тега
    FBCursorLastTag — сдвиг по тексту внутри тега
    FB2_CurrentTagStep — сдвиг по тексту уже записанному в буфер
    FB2Tag_Style — стиль текста.

    Поясню, зачем опять я, казалось бы, наплодил сущности со сдвигами. Дело в том, что после печати страницы книга отключается от питания, вся текущая информация пропадает. И после включения мы должны «вспомнить» где взять текстовый тег в файле, сколько из него уже напечатано, откуда начать выводить на экран (с учетом почищенных тегов) и продолжать печатать жирным, стандартным текстом или курсивом. Можно конечно провести имитацию с печатью невидимой страницы (или нескольких), тогда нам нужна только позиция курсора в файле на начале тега, но зачем такие сложности? Тем более что тег может занимать десяток страниц.

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

    Так выглядит результат печати листа:

    Вспомним кто такие Хоббиты


    Пример вывода разных стилей текста


    Осталось совсем чуть-чуть (а то я утомил уже, наверное).

    Сохранение информации и общий цикл работы


    Для сохранения данных при отключении книги, воспользуемся установленными FLASH и EEPROM
    Почему я решил дополнительно их припаивать, а не использовать ресурсы STM`ки или SD? Хранить во FLASH микроконтроллера это зверство, там циклов перезаписи не так много, да и этой самой FLASH кот наплакал. Использовать SD не хочу просто потому, что считаю некрасивым использовать не свой ресурс, да и в итоге будут доп. задачи, которые должны работать без карточки.

    В чем характерное отличие EEPROM и FLASH для поставленной задачи:

    FLASH – имеет ограниченное число перезаписей на конкретную ячейку (5-20тысяч) записывает и читает быстро
    EEPROM – можно сказать не имеет ограничений на перезапись (1-2млн), записывает медленно (5 msek), читает относительно быстро.

    Вывод: долбить во FLASH статистику каждой страницы не следует.

    Положа руку на все места, одной FLASH обойтись можно, используя смещение ячеек или другие алгоритмы которые используются уже давно, но на базе этой книжки у меня еще будет логгер сигналов (этакий вариант анализатора с длительным ожиданием запрограммированной формы сигнала) и там мне Епромка будет нужна. Поэтому и тут я ее все же использую :)

    Алгоритм работы следующий:

    1. При открытии новой книги FLASH стирается вся (ограничиваем себя 5-20 тысячами книг, потом замена FLASH) можно стирать и по одному блоку (их 128 по 64кбайт), но пока так не делал.
    2. В первую станицу пишется имя файла (256 байт), во вторую директорию (256 байт).
    3. С 512 ячейки начинаем запись текущих данных. Каждая открытая страница записывает 28 байт и смещает указатель текущей страницы для записи следующих 28 байт. Указатель записан в EEPROM. 1000 прочитанных страниц займет 28000 байт.
    4. при включении книги идем в EEPROM и получаем адрес, по нему идем в FLASH и получаем данные, как отразить текущую страницу или следующую (в зависимости от нажатой кнопки).

    Описание данных:

    struct SaveData   // 28 байт
    {    // маркеры текущей страницы
    	unsigned long CurrFileCursor;    
    	unsigned long CurrFileCursorLastTag;
          unsigned long CurrTagStep;
          uint8_t CurrTagStyle;
        // маркеры следующей страницы
          unsigned long NextFileCursor;
          unsigned long NextFileCursorLastTag;
          unsigned long NextTagStep;
          uint8_t NextTagStyle;
        uint8_t EPointer; // указатель для поиска текущей страницы, в случает отказа от использования EEPROM 
        uint8_t Mark;  // номер закладки
    };

    С маркерами мы уже встречались выше, EPointer – резерв, Mark – номер закладки, тоже пока как резерв.

    Запись в EEPROM — одно значение типа uint32_t

    Работа с EEPROM по умолчанию в HAL поддержана, работа с FLASH, через библиотеку «w25qxx.h» взятую с github. Останавливаться на особенностях не буду, так как все в сети есть.
    Упомяну только то, что при сохранении данных указываются массивы, а у нас структура. Их можно перекидывать одно в другое через указатели, а можно через объединения.

    Для записи во FLASH:

    typedef union
       {
        struct SaveData my_Var;
        uint8_t bytes[28];
    } DataChang;

    Для EEPROM
     typedef union
       {
        uint32_t my_Var;
        uint8_t bytes[4];
    } Four_Bytes;

    Поля в union имеют общую память, так что переводить одно в другое удобно.

    Старт книги


    В main.c

    Первым делом после инициализации поддерживаем питание через PD7, определяем с какой кнопки мы включились, если мы нажали кнопку и очень быстро отпустили, то есть после инициализации она уже будет отпущена, то просто обновим текущую страницу. Включаем питание на WS2812 и еще один диодик, который показывает что процессор уже не спит. После уходим в Book_Start(start_key), где отрисовывается вышеуказанными методами страница.

    После гасим питание:

     /* USER CODE BEGIN 2 */
           GPIOD->BSRR = GPIO_BSRR_BS7;// вкл поддежку питания
        //При включении определяем с какой кнопки включились
           uint8_t start_key = 0;
    	if((GPIOC->IDR&(1<<5))==(1<<5))   {start_key=1;}   //dwn
    	if(GPIOB->IDR&1)                  {start_key=2;}   // up
    	if((GPIOC->IDR&(1<<4))==(1<<4))   {start_key=3;}   // меню
    	GPIOE->BSRR = GPIO_BSRR_BS3;// вкл светодиоды меню
    	GPIOE->BSRR = GPIO_BSRR_BS4;// вкл индикатор на панели
           Book_Start(start_key);
           GPIOD->BSRR = GPIO_BSRR_BR7;// by-by
      /* USER CODE END 2 */

    Наверное все и наверное ничего не забыл


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

    Ссылка на файлы (там все по папочкам)

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 75

      –11
      Отличная курсовая работа!
        –7
        еще бы спелчекером прогнать…
          +12

          У нас в городе на радиотехнике это тянуло бы на диплом. Но преподы рассказывали, что наши дипломные работы в Москве превращаются в курсовые. Это понятно хотя бы из того, что на радиотехнику у нас поступают люди, которые никогда не паяли, а их там этому и не учат, поэтому паяльник приходится брать уже во время написания диплома.

            +5
            Курсовая? Точно? Я помню как устроился на работу, где 3 человека аж одну дипломную работу делали, так там качество работы даже на курсовую одного с натяжкой тянуло. А здесь всё же поболее курсовой будет.
              –2
              Уровень со временем растёт.
            0

            Waveshare 7.5inch E-Ink, прикольный дисплей, вроде как цветной даже есть. Если бы еще подстветку как у paperwhite

              0
              А почему не просто в сон? ST утверждает, что ток потребления в глубоком сне 2.95 мка. А питание на флешку winbond можно подавать от порта (с ножки или с двух ножек, если тока не хватит) контроллера STM32h7.
                +1
                Идея гасить все, мне понравилась больше, так как универсальна, вроде как. Отработать и использовать где то еще
                  +1
                  Может и не такая плохая идея выключать полностью — иногда гаджеты виснут, не помогает даже кнопка reset если она вообще есть, единственный путь вернуть их к работе — отключить батарею и кратковременно закоротить контакты питания. Если батарея несъёмная, а корпус неразборный это может быть проблемой.

                  Книга получилась отличная. Своя книга позволяет реализовать любой каприз в удобстве использования и функциональности, а не то как их видит производитель.
                    +2
                    Да, наверное, это вопрос вкуса конечно, но работающий контроллер даёт больше возможностей. Часы там, статическая память. И это я к току покоя W25 флешки, что ее как раз можно просто питать от ножек. Да и не только ее. А 3 мка… Можно поставить небольшую солнечную панельку и суперконденсатор и обойтись вообще без батарейки.
                      0
                      Вот только в режиме сна (когда сохраняется вся память) потребление >150 мкА. Впрочем, 4k оперативки в backup domain при потреблении 2.5 мкА тоже на многое хватит.
                        0
                        Да я в курсе.я с ними работаю. Очевидно, что имел в виду backup domain, с его 4K Ram -ом.А ещё, во время работы с дисплеем можно понижать клоск. Его пара секунд обновления экрана, это можно много энергии сэкономить.
                          +1
                          А не лучше на время обновления в неглубокий сон уходить? Он же вроде по завершении операции умеет дергать ножкой BSY, по ней пусть контроллер просыпается.
                          Режим отключения плох еще тем (помимо сброса контроллера), что очень мало прерываний работает. Разве что RTC да пара специальных ножек.
                  +6
                  Добрый день. Отлично получилось. А шрифт, я так понимаю, графический, не векторный? Просто выглядит плохо, как векторный без антиалиазинга. Если растровый, то подобрать бы шрифты по-лучше. Допустим тут. Файлы с расширением fon
                    0
                    он и есть без сглаживания, так как нет градаций серого. в этом и проблема. Я их до сих пор перерисовываю, пока устоялся только основной шрифт
                      +4
                      Возьмите готовый. Их много со времён DOS.
                      Один из лучших в русификаторе keyrus. com
                        +1
                        А может и не надо стараться улучшить шрифт?
                        Идеального сглаживания всё равно не выйдет, а «полуидеальный» шрифт мозг будет воспринимать фальшивым, недоделанным.
                        «Рваный», нечеткий шрифт мозг так и воспринимает, как есть, не пытаясь запускать улучшайзеры, на картинку с глаз.
                        На моей читалке есть три уровня детализации, так вот чёткий шрифт выглядит красиво, но глаза быстро устают его читать, а вот самый корявый шрифт воспринимается как типографский, как будь то расплылась краска на бумаге из под печатного пресса.
                      +5
                      — Книга не должна требовать предварительной конвертации файлов электронных книг перед загрузкой, то есть отображать формат .FB2 как есть.

                      Очень часто fb2 пакуют зипом (*.fb2.zip). В идеале, научить открывать файлы fb2.zip так сказать «искаропки».
                        +10
                        Такое соединение светодиодов называется чарлиплексинг. Помню ещё на easyelectronics статью про мультиплексирование.
                          0
                          Спасибо, не знал. Хотя подозревал, что название есть
                          +1

                          А не замеряли, что тратит больше энергии, обновить экран или светить светодиодом?
                          И через какое время в меню светить становится не выгодно?

                            0
                            Обновить экран менее затратно, но задержка на обновление после каждого нажатия — бесит. Уйти от обновлений при навигации, это была цель. лучший вариант — вместо диодов поставить кнопки — 12 штук, это мне задачка на будущее (с точки зрения реализации в корпусе)
                              +5
                              По первой фотографии я сначала принял горизонтальные планочки за толкатели кнопок.
                            +2

                            Интересно, а кто-нибудь пробовал использовать устройство с E-Ink для набора текстов?
                            Хочется иметь устройство, с которым бы можно было работать на ярком свету.

                              0
                              Медленно и неудобно. Можно, конечно, вспомнить детство и тормозящий текстовый редактор, когда сначала наколачиваешь не глядя на экран текст, а потом ждёшь, как отрисуется, и надеешься, что нигде не опечатался, но зачем?
                                +2

                                Очень хочется совместить пляжный отдых и работу.


                                экран слепнет

                                image

                                  0
                                  По-моему, в такой постановке задача идеально не решается. Можно попробовать поляризационные очки или плоскую линзу-поляроид на экран.
                                0
                                Да, в теории. В e-ink экранах есть т.н. однобитный режим обновления — только чёрный/белый цвет, без градаций серого, без полного обновления картники.
                                Напр. для Nook'ов есть NoRefresh, который умеет включать этот режим.

                                Angry Birds, 1-bit style


                                Не очень удобно (т.к. нужно его каждый раз запускать/включать/выключать), но работает. В идеале, этот режим должен включаться автоматически (напр. быть фичёй текстового редактора читалки).
                                  +1
                                  Для текста идеальный режим, заодно максимизирующий контрастность.
                                    0
                                    Не все поддерживают однобитный режим, даже обновление части экрана поддерживают не все.
                                    0
                                    Современные E-ink очень даже можно использовать для набора текста. Можно посмотреть на Onyx Boox Max который подключается как внешний монитор. Да и вообще выпускаются книжки с андроидом, где можно устанавливать подходящие текстовые редакторы.
                                    0
                                    Прекрасная работа! Данный экран поддерживает возможность частичного обновления указанной прямоугольной области?
                                      0
                                      Нет :(. Я на самом деле, когда выбирал дисплей повелся, что в мануале есть команды передачи кастомной области, но оказалось что это просто регион обновления буфера дисплея, а обновляет картинку он все равно по всей поверхности.
                                      +1
                                      Q6 на схеме нарисован неправильно.
                                      Причина тому может быть в прыжках напряжения при переходе АКБ на холостой ход, либо в том, что резистор имеет паразитную индуктивность и получается колебательный контур, а может еще в чем-то.

                                      Причина в том, что конденсатор стоит не между затвором и истоком, а неправильно.

                                      Флеш или китайская подделка, или неправильно подаёте команду сна, у меня 25Q128 из Элитана в сне потребляет микроамперы из даташита.
                                        0
                                        Уточните пожалуйста, именно Q6? он отвечает за переключение источника питания (внешнее или АКБ) конденсатор на затворе даст инертность в преключении. Или Q2? тогда предложенное включение не будет отличаться от использования вообще без ключа (быстрый разряд как я и писал).
                                        Про хорошие и плохие 25Qx я тоже указал и правильные я видел (как и написал), так что про китайцев — в точку, только думаю не подделка, а отбраковка, которая распродается на Алике
                                          0
                                          При указанном на схеме включении плюс с батареи всегда проходит на выход через паразитный диод транзистора, надо повернуть истоком на батарею.

                                          У Q2 по схеме с общим стоком минимальное падение на канале — вольта 1,5...2, при разряде батареи может не хватить для включения преобразователя. Заменить биполярным, резисторы и задержка те же. Конденсатор перенести параллельно R29.
                                            0
                                            добавил в схему как предложено

                                            Если C36 установить на как предложено -> на C39 то, Q2 не нужен, вход 3_U4 кондер будет быстро разряжать (на линии помеченой KT1 потребление высокое).
                                            При падении на АКБ ниже 3.4V не запуститься LDO. поэтому потери значения не имеют. На самом деле дребезг связан с моделью исполнения резистора R30. там при замере красивые преодические колебания. При замене резистора на резистор другого исполнения (тонкопленочный вроде называется, в зеленый такие красят) все выравнивается. Либо R29 и R30 можно вообще убрать, тогда все идеально, только время открытого ключа сложно прогнозируется (от 10сек до минуты)
                                              0
                                              вот снял АЦПшкой контроллера кривую на затворе Q2 и в Экселе превратил в график

                                              по X — время шагом 0,1 сек по Y напряжение *100.
                                              R29 удален.
                                              Поддержка питания закончена в точке x=13 в точке x=31 вероятно питание первый раз отключено. При установленном R29 кривая колеблеться конечно, но после первого закрытия транзистора падает как курс рубля.
                                          0
                                          Q6 на схеме нарисован неправильно.
                                          Всё правильно. Q6 работает в качестве диода. Стандартная схема переключения питания.
                                          0
                                          Не проще ли плате распаять кучку ОЗУ с работой от батарейки как в BIOS? Если не будет быстрой замены аккумулятора, то можно сделать писание ОЗУ от него. Так быстрее будет, да и износа у нее нет. Еще можно было вместо светодиодов использовать индикацию на экране, экономия энергии, места на плате, толщины девайса как никак. WS2812 не лучший выбор для индикатора одного цвета в портативном устройстве т.к. у них 3 цвета и они потребляют энергию на холостом ходу. Ты экономишь совсем немного на энергосбережении ядра, но при этом светодиоды жрут как не в себя даже если не работают. Для курсовой отлично, но для нормального устройства на каждый день слабенько.
                                            0
                                            Подключение ОЗУ на ЛУТе не развести. Много раз пробывал и в итоге заказывал плату делать в Резонит. Хотя ОЗУ преводит всю поделку на другой уровень (есть место под целые файлы), но это уже совсем другая задача и тогда можно просто взять Малину Зеро.
                                            WS2812 — обесточены, кроме времени когда они необходимы, по схеме видно.
                                            Экономиться не потребление ядра, а на отключении всего, что выведено на шину питания
                                              0
                                              При отображении индикации на экране индикация может быть активна всегда, даже с выключенным устройством. А когда ws2812 активны их контроллеры жрут по 2ма на штуку. Для включения WS2812 нужно дергать ногой GPIO > увеличение потребления. Если использовать индикаторы на экране, то можно значительно сэкономить на разводке платы и включать индикацию на продолжительное время, если же необходимы именно световые индикаторы, то простые smd-хи были бы предпочтительней. WS2812 нужны в основном для использования когда светодиодов должно быть достаточно большое количество, иначе они безсмыслены.
                                                0
                                                Так WS2812 это План В, исключительно потому, что мне цвет в Плане А не понравился )) Под План А (а там именно SMD, хотя и WS2812 это тоже SMD с потреблением 5mA) уже жду посылку с «теплыми белыми» диодами
                                                  0
                                                  «может быть активна всегда, даже с выключенным устройством» — не может. посмотрите схему
                                                    0
                                                    E-ink при отключении питания сохраняет свое состояние. Если индикатор был бы на экране(стрелка, точка, текст и пр.), то при отключении питания светодиоды бы отрубались, а изображение на экране оставалось вместе с наэкранным индикатором.
                                              0

                                              Устройство нравиться очень! +1 статьи и +1 в карму.


                                              Но! Шрифты получились на троечку. А их так просто вылизать до совершенство. И тогда получится шедевр.


                                              Ну и еще если в русском есть простой алгоритм переноса слов (в болгарском есть), то он совершенно не навредит. ;) Выравнивание будет лучше и не будут такие большие дыры на местах.

                                                +1
                                                Вторая статья за неделю про opensource читалки) Тенденция не может ни радовать)
                                                  0
                                                  Спасибо за статью! Прикольно, что помимо разработки взаимодействия ЦПУ-Экран-Память пришлось вникать, например, в особенности управления питанием и коммутацией Аккумулятор-Внешнее питание. Если позволите, вопросы:
                                                  1. Сколько времени ушло от идеи до готового устройства? Дни месяцы всего и «чистое» время в часах. В каком темпе велась разработка?
                                                  2. В каких пропорциях примерно потрачено время по основным этапам создания читалки?
                                                  3. Если не секрет, основная работа насколько близка-далека от данной разработки?
                                                  4. Какие сомнения были в процессе?
                                                  5. Какие неожиданные грабли были (не очевидные места, в которых потрачено времени сильно больше, чем ожидалось)
                                                  6. У Процессора многие ноги не использованы, был ли резон использовать более младший процессор, вплоть до STM32F103, если уж оставаться в рамках STM32? Какой минимальный STM32 ориентировочно «потянет» разработку?
                                                  7. Какой багаж знаний и навыков до старта был из пригодившегося?
                                                  8. Какие ошибки/грабли посоветуете избегать при повторении своего, похожего по уровню сложности, DIY любительского устройства?
                                                    0
                                                    Если позволите, опросник проходить не буду :)
                                                    Если кратко:
                                                    -изначально все делалось на F407vet — нехватило ОЗУ (192K)
                                                    -Общее время: сколько то вечеров в течении пары месяцев, 50% времени — шрифты и корпус
                                                    +1
                                                    А не рассматривали дисплей Waveshare 7.8" E-Ink (1872*1404 )?- он подороже будет — но 300dpi это 300 dpi (мой уже приехал — потестил — просто прекрасен — но книжку не собрал ещё).
                                                      0
                                                      его и хотел, но не поверил характеристикам. он действительно обновляется за 0.4 секунды?
                                                        0
                                                        У платы управления разные интерфейсы — и по SPI с малики больше 2 секунд занимает. Но есть и USB2 интерфейс и драйвер под Windows (upd: перепроверил) действительно время обновления близко к 0.4 сек, причём в режиме градации серого!

                                                        Но вот время пересылки(оно в windows, как оказалось, идёт в фоне) — 2297 милисекунд — т.е. суммарно порядка 2.7 секунды на всё.

                                                        upd: загрузку следующей страницы книги можно сделать тоже фоне, но вот для пользовательского UI у меня бродит мысль использовать лишь часть экрана
                                                          0
                                                          Это радует. значит следующая задачка Waveshare 7.8" E-Ink + STM32 + MT48LC16M :)
                                                            0
                                                            8MB — PSRAM64H $0.7 qspi ~100MHz. Разводка простая, 8 ножек
                                                              0
                                                              Я ещё буду разбираться, но при работе по SPI через IT8951 вообще результаты грустные — библиотечная функция сlearScreen() занимает от 7 до 9 секунд.

                                                              Ну и для сравнения сам дисплей(фрагмент) — шрифт Sans 30pt и линейка
                                                              image
                                                                0
                                                                IT8951 на SPI по даташиту может разгоняться до 24 Mгерц. как я понимаю на дисплее чуть больше 2 мегапикселей по 4 байта на каждый. С учетом накладных расходов, наверное в 1 секунду уложиться шанс есть. Шлейф позволяет по 8080 зацепиться?
                                                                  +1
                                                                  Дело не в самой передаче изображения по SPI — чуть больше 2х сек она занимает при забивании попиксельно(уходит по 1 байту), а в том, что именно функция сlearScreen(), у которой всего-то данных 1 байт(и 4 значаших бита) выполняется 7 сек — т.е. что-то сильно накосячено в самой либе. Я внутрь либы пока не заглявал — хочу посмотреть, можно ли что-то на USB сделать;)
                                                                    +1
                                                                    В общем — это грусть — внутри либы(от waveshare) — ранее заполненный фреймбуффер начинает писать по SPI по 2 байта, каждый раз включая/выключая шину на запись (1.3млн раз для этого дисплея).

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

                                                                    Если писать построчно с буффером — то вместо 7 сек уже становится ~3.5 сек
                                                                      +2
                                                                      Удалось поднять частоту SPI с 7.8МГц до 15.6Мгц (на малинке она меняется лишь в 2 раза вверх/вниз) — и единым копированием всего фреймбуфера получить 2.45-2.5 сек. А потом я заглянул уже по привычке во внутрь самой функции копирования буфера от WaveShare — и о чудо — там всё-равно побайтное копирование через API малинки. Которое поддерживает и трансфер буфера. Так что ожидаю дальнейшего ускорения — хоть и не большого (и уже близко к 2.3секундам на USB ;) )

                                                                      В общем — я слегка в шоке от такого кода от Waveshare(хоть это и пример, но всё-таки) — это было малозаметно на дисплеях с низким разрешением — но на 2+МР экранах вылазит во всей красе;)
                                                                        +2
                                                                        Сорри за такой вид спама — 947 милисекунд при одинарном трансфере всего буфера(2628288байт) выжал на 15.6МГц из малинки — ваша первоначальная оценка очень правильная :)

                                                                        Спасибо, что вашей статьёй вдохновили меня наконец разобраться с этим вопросом :)
                                                                          –1
                                                                          Спасибо и вам, я сильно сомневался в этом дисплее, а вы потестили )
                                                                  0
                                                                  Не успел в прошлый ответ добавить(USB/Win) — по каким-то причинам время пересылки полного изображения в полном разрешении (1872х1404) заниамет 2.3 сек, но если сделать его на 1 пиксель меньше (т.е. 1871х1404) — уже 1.3 сек. а для 1800х1350 — уже 0.97сек — т.е. непропорционально обьёму переданных данных.

                                                                  Затвра проверю по SPI — но наверняка там аналогично.
                                                                0

                                                                Идея с диодами необычна, но не превышает ли потребление этих диодов ту мощность, которая расходуется на перерисовку экрана? (в случае если пункты меню подствечивать непосредственно)

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

                                                                    Имею в хозяйстве старинную читалку Azbooka и там сделано как раз так с кнопками, на фоне тачскрина выглядит архаично

                                                                  0
                                                                  По поводу шрифтов. Давным-давно в далёкой-далёкой галактикеещё во времена AVR8 я сделал простой конвертор любых установленных шрифтов в си файл. Не идеален, но если он вам пригодится — могу скинуть. Это всё же проще чем неделями рисовать вручную :-)
                                                                    0
                                                                    я тоже сделал такой конвертер (курсив именно им забран), но после него надо каждую литеру все же редактировать, косые тонкие линии идут пунктиром или просото не видны на такой маленькой матрице символа
                                                                    0
                                                                    Красивый, стильный корпус, если не считать светлых вставок сверху и снизу. Интересно, сколько он весит?

                                                                    Схема содержит транзистор SI1308, это оказался самый «уникальный» компонент
                                                                    В чём «уникальность»?

                                                                    подходят только специфичные от BQ
                                                                    Что такое «BQ»?

                                                                    Текст, судя по изображению «Вспомним кто такие Хоббиты», не очень удобен для чтения: где-то большие пробелы, где-то наоборот — маленькие, недостаточный интерлиньяж, средняя вертикальная черта буквы «ш» выделена жирным.

                                                                    Пайка аккуратная, но вот ошибок правописания в статье… Имя им — легион.
                                                                      +2
                                                                      — сам корпус почти невесомый (стенки 2мм). Вставки (шпон из деревесины Падук) действительно не в тему, и надо будет срезать и подбирать что то другое. Нижняя закрывает отверстия динамика, верхняя закрывает два места, где при соединении не удалось свести текстуру дерева.
                                                                      — в том, что ничем не заменяется, и не сильно распространен
                                                                      — BQ — серия контроллеров питания (например BQ24296RGER). Согласен не так выразился, они от «ТI»
                                                                      — С неудобством текста, тоже согласен. При dpi=125 и без градаций серого, красоту навести сложно, но сейчас шрифт _standart читается удобно (литеры «ш» «м» подредактировать, конечно надо), курсив, вероятно без сглаживания никогда нормальным не будет.
                                                                      — И, да, про ошибки вы тоже правы. Все, что прилетает в личку, я правлю. Видно изложение текстов это не мое. В конце уже заставлял себя дописывать, чтобы не бросить. Зато я теперь буду больше ценить труд Тех. писателя, который на работе за мной документы правит :)
                                                                      +1
                                                                      Бонус под одноименным сполером уже не актуален. Зарезервирован под пользователя kudisoldier
                                                                        0
                                                                        Круто
                                                                          0
                                                                          Здорово! Необходимо добавить подсветку для чтения в темное время и, вероятно, увеличить ресурс АКБ.
                                                                            0
                                                                            Каким-то образом пропустил вашу статью.

                                                                            Моё восхищение упорству и трудолюбию! Просто большое уважение. Не думаете сделать какой-то открытый проект для публики, так чтобы могли энтузиасты подключиться? Может сделать что-то подобное, выложить на hackaday?
                                                                              0
                                                                              я дал ссылки на исходники, если у кого-то есть желание его куда-то дальше распространить, то я не против.
                                                                                0
                                                                                Брать чужие лавры славы — это как-то не правильно. Наоборот, хотел помочь, хоть как-то. Проект реально клёвый.

                                                                            Only users with full accounts can post comments. Log in, please.