Привет, Хабровчане! Этот цикл (надеюсь) статей будет посвящён моему пути в создании своего собственного решения по струйной печати. Это будет что-то вроде блога или дневника разработчика в котором постараюсь изучить как же всё таки работает печатающая головка у принтера и как ей можно управлять с помощью микроконтроллера. А также нас ждёт интригующий ответ на вопрос: "Если ли место DIY и OpenSourse в мире струйной печати".

HP Deskjet 2630
HP Deskjet 2630

Пролог

Когда-то я решил завести себе хобби - печатать книги на домашнем принтере, а помогал мне в этом уже немолодой HP Deskjet 2630 с приколхоженной подключённой к нему СНПЧ дабы не заправлять картриджи каждый день.

Всем известны типичные проблемы струйных принтеров:

  • Остановиться посреди печати с ошибкой

  • Не видеть картриджи, в том числе новые

  • Засорение дюз и многое другое

Думаю, каждый сможет пополнить парой-тройкой десятков проблем. В какой-то момент терпение лопается и на смену старому принтеру приходит новый вместе с ощутимой потерей веса кошельком, либо мы познаём дзен и учимся жить с тем что есть.

Будучи инженером-робототехником по образованию и программистом по профессии я был не готов мириться с таким положением дел и решил заняться поисками способов кастомизировать свой принтер. Я надеялся найти огромное количество статей в духе "перепрошивка принтера", "open source прошивка для принтера", "струйный принтер на Arduino", "DIY принтер" и т.д. .

Однако, реальность оказалась жестока и я не смог найти ни одного подходящего решения. Были умельцы, которые модифицировали принтер в планшетный для печати на тортах или текстолите, кто-то на основе совсем уж старой печатающей головки делал что-то вроде CNC. Это были как и достойные, так и колхозные работы, но они либо не меняли ПО и железо, либо принтер переставал быть принтером.

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

§1. Становление идеи

Наткнувшись на статью про Взлом цветного картриджа HP (и основана на блоге) в мою голову закралась мысль, что это можно попробовать воспроизвести. После я нашёл статью на Hackaday где автор, использую начинания предыдущего автора для своего проекта и адаптацию для Arduino от другого автора. Это придало мне некоторую уверенность в что можно попытаться создать свой принтер на базе этих решений.

Безуспешно пытаясь хотя бы запустить код на Arduino UNO (ESP32 просто не было под рукой), я пришёл к выводу что всё будет не так просто и мне придётся начинать свой собственный проект практически с нуля.

§2. Бездна анализа, планирования и ТЗ

Покрутив в голове мысль о собственном проекте, я сформировал для него первые требования к тому что я хочу получить:

  • Устройство должно подключаться к ПК и определяться им как принтер

  • Устройство должно управлять картриджами HP123 (такие используются моим принтером и авторами упомянутых выше статей)

  • У устройства должен быть минимальный HMI - небольшой дисплей для вывода информации и несколько кнопок для управления

NUCLEO-411RE
NUCLEO-411RE

И я стал думать над базой. Если вышеупомянутые проекты несли скорее исследовательский и развлекательный характер, то мне хотелось создать более комплексное решение, так что я отказался от использования ESP32 и Arduino. Мой взгляд пал на давно пылящуюся в закромах NUCLEO-411RE в качестве основы - 512 Кбайт Flash и 128 Кбайт RAM дают пространство для разворота, а DMA и 72 МГц максимальной частоты поможет меньше задумываться о производительности, не говоря уже об огромном количестве возможной периферии.

Теперь можно добавить чуть больше конкретики для начала прототипирования:

  • NUCLEO-411RE как основа

  • Проект должен быть открытым для желающих повторить, что-то улучшить или же создать что-то своё на базе. Плохо знаком с лицензиями, но, думаю Apache 2.0 подходит

  • Необходимо оставить, по крайней мере 10-15 пинов ШИМ чтобы управлять одной печатающей головкой (я ещё не разобрался с подробностями управления, пока будем держать в голове такие числа)

  • Используем просто OLED дисплей 128x64 для вывода информации. Он работает по I2C и уже есть библиотеки для работы с ним

  • Больше мосфетов богу мосфетов. Пины печатающей головки подключаются к нагревательному элементу (немного подробнее описано тут), а значит могут потреблять значительный ток (где-то встречал значение до 2.5А). Таким образом, как было отмечено в статьях ранее, банального преобразователя уровня недостаточно, необходимо хорошее усиление

  • В качестве основного ввода можно воспользоваться стиком для Arduino и свести 5 кнопок в 3 пина + подключим модуль для расширения GPIO по I2C дабы иметь больше кнопок (включение, отмена, информация и т.д.) и не трогать ценные пины контроллера

  • Будет хорошей идеей подключить SD карту, её можно будет использовать в качестве источника для задания печати, писать логи и (в крайнем случае) хранить ресурсы для дисплея, возможно появятся ещё идеи. Можно было бы воспользоваться модулем с SDIO, но у меня уже имеется SPI модуль - воспользуемся тем что есть

  • Нужно будет перемещать печатающую головку и бумагу. Самое логичное решение - CNC Shield для Arduino + набор шаговых двигателей. Просто и всем знакомо по 3D принтерам. Будем считать шаги для определения положения и концевики для крайних положений

  • Необходимо хранить профили коррекции цвета, возможно для этого подойдёт модуль EEPROM, который также можно подключить по I2C

  • Логгер. Вывод в консоль через UART и в файл жизненно необходим

  • Разобраться с подключением контроллера как принтера

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

  • Используем DMA везде где это возможно: SPI, I2C, UART

  • Простой обработчик событий. Да FreeRTOS имеет механизм сообщений, но он кажется слишком громоздким для простого события нажатия кнопки

Тем самым вырисовываются первые функциональные модули, которые могут работать в отдельных потоках:

  • модуль для работы с дисплеем,

  • модуль для "прямой" работы с пинами ввода-вывода. Вынесем сюда обработку GPIO, в том числе ADC и работу с I2C расширением

  • модуль логирования - без комментариев

  • простой обработчик событий. Да FreeRTOS имеет механизм сообщений, но он кажется слишком громоздким для простого события нажатия кнопки

  • модуль обработки событий. Для начала ничего сложного - вызываем событие с параметром в виде enum'а, а модуль будет вызывать подписанные обработчики (они сами решат какие события обрабатывают)

  • модуль для управления шаговыми двигателями

  • модуль для управления печатающей головкой

  • модуль для контроля печати. Будем контролировать прогресс печати, преобразовывать задание печати для управления моторами и печатающей головкой (возможно объединение с управлением моторами и печатающей головкой) + контроль уровня чернил (датчик уровня для СНПЧ и счётчик со сбросом для картриджей)

Таким образом у меня уже есть что-то похожее на план от которого можно отталкиваться при разработке ПО.

§3. Проблемы и вопросы

Начнём с главной проблемы: все печатающие головки проприетарные и на них нет документации в открытом доступе. Так что мне пригодятся начиная связанные с блогом.

Исходя из этой проблемы вытекает следующая: в сети полно статей как работать с принтером, в основном про принт-серверы, но практически ни одной статьи как это подключение устроено с другой стороны. C похожей проблемой столкнулся автор этой статьи. Несмотря на наличие спецификации для USB Printer Class мне так и не удалось найти ни одной реализации, даже пример реализации от STM найти удалось далеко не сразу.

В связи с этим на поверхности появляется уже появляются, например:

  • вагон протоколов LPR/LPD, RAW Printing, IPP, SNMP и т.д.

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

  • В каком виде приходит задание на печать? Какие преобразования должны происходить? В конце концов это должен быть набор пикселей в CMYK, который должен быть преобразован в управляющие сигналы для печатающей головки

  • Отличается ли задание на печать текста от изображения?

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

§4. А где писать код? Или Cmake для STM32

Вопрос в заголовке кажется глупым и очевидным, но тем ни менее настройка среды для разработки довольно важным моментом в работе. Кто-то поспорят что я всё усложняю, но кто-то найдёт мои следующие рассуждения весьма занимательными.

Для STM32 наиболее простым решением будет ST32 CubeIDE. В него уже интегрирован CubeMX для конфигурации микроконтроллера, а так как у меня дефицит опыта работы с STM32, то это идеальный вариант. Однако, редактор кода основан на Eclipse, который не отличается своим удобством и дружелюбностью. Я провёл достаточно времени в Visual Studio, Visual Studio Code, Android Studio и прочих IDE от JetBrains и ни один переход в другую IDE не вызывает такой боли как переход в Eclipse.

Самой удобной для меня всегда оказывался VS Code, будь то Embeddeed или Web проекты. Однако нельзя просто так взять и создать проект для STM32 в VS Code, а устанавливать и настраивать вагон расширений, который работает с CubeIDE зависимостями просто не хочется.

Многие STM32 разработчики привыкли к CubeIDE, так что я обязан сохранить работу с ней если хочу чтобы в будущем проект мог поддерживаться другими людьми, но при этом для свой собственной эффективности мне нужен VS Code. Выход из этой ситуации простой - использовать CMake.

Идея заключается в том чтобы положить рядом с ioc-файлом CMakeLists.txt, благо, CubeIDE тоже умеет их создавать (теряя при этом ioc-файл), так что мы воспользуемся одним из таких сгенерированных CMakeLists.txt и немного доработаем:

CmakeLists.txt
#############################################################################################################################
# file:  CMakeLists.txt
# brief: Template "CMakeLists.txt" for building of executables and static libraries.
#
# usage: Edit "VARIABLES"-section to suit project requirements.
#        For debug build:
#          cmake -DCMAKE_TOOLCHAIN_FILE=cubeide-gcc.cmake  -S ./ -B Debug -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug
#          make -C Debug VERBOSE=1 -j
#        For release build:
#          cmake -DCMAKE_TOOLCHAIN_FILE=cubeide-gcc.cmake  -S ./ -B Release -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
#          make -C Release VERBOSE=1 -j
#############################################################################################################################
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_VERSION 1)
cmake_minimum_required(VERSION 3.20)

###################### CONSTANTS ######################################
set (PROJECT_TYPE_EXECUTABLE          "exe")
set (PROJECT_TYPE_STATIC_LIBRARY      "static-lib")
set (MCPU_CORTEX_M0				      "-mcpu=cortex-m0")
set (MCPU_CORTEX_M0PLUS				  "-mcpu=cortex-m0plus")
set (MCPU_CORTEX_M3				      "-mcpu=cortex-m3")
set (MCPU_CORTEX_M4				      "-mcpu=cortex-m4")
set (MCPU_CORTEX_M7				      "-mcpu=cortex-m7")
set (MCPU_CORTEX_M33				  "-mcpu=cortex-m33")
set (MCPU_CORTEX_M55				  "-mcpu=cortex-m55")
set (MCPU_CORTEX_M85				  "-mcpu=cortex-m85")
set (MFPU_FPV4_SP_D16                 "-mfpu=fpv4-sp-d16")
set (MFPU_FPV4                        "-mfpu=vfpv4")
set (MFPU_FPV5_D16                    "-mfpu=fpv5-d16")
set (RUNTIME_LIBRARY_REDUCED_C        "--specs=nano.specs")
set (RUNTIME_LIBRARY_STD_C            "")
set (RUNTIME_LIBRARY_SYSCALLS_MINIMAL "--specs=nosys.specs")
set (RUNTIME_LIBRARY_SYSCALLS_NONE    "")
set (MFLOAT_ABI_SOFTWARE              "-mfloat-abi=soft")
set (MFLOAT_ABI_HARDWARE              "-mfloat-abi=hard")
set (MFLOAT_ABI_MIX                   "-mfloat-abi=softfp")
#######################################################################

###################### VARIABLES ######################################
set (PROJECT_NAME             "test_F411RE")
set (PROJECT_TYPE             "exe")
set (LINKER_SCRIPT            "${CMAKE_CURRENT_LIST_DIR}/STM32F411RETX_FLASH.ld")
set (MCPU                     "-mcpu=Cortex-M4")
set (MFLOAT_ABI               "")
set (RUNTIME_LIBRARY          "--specs=nano.specs")
set (RUNTIME_LIBRARY_SYSCALLS "--specs=nosys.specs")

file(GLOB_RECURSE SOURCES
    Drivers/STM32F4xx_HAL_Driver/Src/*.*
    Core/Src/*.*
)

set (PROJECT_SOURCES
	# LIST SOURCE FILES HERE
	Core/Startup/startup_stm32f411retx.s
	${SOURCES}


	)

set (PROJECT_DEFINES
	# LIST COMPILER DEFINITIONS HERE
    STM32F411xE
    )

set (PROJECT_INCLUDES
	# LIST INCLUDE DIRECTORIES HERE
    Core/Inc
    Drivers/STM32F4xx_HAL_Driver/Inc
    Drivers/CMSIS/Include
    Drivers/CMSIS/Device/ST/STM32F4xx/Include
    )

# specify cross-compilers and tools
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER  arm-none-eabi-gcc)
set(CMAKE_AR arm-none-eabi-ar)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
set(SIZE arm-none-eabi-size)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

############ MODIFY ACCORDING TO REQUIREMENTS) ########################

#######################################################################

################## PROJECT SETUP ######################################
project(${PROJECT_NAME})
enable_language(ASM)

add_executable(${PROJECT_NAME} ${PROJECT_SOURCES} ${GLOB_RECURSE})
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_SIZE} $<TARGET_FILE:${CMAKE_PROJECT_NAME}>)

add_compile_definitions (${PROJECT_DEFINES})
include_directories (${PROJECT_INCLUDES})

set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type")

set (CMAKE_EXECUTABLE_SUFFIX ".elf")
set (CMAKE_STATIC_LIBRARY_SUFFIX ".a")
set (CMAKE_C_FLAGS "${MCPU} -std=gnu11 ${MFPU} ${MFLOAT_ABI} ${RUNTIME_LIBRARY} -mthumb -Wall -Werror")
set (CMAKE_EXE_LINKER_FLAGS "-T${LINKER_SCRIPT} ${RUNTIME_LIBRARY_SYSCALLS} -Wl,-Map=test_F411RE.map -Wl,--gc-sections -static -Wl,--start-group -lc -lm -Wl,--end-group")
set (CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp")

Используем PROJECT_SOURCES для всех файлов, PROJECT_INCLUDES для всех директорий с .h файлами. В целом, он выглядит как классический CMakeLists.txt для исполняемого файла с некоторыми дополнениями от CubeIDE, такими как константы:

###################### CONSTANTS ######################################
set (PROJECT_TYPE_EXECUTABLE          "exe")
set (PROJECT_TYPE_STATIC_LIBRARY      "static-lib")
set (MCPU_CORTEX_M0				      "-mcpu=cortex-m0")
set (MCPU_CORTEX_M0PLUS				  "-mcpu=cortex-m0plus")
set (MCPU_CORTEX_M3				      "-mcpu=cortex-m3")
set (MCPU_CORTEX_M4				      "-mcpu=cortex-m4")
set (MCPU_CORTEX_M7				      "-mcpu=cortex-m7")
set (MCPU_CORTEX_M33				  "-mcpu=cortex-m33")
set (MCPU_CORTEX_M55				  "-mcpu=cortex-m55")
set (MCPU_CORTEX_M85				  "-mcpu=cortex-m85")
set (MFPU_FPV4_SP_D16                 "-mfpu=fpv4-sp-d16")
set (MFPU_FPV4                        "-mfpu=vfpv4")
set (MFPU_FPV5_D16                    "-mfpu=fpv5-d16")
set (RUNTIME_LIBRARY_REDUCED_C        "--specs=nano.specs")
set (RUNTIME_LIBRARY_STD_C            "")
set (RUNTIME_LIBRARY_SYSCALLS_MINIMAL "--specs=nosys.specs")
set (RUNTIME_LIBRARY_SYSCALLS_NONE    "")
set (MFLOAT_ABI_SOFTWARE              "-mfloat-abi=soft")
set (MFLOAT_ABI_HARDWARE              "-mfloat-abi=hard")
set (MFLOAT_ABI_MIX                   "-mfloat-abi=softfp")
#######################################################################

и ARM тулчейн

# specify cross-compilers and tools
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER  arm-none-eabi-gcc)
set(CMAKE_AR arm-none-eabi-ar)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
set(SIZE arm-none-eabi-size)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

Таким образом я имею удобный конфигуратор в CubeIDE (который можно заменить на CubeMX) и могу писать и компилировать код в VS Code с помощью CMake, а так же это открывает возможность сборки в CI/CD.

§4. А как же отладка?

Одним из преимуществ STM32 является возможность отладки через SWD интерфейс. CubeIDE поддерживает такую возможность, а вот для VS Code придётся напрячься.

Во-первых нужны расширения, позволяющие запускать компилировать наш код и запускать отладчик, я составил для себя следующий список, который можно поместить в .vscode/extensions.json:

extensions.json
{
    "recommendations": [
        "dan-c-underwood.arm",
        "marus25.cortex-debug",
        "trond-snekvik.gnu-mapfiles",
        "mcu-debug.memory-view",
        "twxs.cmake",
        "josetr.cmake-language-support-vscode",
        "ms-vscode.cmake-tools",
        "ms-vscode.cpptools",
        "ms-vscode.cpptools-extension-pack",
        "ms-vscode.cpptools-themes"
    ]
}

Ключевым тут является marus25.cortex-debug, т.к. именно это расширение делает всё необходимое, но ему надо помочь написав правильный launch.json. Но перед этим я поставлю OpenOCD, который будет поднимать Debug Server для VS Code. и помещу путь к нему в settings.json :

{
    "cmake.useCMakePresets": "always",
    "cortex-debug.variableUseNaturalFormat": false,
    "cortex-debug.openocdPath": "${config:openOCD_dir}/openocd.exe",
    
    // Local environment
    "openOCD_dir" : "C:/tools/stmOpenOCD",
    "openOCD_CFG": "${workspaceFolder}/test.cfg",
    "openOCD_scripts": "${config:openOCD_dir}/st_scripts",
    "plink": "C:/Program Files/PuTTY/plink.exe"
}

Для правильной работы OpenOCD нужен правильный конфиг test.cfg:

test.cfg
# This is an genericBoard board with a single STM32F411RETx chip
#
# Generated by STM32CubeIDE
# Take care that such file, as generated, may be overridden without any early notice. Please have a look to debug launch configuration setup(s)

source [find interface/stlink-dap.cfg]


set WORKAREASIZE 0x8000

transport select "dapdirect_swd"

set CHIPNAME STM32F411RETx
set BOARDNAME genericBoard

# Enable debug when in low power modes
set ENABLE_LOW_POWER 1

# Stop Watchdog counters when halt
set STOP_WATCHDOG 1

# STlink Debug clock frequency
set CLOCK_FREQ 8000

# Reset configuration
# use hardware reset, connect under reset
# connect_assert_srst needed if low power mode application running (WFI...)
reset_config srst_only srst_nogate connect_assert_srst
set CONNECT_UNDER_RESET 1
set CORE_RESET 0

# ACCESS PORT NUMBER
set AP_NUM 0
# GDB PORT
set GDB_PORT 3333





# BCTM CPU variables

source [find target/stm32f4x.cfg]

# SWV trace
set USE_SWO 0
set swv_cmd "-protocol uart -output :3344 -traceclk 16000000"
source [find board/swv.tcl]

# No way to set port, probably it is hardcoded to 3344
swv start 8 -port 3344 -traceclk 32000000

# The following commands must be sent manually
# itm port 0 on
# itm port start

Но есть несколько нюансов:

  1. source [find target/stm32f4x.cfg] отвечает за то какой контроллер мы собираемся прошивать и отлаживать. При смене MCU эта строчка должна быть обновлена

  2. Если используется SWO порт для отладки, то необходимо использовать OpenOCD из STM32CubeIDE, в противном случае всё что после строчки из пункта может быть удалено

  3. Запуск терминала для вывода сообщений отладки - об этом ниже

Самый короткий путь для получения отладки это запуск putty/plink на прослушивание нужного порта. А так как удобство превыше всего, то автоматизируем это.

Создадим скрипт для запуска plink в консоли:

swo.bat
@echo off
set host=localhost
set port=3344
chcp 65001
cls

:loop
  :: check if port available
  >nul 2>&1 (echo >\\.\%host%:%port%)
  if errorlevel 1 (
    echo Port %port% is unavailable — wait...
    timeout /T 2 /NOBREAK >nul
  ) else (
    %1 -raw %host% -P %port%
  )
goto loop

И сделаем task для его запуска в терминал VS Code и (чисто формальную) остановку:

tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "SWO",
            "type": "shell",
            "command": "${workspaceFolder}/swo.bat",
            "args": ["${config:plink}"],
            "isBackground": true,
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": true,
                "panel": "shared",
                "clear": true,
            },
            "problemMatcher": [],
        },
        {
            "label": "Stop SWO",
            "type": "shell",
            "command": "taskkill",
            "args": ["/IM", "plink.exe", "/F"],
            "problemMatcher": [],
            "hide": true,
            "presentation": {
            "reveal": "never",
            "focus": false,
            "panel": "shared",
            "showReuseMessage": false,
            "echo": false,
            "clear": false,
            "close": true
        },
        }
    ],
    
}

Теперь создадим конфигурацию "Deploy & Start" для запуска отладки вместе с терминалом:

Конфигурация в launch.json
..........
{
  "name": "Deploy & Start",
  "type":"cortex-debug",
  "cwd": "${workspaceRoot}",
  "executable": "${command:cmake.launchTargetPath}",
  "request": "launch",
  "servertype": "openocd",
  "gdbPath" : "arm-none-eabi-gdb",

// ============== OpenOCD Config BEGIN ==============
  "interface": "swd",
  "configFiles": [
      "${config:openOCD_CFG}"
  ],
  "serverArgs": [
      "-s", "${config:openOCD_scripts}",
      "-c", "itm port 0 on",
  ],
  // ============== OpenOCD Config END ==============

  "runToEntryPoint": "main",
  // Work around for stopping at main on restart
  "postRestartCommands": [
      "break main",
      "continue"
  ],
  // Work around for debugging via SWO
  "preLaunchTask": "SWO",
  "postDebugTask": "Stop SWO"
},
.............

Теперь можно запускать отладку прямо в VS Code нажатием F5 и пользоваться всеми благами отладки вроде Watch, CallStack и т.д.

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

OpenOCD кажется ненужным, т.к. ST-Link уже подключен и можно использовать его тулчейн, однако, OpenOCD, помимо прочего, открывает возможности удалённой отладки, которой я бы хотел воспользоваться в других проектах.

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


Эпилог

В итоге я имею план для написания своего ПО для принтера и готовую среду для разработки. Определился с компонентной базой и чем-то похожим на архитектуру.

На момент написания статьи транзисторы для управления печатающей головкой ещё в пути и у меня есть время на небольшое изучение FreeRTOS и погружение в С на STM32, так что уже есть репозиторий с рабочим названием PrintSpider_stm32, которое впоследствии будет изменено (буду рад хорошим идеям, пока в голове только HackInkTer образованное как сокращение от Hacked Inkjet Printer), наладил CI/CD для будущих самодельцев, создал заготовку под модульные тесты на Google Tests и я начал разработку первых модулей:

  • модуль для работы с GPIO расширением и обработкой стика

  • модуль OLED дисплея и простое меню

  • абстракция над FATFS, обрабатывающая команды в отдельном потоке

  • обработчик событий

  • логгер с выводом в UART

Уже есть желание перевести проект на C++, т.к. написание даже простого UI пока ещё кажется слишком громоздким. Не знаю кого больше в сообществе любителей и знатоков C или C++, но пока нужно добиться MVP на C.

Возможно я избавлюсь от мусора, приведу в порядок стиль кода и какие-то из следующих частей будут посвящены их разбору уже написанных модулей. А пока всем спасибо за внимание и до следующей части!

Комментарии (0)