├── F401-T12+858D_TFT.hex ├── F401-T12+858D_TFT.ioc ├── F401-T12+858D_TFT_wo_DMA.hex ├── NLS ├── cfg.json ├── impact_we.font ├── po_lang.json ├── port_lang.json ├── ru_lang.json ├── ubuntu_cyr.font └── ubuntu_we.font ├── PCB ├── Gerber_HOT_GUN_v1_2024-03-30.zip ├── Gerber_HOT_GUN_v2_2024-03-30.zip ├── Gerber_main_board.zip ├── Gerber_tft_board_v2_2024-03-30.zip ├── Gerber_tft_board_v3_2024-03-30.zip ├── Gerber_tft_board_v4_2024-03-30.zip └── README ├── README.md ├── SRC ├── Core │ ├── Inc │ │ ├── buzzer.h │ │ ├── cfgtypes.h │ │ ├── config.h │ │ ├── core.h │ │ ├── display.h │ │ ├── encoder.h │ │ ├── flash.h │ │ ├── font.h │ │ ├── graph.h │ │ ├── gun.h │ │ ├── hw.h │ │ ├── iron.h │ │ ├── iron_tips.h │ │ ├── jsoncfg.h │ │ ├── main.h │ │ ├── mode.h │ │ ├── nls.h │ │ ├── nls_cfg.h │ │ ├── pid.h │ │ ├── sdload.h │ │ ├── stat.h │ │ ├── stm32f4xx_hal_conf.h │ │ ├── stm32f4xx_it.h │ │ ├── tools.h │ │ ├── unit.h │ │ └── vars.h │ └── Src │ │ ├── buzzer.cpp │ │ ├── config.cpp │ │ ├── core.cpp │ │ ├── display.cpp │ │ ├── encoder.cpp │ │ ├── flash.cpp │ │ ├── font.c │ │ ├── graph.cpp │ │ ├── gun.cpp │ │ ├── hw.cpp │ │ ├── iron.cpp │ │ ├── iron_tips.cpp │ │ ├── jsoncfg.cpp │ │ ├── main.c │ │ ├── mode.cpp │ │ ├── nls.cpp │ │ ├── nls_cfg.cpp │ │ ├── pid.cpp │ │ ├── sdload.cpp │ │ ├── stat.cpp │ │ ├── stm32f4xx_hal_msp.c │ │ ├── stm32f4xx_it.c │ │ ├── syscalls.c │ │ ├── system_stm32f4xx.c │ │ ├── tools.cpp │ │ ├── unit.cpp │ │ └── vars.cpp ├── FatFS │ ├── README │ ├── diskio.c │ ├── diskio.h │ ├── ff.c │ ├── ff.h │ ├── ffconf.h │ ├── ffsystem.c │ └── ffunicode.c ├── JSON_PARSER │ ├── JsonParser.cpp │ ├── JsonParser.h │ └── README ├── SD_SPI │ ├── README │ ├── sdspi.c │ └── sdspi.h ├── TFT │ ├── ILI9341.c │ ├── ILI9341.h │ ├── ILI9488.c │ ├── ILI9488.h │ ├── NT35510.c │ ├── NT35510.h │ ├── README │ ├── SSD1963.c │ ├── SSD1963.h │ ├── ST7735.c │ ├── ST7735.h │ ├── ST7796.c │ ├── ST7796.h │ ├── bitmap.cpp │ ├── bitmap.h │ ├── common.c │ ├── common.h │ ├── config.h │ ├── gamma.c │ ├── gamma.h │ ├── interface.c │ ├── interface.h │ ├── ll_fsmc.c │ ├── ll_fsmc.h │ ├── ll_spi.c │ ├── ll_spi.h │ ├── picture.h │ ├── pictute.c │ ├── pixmap.cpp │ ├── pixmap.h │ ├── region.cpp │ ├── region.h │ ├── tft.h │ ├── thick_line.c │ ├── tjpgd.c │ ├── tjpgd.h │ ├── u8g2_fonts.c │ ├── u8g2_fonts.h │ ├── u8g_font.c │ └── u8g_font.h └── W25Qxx │ ├── README │ ├── W25Qxx.c │ └── W25Qxx.h ├── ctrl.png ├── high_voltage.png ├── iron_sensors.png ├── tft_board.png ├── title.JPG └── Паяльная и ремонтная станция на STM32 с дисплеем TFT.pdf /NLS/cfg.json: -------------------------------------------------------------------------------- 1 | { 2 | "languages": [ 3 | { "name": "russian", "messages": "ru_lang.json", "font": "ubuntu_cyr.font"}, 4 | { "name": "portuguese", "messages": "port_lang.json", "font": "ubuntu_we.font"}, 5 | { "name": "polish", "messages": "po_lang.json", "font": "impact_we.font"} 6 | ] 7 | } -------------------------------------------------------------------------------- /NLS/impact_we.font: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/NLS/impact_we.font -------------------------------------------------------------------------------- /NLS/po_lang.json: -------------------------------------------------------------------------------- 1 | { 2 | "standalone": { 3 | "OFF": "Wył", 4 | "ON": "Wł", 5 | "Fan:": "Went.:", 6 | "Pwr:": "Pwr:", 7 | "Ref. #": "Ref. #", 8 | "REED": "REED", 9 | "TILT": "Wibr.", 10 | "deg.": "deg.", 11 | "min": "min", 12 | "sec": "sec", 13 | "cw": "w prawo", 14 | "ccw": "w lewo", 15 | "Set:": "Set:", 16 | "ERROR": "ERROR", 17 | "Tune PID": "Ustawienia PID", 18 | "Select tip": "Wybór grota", 19 | "FLASH read error": "Błąd odczytu pamięci", 20 | "FLASH write erro": "Błąd odczytu pamięci", 21 | "No directory": "Brak katalogu", 22 | "format FLASH?": "Formatować?", 23 | "Failed to format FLASH": "Błąd formatowania", 24 | "saving configuration": "Zapisywanie konfiguracji", 25 | "Hot Gun": "Hot Gun", 26 | "Save?": "Zapisać?", 27 | "Yes": "Tak", 28 | "No": "Nie" 29 | }, 30 | "Menu": { 31 | "Main Menu": { 32 | "Main Menu": "Menu główne", 33 | "parameters": "Parametry", 34 | "boost setup": "Ust.boost", 35 | "change tip": "Zmiana grota", 36 | "calibrate tip": "Kalibracja grota", 37 | "activate tips": "Aktywacja grota", 38 | "tune iron": "Ustawienia.lutow.", 39 | "gun setup": "Ustawienia hot-air", 40 | "reset config": "Reset ustawień", 41 | "tune iron PID": "PID lutownicy", 42 | "about": "Wersja oprogram.", 43 | "quit": "Wyjście" 44 | }, 45 | "Parameters": { 46 | "Parameters": "Ustawienia", 47 | "units": "Stopnie", 48 | "buzzer": "Buzzer", 49 | "iron encoder": "Enkoder lutow.", 50 | "gun encoder": "Enkoder hot-air", 51 | "fast gun chill": "szybkie chłodzenie", 52 | "switch type": "Typ czujnika", 53 | "temp. step": "Skok temperatury", 54 | "auto start": "auto start", 55 | "auto off": "Auto wył.", 56 | "standby temp": "Standby temp.", 57 | "standby time": "Czas oczekiwania", 58 | "brightness": "Jasność", 59 | "language": "Język", 60 | "display type": "typ wyświetlacza", 61 | "save": "Zapisać", 62 | "cancel": "Anuluj" 63 | }, 64 | "Boost setup": { 65 | "Boost setup": "Ustawienia Boost", 66 | "temperature": "Temperatura", 67 | "duration": "Czas trwania", 68 | "back to menu": "Powrót do menu" 69 | }, 70 | "Calibrate": { 71 | "Calibrate": "Kalibracja", 72 | "automatic": "Automatyczna", 73 | "manual": "Ręczna", 74 | "clear": "Wyczyścić", 75 | "quit": "Wyjście" 76 | }, 77 | "Hot Air Gun": { 78 | "Hot Air Gun": "Hot Air", 79 | "calibrate": "Kalibracja", 80 | "tune gun": "Ustawienia Hot Air", 81 | "tune gun PID": "Ustawienia PID", 82 | "clear": "Wyczyścić", 83 | "exit": "Wyjście" 84 | } 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /NLS/port_lang.json: -------------------------------------------------------------------------------- 1 | { 2 | "standalone": { 3 | "Fan:": "VENT:", 4 | "Pwr:": "POT:", 5 | "TILT": "INCL.", 6 | "deg.": "grau", 7 | "min": "min.", 8 | "sec": "seg.", 9 | "cw": "horario", 10 | "ccw": "ant.horario",, 11 | "ERROR": "ERRO", 12 | "Tune PID": "ajuste PID", 13 | "Select tip": "Selecionar ponta", 14 | "FLASH read error": "Erro Ler Memoria", 15 | "FLASH write erro": "Erro Gravar Memoria", 16 | "No directory": "Diretorio Nao Existe", 17 | "format FLASH?": "Formatar FLASH?", 18 | "Failed to format FLASH": "Falha Formatar FLASH", 19 | "saving configuration": "Salvando Configuraçao", 20 | "Hot Gun": "Ar-Quente", 21 | "Save?": "Salvar?", 22 | "Yes": "Sim", 23 | "No": "Não", 24 | "Delete file": "xcluir arquivo", 25 | "FLASH debug": "Depuração FLASH", 26 | "Failed mount SD": "Falha na montagem do SD", 27 | "NO config file": "Sem arquivo de configuração", 28 | "No lang. specified": "Nenhum idioma especificado", 29 | "No memory": "Sem memória", 30 | "Inconsistent lang": "Idioma inconsistente" 31 | }, 32 | "Menu": { 33 | "Main Menu": { 34 | "Main Menu": "Menu Principal", 35 | "parameters": "Parametros", 36 | "boost setup": "Ajuste de Reforço", 37 | "change tip": "Mudar Ponta", 38 | "calibrate tip": "Calibrar Ponta", 39 | "activate tips": "Ativar Ponta", 40 | "tune iron": "Ajustar Ferro", 41 | "gun setup": "Calibrar Ar-Quente", 42 | "reset config": "Anular Config.", 43 | "tune iron PID": "Ajustar PID Ferro", 44 | "about": "Sobre", 45 | "quit": "Sair" 46 | }, 47 | "Parameters": { 48 | "Parameters": "Parametros", 49 | "units": "Unidades", 50 | "buzzer": "Buzzer", 51 | "iron encoder": "Encoder Ferro", 52 | "gun encoder": "Encoder Ar-Quente", 53 | "fast gun chill": "arma rápida e fria", 54 | "switch type": "Tipo de Chave", 55 | "temp. step": "Incremento Temp", 56 | "auto start": "Auto Iniciar", 57 | "auto off": "Auto Desligar", 58 | "standby temp": "Temp. de Espera", 59 | "standby time": "Tempo de Espera", 60 | "brightness": "Brilho", 61 | "rotation": "rotação", 62 | "language": "Idioma", 63 | "display type": "tipo de exibição", 64 | "save": "Salvar", 65 | "cancel": "Cancelar" 66 | }, 67 | "Boost setup": { 68 | "Boost setup": "Ajuste de Reforço", 69 | "temperature": "Temperatura", 70 | "duration": "Duraçao", 71 | "back to menu": "Voltar ao Menu" 72 | }, 73 | "Calibrate": { 74 | "Calibrate": "Calibrar", 75 | "automatic": "Automatico", 76 | "manual": "Manual", 77 | "clear": "Limpar", 78 | "quit": "Sair" 79 | }, 80 | "Hot Air Gun": { 81 | "Hot Air Gun": "Ar-Quente", 82 | "calibrate": "Caibrar", 83 | "tune gun": "Ajustar Ar-Quente", 84 | "tune gun PID": "Ajustar PID Ar-Quente", 85 | "clear": "Limpar", 86 | "exit": "Sair" 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /NLS/ru_lang.json: -------------------------------------------------------------------------------- 1 | { 2 | "standalone": { 3 | "OFF": "откл", 4 | "ON": "вкл", 5 | "Fan:": "Фен:", 6 | "Pwr:": "мощн:", 7 | "Ref. #": "Тчк №", 8 | "REED": "геркон", 9 | "TILT": "вибро", 10 | "deg.": "град.", 11 | "min": "мин", 12 | "sec": "сек", 13 | "cw": "вправо", 14 | "ccw": "влево", 15 | "Set:": "Уст:", 16 | "ERROR": "ОШИБКА", 17 | "Tune PID": "настройка ПИД", 18 | "Select tip": Выбрать жало", 19 | "FLASH read error": "Ошибка чтения памяти", 20 | "FLASH write erro": "Ошибка записи в память", 21 | "No directory": "Нет каталога", 22 | "format FLASH?": "Форматировать?", 23 | "Failed to format FLASH": "Ошибка форматирования", 24 | "saving configuration": "сохранение", 25 | "Hot Gun": "Термофен", 26 | "Save?": "Сохранить?", 27 | "Yes": "Да", 28 | "No": "Нет", 29 | "Delete file": "Удалить файл", 30 | "FLASH debug": "Отладка FLASH", 31 | "Failed mount SD": "Ошибка карты", 32 | "NO config file": "Нет файла конф.", 33 | "No lang. specified": "Язык не задан", 34 | "No memory": "Недостаточно памяти", 35 | "Inconsistent lang": "Неполный язык" 36 | }, 37 | "Menu": { 38 | "Main Menu": { 39 | "Main Menu": "Основное меню", 40 | "parameters": "параметры", 41 | "boost setup": "буст режим", 42 | "change tip": "сменить жало", 43 | "calibrate tip": "калибровка жала", 44 | "activate tips": "активация жал", 45 | "tune iron": "настр. паяльника", 46 | "gun setup": "настройка фена", 47 | "reset config": "сброс настроек", 48 | "tune iron PID": "ПИД паяльника", 49 | "about": "версия ПО", 50 | "quit": "выход" 51 | }, 52 | "Parameters": { 53 | "Parameters": "Настройки", 54 | "units": "градусы", 55 | "buzzer": "зуммер", 56 | "iron encoder": "энкодер паяльника", 57 | "gun encoder": "энкодер фена", 58 | "fast gun chill": "быстрое охл.", 59 | "switch type": "тип датчика", 60 | "temp. step": "шаг температуры", 61 | "auto start": "автостарт", 62 | "auto off": "выключение", 63 | "standby temp": "темп. ожидания", 64 | "standby time": "время ожидания", 65 | "brightness": "яркость", 66 | "rotation": "поворот", 67 | "language": "язык", 68 | "display type": "Тип экрана", 69 | "save": "сохранить", 70 | "cancel": "отмена" 71 | }, 72 | "Boost setup": { 73 | "Boost setup": "Буст режим", 74 | "temperature": "температура", 75 | "duration": "длительность", 76 | "back to menu": "вернуться" 77 | }, 78 | "Calibrate": { 79 | "Calibrate": "Калибровка", 80 | "automatic": "автоматически", 81 | "manual": "вручную", 82 | "clear": "сброс", 83 | "quit": "выход" 84 | }, 85 | "Hot Air Gun": { 86 | "Hot Air Gun": "Термофен", 87 | "calibrate": "калибровка", 88 | "tune gun": "настройка фена", 89 | "tune gun PID": "ПИД фена", 90 | "clear": "сброс", 91 | "exit": "выход" 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /NLS/ubuntu_cyr.font: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/NLS/ubuntu_cyr.font -------------------------------------------------------------------------------- /NLS/ubuntu_we.font: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/NLS/ubuntu_we.font -------------------------------------------------------------------------------- /PCB/Gerber_HOT_GUN_v1_2024-03-30.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/PCB/Gerber_HOT_GUN_v1_2024-03-30.zip -------------------------------------------------------------------------------- /PCB/Gerber_HOT_GUN_v2_2024-03-30.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/PCB/Gerber_HOT_GUN_v2_2024-03-30.zip -------------------------------------------------------------------------------- /PCB/Gerber_main_board.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/PCB/Gerber_main_board.zip -------------------------------------------------------------------------------- /PCB/Gerber_tft_board_v2_2024-03-30.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/PCB/Gerber_tft_board_v2_2024-03-30.zip -------------------------------------------------------------------------------- /PCB/Gerber_tft_board_v3_2024-03-30.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/PCB/Gerber_tft_board_v3_2024-03-30.zip -------------------------------------------------------------------------------- /PCB/Gerber_tft_board_v4_2024-03-30.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/PCB/Gerber_tft_board_v4_2024-03-30.zip -------------------------------------------------------------------------------- /PCB/README: -------------------------------------------------------------------------------- 1 | The Gerber files of PCB 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TFT_Rework_station 2 | Soldering and rework station with TFT ili9341 display based on stm32 3 | 4 | Here is a binary firmware of the controller and the controller shcematics files only. 5 | No sources available at the moment. 6 | 7 | The description of the project you can find on hackster https://www.hackster.io/sfrwmaker/stm32-soldering-and-rework-station-with-tft-display-b23f73 8 | 9 | Revision history: 10 | 11 | Nov 04 2021, v.1.02 12 | * Fixed error unformatted flash detection 13 | * Fixed black screen if the flash is not formatted 14 | * Introduce the debug mode 15 | 16 | Dec 17 2021, v.1.03 17 | * Fixed issue the hot Air Gun calibration data rewrites current tip calibration 18 | * Iron anf Hot Air Gun messages changed to icons to simplify project localization 19 | 20 | Dec 21 2021, v.1.04 21 | * Fixed Hot Air Gun setup temperature or fan speed issue in the main working mode 22 | * Added Native Language Support using UTF-8 encoding. Please, consult article on hackster.io how lo upload NLS files to the SPI FLASH. 23 | * Added russian language messages (Cyryllic font + message file) 24 | * Added Portugeese language messages (Western Europe font + message file). Thank to my friend Armindo for translation. 25 | 26 | Dec 22 2021, v.1.05 27 | * Extend diagnistic messages when uploading NLS data from SD-CARD 28 | 29 | Dec 30 2021, v.1.06 30 | * Minor bugs fixed 31 | * Added polish language messages (Western Europe font - impact + message file). In my opinion, the impact font is not very clear, it is better to use unifont_we.font. 32 | 33 | Dec 31, 2021, v.1.07 34 | * Fixed parameter menu incorrect value show issue 35 | 36 | Feb 12, 2022, v.1.08 37 | * Fixed errors in NLS files, added new sentenses to russian ang portugeese languages 38 | * Added support for display rotaion (0, 90, 180, 270 degrees). Landscape display rotation is the default. 39 | * Display rotation menu item added to the parameters menu 40 | 41 | Mar 4, 2022, v.1.09 42 | * Changed rotary endoder procedure. Increased encoder stability. 43 | 44 | Oct 14, 2022, v.1.10 45 | * Rebuilt the project using STM CubeIDE and new HAL firmware. 46 | * Add second binary version with DMA support of the TFT SPI display. 47 | 48 | Nov 14, 2022, v.1.11 49 | * Rebuilt the project with an updateg graphic library version. 50 | * Revisited internal controller logic. 51 | * Minor bugs fixed. 52 | 53 | Nov 26, 2022, v 1.12 54 | * Fixed issues in the parameters menu 55 | * Updated the NLS message files (removed one parameter item, old files should work properly) 56 | 57 | Jan 01, 2023, 1 1.13 58 | * Changed TIM1 value in the debug screen. Now this velus shows the TIM1 period 59 | * Speed-up the power-up procedure. Not the temperature values are read from the hardware during startup 60 | 61 | Mar 29, 2024, v 1.14 62 | * Updated the W25Qxx library 63 | * Fixed some issues regarded read and write operations on FLASH 64 | 65 | Oct 15, 2024, v 1.15 66 | * Added support for IPS display, display drier - ILI9341v. 67 | * Implemented fast hot air gun cooling procedure. 68 | -------------------------------------------------------------------------------- /SRC/Core/Inc/buzzer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * buzzer.h 3 | * 4 | */ 5 | 6 | #ifndef BUZZER_H_ 7 | #define BUZZER_H_ 8 | 9 | #ifndef __BUZZ_H 10 | #define __BUZZ_H 11 | #include "main.h" 12 | 13 | class BUZZER { 14 | public: 15 | BUZZER(void); 16 | void activate(bool e) { enabled = e; } 17 | void lowBeep(void); 18 | void shortBeep(void); 19 | void doubleBeep(void); 20 | void failedBeep(void); 21 | private: 22 | void playTone(uint16_t period_mks, uint16_t duration_ms); 23 | bool enabled = true; 24 | }; 25 | 26 | #endif 27 | 28 | #endif /* BUZZER_H_ */ 29 | -------------------------------------------------------------------------------- /SRC/Core/Inc/cfgtypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cfgtypes.h 3 | * 4 | * Created on: 12 july 2021 5 | * Author: Alex 6 | * 7 | * 2022 Nov 6 8 | * Removed 'CFG_TIP_MANUAL' configuration parameter 9 | * 2024 OCT 06 v.1.15 10 | * Added CFG_FAST_COOLING and CFG_DSPL_TYPE entries to the CFG_BIT_MASK 11 | * Changed the type of bit_mask field (uint8_t -> uint16_t) in the RECORD struct. 12 | */ 13 | 14 | #ifndef CFGTYPES_H_ 15 | #define CFGTYPES_H_ 16 | #include "iron_tips.h" 17 | #include "vars.h" 18 | 19 | /* 20 | * The configuration bit map: 21 | * CFG_CELSIUS - The temperature units: Celsius (1) or Fahrenheit (0) 22 | * CFG_BUZZER - Is the Buzzer Enabled (1) 23 | * CFG_SWITCH - Switch type: Tilt (0) or REED (1) 24 | * CFG_AU_START - Powering on the HAkko T12 iron at startup 25 | * CFG_U_CLOCKWISE - Upper Encoder increments clockwise 26 | * CFG_L_CLOCKWISE - Lower Encoder increments clockwise 27 | * CFG_FAST_COOLING - Start cooling the Hot Air Gun at maximum fan speed 28 | * CFG_BIG_STEP - The temperature step 1 degree (0) 5 degree (1) 29 | * CFG_DSPL_TYPE - The ili9341 display variant: TFT (0) IPS (1) 30 | */ 31 | typedef enum { CFG_CELSIUS = 1, CFG_BUZZER = 2, CFG_SWITCH = 4, CFG_AU_START = 8, 32 | CFG_I_CLOCKWISE = 16, CFG_G_CLOCKWISE = 32, CFG_FAST_COOLING = 64, CFG_BIG_STEP = 128, 33 | CFG_DSPL_TYPE = 256 } CFG_BIT_MASK; 34 | 35 | typedef enum { d_t12 = 0, d_gun = 1, d_unknown } tDevice; 36 | 37 | typedef enum {FLASH_OK = 0, FLASH_ERROR, FLASH_NO_FILESYSTEM, FLASH_NO_DIRECTORY} FLASH_STATUS; 38 | 39 | /* Configuration record in the EEPROM (after the tip table) has the following format: 40 | * Records are aligned by 2**n bytes (in this case, 32 bytes) 41 | * 42 | * Boost is a bit map. The upper 4 bits are boost increment temperature (n*5 Celsius), i.e. 43 | * 0000 - disabled 44 | * 0001 - +4 degrees 45 | * 1111 - +75 degrees 46 | * The lower 4 bits is the boost time ((n+1)* 20 seconds), i.e. 47 | * 0000 - 20 seconds 48 | * 0001 - 40 seconds 49 | * 1111 - 320 seconds 50 | */ 51 | typedef struct s_config RECORD; 52 | struct s_config { 53 | uint16_t crc; // The checksum 54 | uint16_t iron_temp; // The IRON preset temperature in degrees (Celsius or Fahrenheit) 55 | uint16_t gun_temp; // The Hot Air Gun preset temperature in degrees (Celsius or Fahrenheit) 56 | uint16_t gun_fan_speed; // The Hot Air Gun fan speed 57 | uint16_t iron_Kp, iron_Ki, iron_Kd; // The IRON PID coefficients 58 | uint16_t gun_Kp, gun_Ki, gun_Kd; // The Hot Air Gun PID coefficients 59 | uint16_t low_temp; // The low power temperature (C) or 0 if the tilt sensor is disabled 60 | uint8_t low_to; // The low power timeout (5 seconds intervals) 61 | uint8_t boost; // Two 4-bits parameters: The boost increment temperature and boost time. See description above 62 | uint8_t tip; // Current tip index 63 | uint8_t off_timeout; // The Automatic switch-off timeout in minutes [0 - 30] 64 | uint16_t bit_mask; // See CFG_BIT_MASK 65 | uint8_t dspl_bright; // The display brightness 66 | uint8_t dspl_rotation; // The display rotation (TFT_ROTATION_0, TFT_ROTATION_90, TFT_ROTATION_180, TFT_ROTATION_270) 67 | char language[LANG_LENGTH]; // The language. lLANG_LENGTH defined in vars.h 68 | }; 69 | 70 | /* 71 | * Configuration data of each initialized tip are saved in the tipcal.dat file (16 bytes per tip record). 72 | * The tip configuration record has the following format: 73 | * 4 reference temperature points 74 | * tip status bitmap 75 | * tip suffix name 76 | */ 77 | typedef struct s_tip TIP; 78 | struct s_tip { 79 | uint16_t t200, t260, t330, t400; // The internal temperature in reference points 80 | uint8_t mask; // The bit mask: TIP_ACTIVE + TIP_CALIBRATED 81 | char name[tip_name_sz]; // T12 tip name suffix, JL02 for T12-JL02 82 | int8_t ambient; // The ambient temperature in Celsius when the tip being calibrated 83 | uint8_t crc; // CRC checksum 84 | }; 85 | 86 | // This tip structure is used to show available tips when tip is activating 87 | typedef struct s_tip_list_item TIP_ITEM; 88 | struct s_tip_list_item { 89 | uint8_t tip_index; // Index of the tip in the global list in EEPROM 90 | uint8_t mask; // The bit mask: 0 - active, 1 - calibrated 91 | char name[tip_name_sz+5]; // Complete tip name, i.e. T12-*** 92 | }; 93 | 94 | /* 95 | * This structure presents a tip record for all possible tips, declared in iron_tips.c 96 | * During controller initialization phase, the buildTipTable() function creates 97 | * the tip list in memory of all possible tips. If the tip is calibrated, i.e. has a record 98 | * in the tipcal.dat file on W25Qxx flash, the tip record saves tip record index in the file 99 | */ 100 | typedef struct s_tip_table TIP_TABLE; 101 | struct s_tip_table { 102 | uint8_t tip_index; // The tip index in the calib.tip file 103 | uint8_t tip_mask; // The bit mask: 0 - active, 1 - calibrated 104 | }; 105 | 106 | typedef enum tip_status { TIP_ACTIVE = 1, TIP_CALIBRATED = 2 } TIP_STATUS; 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /SRC/Core/Inc/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * config.h 3 | * 4 | * Created on: 12 july 2021. 5 | * Author: Alex 6 | * 2024 OCT 06, v.1.15 7 | * Added CFG::CORE::isFastGunCooling() 8 | * Added new parameter to CFG_CORE::setup() 9 | * Added new internal type (struct s_setup) into CFG_CORE class allowing to pass parameters into CFG_CORE::setup() 10 | * Added new method, CFG_CORE::getMainParams() 11 | */ 12 | 13 | #ifndef CONFIG_H_ 14 | #define CONFIG_H_ 15 | 16 | #include 17 | #include 18 | #include "main.h" 19 | #include "pid.h" 20 | #include "flash.h" 21 | #include "cfgtypes.h" 22 | #include "iron_tips.h" 23 | #include "buzzer.h" 24 | 25 | typedef enum {CFG_OK = 0, CFG_NO_TIP, CFG_READ_ERROR, CFG_NO_FILESYSTEM} CFG_STATUS; 26 | 27 | /* 28 | * The actual configuration record is loaded from the EEPROM chunk into a_cfg variable 29 | * The spare copy of the configuration record is preserved into s_cfg variable 30 | * When update request arrives, configuration record writes into EEPROM if spare copy is different from actual copy 31 | */ 32 | class CFG_CORE: public TIPS { 33 | public: 34 | typedef struct s_setup { 35 | uint8_t off_timeout; 36 | bool buzzer; 37 | bool celsius; 38 | bool reed; 39 | bool big_temp_step; 40 | bool i_enc; 41 | bool g_enc; 42 | bool fast_cooling; 43 | bool auto_start; 44 | uint16_t low_temp; 45 | uint8_t low_to; 46 | uint8_t bright; 47 | bool ips_display; 48 | } t_setup_arg; 49 | 50 | CFG_CORE(void) { } 51 | bool isCelsius(void) { return a_cfg.bit_mask & CFG_CELSIUS; } 52 | bool isBuzzerEnabled(void) { return a_cfg.bit_mask & CFG_BUZZER; } 53 | bool isReedType(void) { return a_cfg.bit_mask & CFG_SWITCH; } 54 | bool isBigTempStep(void) { return a_cfg.bit_mask & CFG_BIG_STEP; } 55 | bool isAutoStart(void) { return a_cfg.bit_mask & CFG_AU_START; } 56 | bool isIronEncClockWise(void) { return a_cfg.bit_mask & CFG_I_CLOCKWISE; } 57 | bool isGunEncClockWise(void) { return a_cfg.bit_mask & CFG_G_CLOCKWISE; } 58 | bool isFastGunCooling(void) { return a_cfg.bit_mask & CFG_FAST_COOLING; } 59 | bool isIPS(void) { return a_cfg.bit_mask & CFG_DSPL_TYPE; } 60 | uint16_t tempPresetHuman(void) { return a_cfg.iron_temp; } // Human readable units 61 | uint16_t gunTempPreset(void) { return a_cfg.gun_temp; } // Human readable units 62 | uint16_t gunFanPreset(void) { return a_cfg.gun_fan_speed; } 63 | uint8_t getOffTimeout(void) { return a_cfg.off_timeout; } 64 | uint16_t getLowTemp(void) { return a_cfg.low_temp; } 65 | uint8_t getLowTO(void) { return a_cfg.low_to; } // 5-seconds intervals 66 | uint8_t getDsplBrightness(void) { return a_cfg.dspl_bright; } 67 | uint8_t getDsplRotation(void) { return a_cfg.dspl_rotation; } 68 | void setDsplRotation(uint8_t rotation) { a_cfg.dspl_rotation = rotation; } 69 | void setLanguage(const char *lang) { strncpy(a_cfg.language, lang, LANG_LENGTH);} 70 | const char *getLanguage(void); // Returns current language name 71 | void getMainParams(t_setup_arg &prm); 72 | void setup(t_setup_arg &arg); 73 | void savePresetTempHuman(uint16_t temp_set); 74 | void saveGunPreset(uint16_t temp, uint16_t fan = 0); 75 | uint8_t boostTemp(void); 76 | uint16_t boostDuration(void); 77 | void saveBoost(uint8_t temp, uint16_t duration); 78 | void restoreConfig(void); 79 | PIDparam pidParams(tDevice dev); 80 | PIDparam pidParamsSmooth(tDevice dev); 81 | protected: 82 | void setDefaults(void); 83 | void syncConfig(void); 84 | bool areConfigsIdentical(void); 85 | RECORD a_cfg; // active configuration 86 | private: 87 | RECORD s_cfg; // spare configuration, used when save the configuration to the EEPROM 88 | }; 89 | 90 | typedef struct s_TIP_RECORD TIP_RECORD; 91 | struct s_TIP_RECORD { 92 | uint16_t calibration[4]; 93 | uint8_t mask; 94 | int8_t ambient; 95 | }; 96 | 97 | class TIP_CFG { 98 | public: 99 | TIP_CFG(void) { } 100 | bool isTipCalibrated(void) { return tip[0].mask & TIP_CALIBRATED; } 101 | uint16_t tempMinC(tDevice dev) { return (dev == d_gun)?gun_temp_minC:iron_temp_minC; } 102 | uint16_t tempMaxC(tDevice dev) { return (dev == d_gun)?gun_temp_maxC:iron_temp_maxC; } 103 | void load(const TIP& tip, tDevice dev = d_t12); 104 | void dump(TIP* tip, tDevice dev = d_t12); 105 | int8_t ambientTemp(tDevice dev); 106 | uint16_t calibration(uint8_t index, tDevice dev); 107 | uint16_t referenceTemp(uint8_t index, tDevice dev); 108 | uint16_t tempCelsius(uint16_t temp, int16_t ambient, tDevice dev); 109 | void getTipCalibtarion(uint16_t temp[4], tDevice dev); 110 | void applyTipCalibtarion(uint16_t temp[4], int8_t ambient, tDevice dev); 111 | void resetTipCalibration(tDevice dev); 112 | protected: 113 | void defaultCalibration(tDevice dev = d_t12); 114 | bool isValidTipConfig(TIP *tip); 115 | private: 116 | TIP_RECORD tip[2]; // Active IRON tip (0) and Hot Air Gun virtual tip (1) 117 | const uint16_t temp_ref_iron[4] = { 200, 260, 330, 400}; 118 | const uint16_t temp_ref_gun[4] = { 200, 300, 400, 500}; 119 | }; 120 | 121 | class CFG : public W25Q, public CFG_CORE, public TIP_CFG, public BUZZER { 122 | public: 123 | CFG(void) { } 124 | CFG_STATUS init(void); 125 | bool reloadTips(void); 126 | uint16_t tempToHuman(uint16_t temp, int16_t ambient, tDevice dev); 127 | uint16_t humanToTemp(uint16_t temp, int16_t ambient, tDevice dev); 128 | uint16_t lowTempInternal(int16_t ambient, tDevice dev); 129 | std::string tipName(tDevice dev); 130 | void changeTip(uint8_t index); 131 | uint8_t currentTipIndex(tDevice dev); 132 | void saveTipCalibtarion(uint8_t index, uint16_t temp[4], uint8_t mask, int8_t ambient); 133 | bool toggleTipActivation(uint8_t index); 134 | int tipList(uint8_t second, TIP_ITEM list[], uint8_t list_len, bool active_only); 135 | uint8_t nearActiveTip(uint8_t current_tip); 136 | void saveConfig(void); 137 | void savePID(PIDparam &pp, tDevice dev = d_t12); 138 | void initConfig(void); 139 | bool clearAllTipsCalibration(void); // Remove tip calibration data 140 | private: 141 | void correctConfig(RECORD *cfg); 142 | bool selectTip(tDevice dev_type, uint8_t index); 143 | uint8_t buildTipTable(TIP_TABLE tt[]); 144 | std::string buildFullTipName(const uint8_t index); 145 | TIP_TABLE *tip_table = 0; // Tip table - chunk number of the tip or 0xFF if does not exist in the EEPROM 146 | }; 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /SRC/Core/Inc/core.h: -------------------------------------------------------------------------------- 1 | /* 2 | * core.h 3 | * 4 | * Created on: 16 sep 2019 5 | * Author: Alex 6 | * 7 | * 2022 DEC 26 8 | * Added gtimPeriod() function that return the period of GUN timer in ms 9 | */ 10 | 11 | #ifndef CORE_H_ 12 | #define CORE_H_ 13 | 14 | #include "main.h" 15 | 16 | #ifndef __cplusplus 17 | #include 18 | #endif 19 | 20 | // Forward function declaration 21 | bool isACsine(void); 22 | uint16_t gtimPeriod(void); 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | void setup(void); 29 | void loop(void); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /SRC/Core/Inc/encoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * encoder.h 3 | * 4 | * Created on: 15 aug. 2019. 5 | * Author: Alex 6 | * 7 | * 2024 OCT 09, v.1.15 8 | * Added RENC::enc_int variable to calculate the number of encoder interrupts. Used in debug mode. 9 | * Added RENC::intNumber() method 10 | * Added RENC::buttonPressed() method to check current button status 11 | */ 12 | 13 | #ifndef ENCODER_H_ 14 | #define ENCODER_H_ 15 | #include "main.h" 16 | #include "stat.h" 17 | 18 | class RENC { 19 | public: 20 | RENC(GPIO_TypeDef* aPORT, uint16_t aPIN, GPIO_TypeDef* bPORT, uint16_t bPIN); 21 | void addButton(GPIO_TypeDef* ButtonPORT, uint16_t ButtonPIN); 22 | uint8_t buttonStatus(void); 23 | void setClockWise(bool clockwise) { this->clockwise = clockwise; } 24 | bool write(int16_t initPos); 25 | void reset(int16_t initPos, int16_t low, int16_t upp, uint8_t inc, uint8_t fast_inc, bool looped); 26 | void encoderIntr(void); 27 | void setTimeout(uint16_t timeout_ms) { over_press = timeout_ms; } 28 | void setIncrement(uint8_t inc) { increment = fast_increment = inc; } 29 | uint8_t getIncrement(void) { return increment; } 30 | int16_t read(void) { return pos; } 31 | bool buttonPressed(void) { return (GPIO_PIN_RESET == HAL_GPIO_ReadPin(b_port, b_pin)); } 32 | uint32_t intNumber(void); 33 | private: 34 | EMP_AVERAGE avg; // Do average the button readings to maintain the button status 35 | int16_t min_pos = 0; // Minimum value of rotary encoder 36 | int16_t max_pos = 0; // Maximum value of roraty encoder 37 | uint16_t over_press = 0; // Maximum time in ms the button can be pressed 38 | bool is_looped = false; // Whether the encoder is looped 39 | uint8_t increment = 0; // The value to add or substract for each encoder tick 40 | uint8_t fast_increment = 0; // The value to change encoder when it runs quickly 41 | volatile uint32_t rpt = 0; // Time in ms when the encoder was rotated 42 | volatile uint32_t changed = 0; // Time in ms when the value was changed 43 | volatile int16_t pos = 0; // Encoder current position 44 | volatile bool s_up = false; // The status of the secondary channel 45 | bool i_b_rel = false; // Ignore button release event 46 | bool b_on = false; // The button current position: true - pressed 47 | uint32_t bpt = 0; // Time in ms when the button was pressed (press time) 48 | uint32_t b_check = 0; // Time in ms when the button should be checked 49 | GPIO_TypeDef* b_port = 0; // The PORT of the press button 50 | GPIO_TypeDef* m_port = 0; // The PORT of the main channel 51 | GPIO_TypeDef* s_port = 0; // The PORT of the secondary channel 52 | uint16_t b_pin = 0; // The PIN number of the button 53 | uint16_t m_pin = 0; // The PIN number of the main channel 54 | uint16_t s_pin = 0; // The PIN number of the secondary channel 55 | uint32_t enc_int = 0; // The number of encoder interrupts received 56 | bool clockwise = true; // How exactly the encoder soldered 57 | const uint8_t trigger_on = 100; // avg limit to change button status to on 58 | const uint8_t trigger_off = 50; // avg limit to change button status to off 59 | const uint8_t avg_length = 4; // avg length 60 | const uint8_t b_check_period = 20; // The button check period, ms 61 | const uint16_t long_press = 1500; // If the button was pressed more that this timeout, we assume the long button press 62 | const uint16_t fast_timeout = 300; // Time in ms to change encoder quickly 63 | const uint16_t def_over_press = 2500; // Default value for button over press timeout (ms) 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /SRC/Core/Inc/flash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * flash.h 3 | * 4 | */ 5 | 6 | #ifndef _FLASH_H_ 7 | #define _FLASH_H_ 8 | 9 | #include "cfgtypes.h" 10 | #include "ff.h" 11 | #include "vars.h" 12 | 13 | typedef enum tip_io_status {TIP_OK = 0, TIP_IO, TIP_CHECKSUM, TIP_INDEX} TIP_IO_STATUS; 14 | typedef enum active_file {W25Q_NOT_MOUNTED = 0, W25Q_NONE, W25Q_TIPS_CURRENT, W25Q_TIPS_BACKUP, W25Q_CONFIG_CURRENT, W25Q_CONFIG_BACKUP} ACT_FILE; 15 | 16 | class W25Q { 17 | public: 18 | W25Q(void) { } 19 | FLASH_STATUS init(void); // Initialize flash, read tip configuration 20 | bool reset(); // Initialize flash, re-check flash size 21 | bool mount(void); 22 | void umount(void); 23 | void close(void); 24 | bool loadRecord(RECORD* config_record); 25 | bool saveRecord(RECORD* config_record); 26 | TIP_IO_STATUS loadTipData(TIP* tip, uint8_t tip_index, bool keep = false); 27 | int16_t saveTipData(TIP* tip, bool keep = false); // Return tip index in the file or -1 if error 28 | bool formatFlashDrive(void); 29 | bool clearTips(void); 30 | bool clearConfig(void); 31 | bool canDelete(const TCHAR *file_name); 32 | private: 33 | TIP_IO_STATUS returnStatus(bool keep, TIP_IO_STATUS ret_code); 34 | uint8_t TIP_checkSum(TIP* tip, bool write); 35 | uint8_t CFG_checkSum(RECORD* cfg, bool write); 36 | bool backup(ACT_FILE type); 37 | FIL cfg_f; 38 | ACT_FILE act_f = W25Q_NOT_MOUNTED; // Open file 39 | const uint16_t blk_size = 4096; 40 | const TCHAR* fn_tip_calib = "tipcal.dat"; 41 | const TCHAR* fn_tip_backup = "tipcal.bak"; 42 | const TCHAR* fn_cfg = "config.dat"; 43 | const TCHAR* fn_cfg_backup = "config.bak"; 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /SRC/Core/Inc/font.h: -------------------------------------------------------------------------------- 1 | /* 2 | * font.h 3 | * 4 | */ 5 | 6 | #ifndef FONT_H_ 7 | #define FONT_H_ 8 | 9 | #include "tft.h" 10 | 11 | extern const uint8_t u8g2_font_kam24n[] U8G2_FONT_SECTION("google_kameron_24"); 12 | extern const uint8_t u8g2_font_kam26n[] U8G2_FONT_SECTION("google_kameron_26"); 13 | extern const uint8_t u8g2_font_kam28n[] U8G2_FONT_SECTION("google_kameron_28"); 14 | extern const uint8_t u8g2_font_kam42n[] U8G2_FONT_SECTION("google_kameron_42"); 15 | extern const uint8_t u8g2_font_kam16r[] U8G2_FONT_SECTION("google_kameron_16"); 16 | extern const uint8_t u8g2_font_ubuntu16_cyr[] U8G2_FONT_SECTION("ubuntu_16_cyr"); 17 | extern const uint8_t u8g2_font_ubuntu16r[] U8G2_FONT_SECTION("ubuntu16"); 18 | extern const uint8_t u8g2_font_ubuntu16u[] U8G2_FONT_SECTION("ubuntu16u"); 19 | extern const uint8_t u8g2_font_robotou[] U8G2_FONT_SECTION("u8g2_font_roboto"); 20 | extern const uint8_t u8g2_font_ubuntu_we[] U8G2_FONT_SECTION("u8g2_font_ubuntu_we"); 21 | extern const uint8_t u8g2_font_impact16r[] U8G2_FONT_SECTION("u8g2_font_impactr"); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /SRC/Core/Inc/graph.h: -------------------------------------------------------------------------------- 1 | /* 2 | * graph.h 3 | * 4 | */ 5 | 6 | #ifndef GRAPH_H_ 7 | #define GRAPH_H_ 8 | 9 | #include 10 | 11 | class GRAPH { 12 | public: 13 | GRAPH(void) { } 14 | bool isFull(void) { return full_buff; } 15 | uint16_t dataSize(void) { return (full_buff)?size:data_index; } 16 | void reset(void) { data_index = 0; full_buff = false; } 17 | bool allocate(uint16_t size); 18 | void freeData(void); 19 | void put(int16_t t, uint16_t d); 20 | int16_t temp(uint16_t index); 21 | uint16_t disp(uint16_t index); 22 | private: 23 | uint16_t indx(uint16_t i); 24 | uint16_t size = 0; // The graph size 25 | int16_t *h_temp = 0; // The temperature history data, allocated later 26 | uint16_t *h_disp = 0; // The dispersion history data, allocated later 27 | uint16_t data_index = 0; // The index in the array to put new data 28 | bool full_buff = false; // Whether the history data buffer is full 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /SRC/Core/Inc/gun.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gun.h 3 | * 4 | * 2024 OCT 06, v.1.15 5 | * Added fast_cooling parameter to HOTGUN 6 | * Added HOTGUN::setFastGunCooling() 7 | * Changed the HOTGUN::sw_avg_len from 10 to 13 8 | */ 9 | 10 | #ifndef GUN_H_ 11 | #define GUN_H_ 12 | 13 | #include "stat.h" 14 | #include "tools.h" 15 | #include "unit.h" 16 | 17 | class HOTGUN : public UNIT { 18 | public: 19 | typedef enum { POWER_OFF, POWER_ON, POWER_FIXED, POWER_COOLING, POWER_PID_TUNE } PowerMode; 20 | HOTGUN(void) : h_power(hot_gun_hist_length), h_temp(hot_gun_hist_length) { } 21 | void init(void); 22 | bool isOn(void) { return (mode == POWER_ON || mode == POWER_FIXED); } 23 | virtual uint16_t presetTemp(void) { return temp_set; } 24 | uint16_t presetFan(void) { return fan_speed; } 25 | virtual uint16_t averageTemp(void) { return avg_sync_temp; } 26 | virtual uint16_t getMaxFixedPower(void) { return max_fix_power; } 27 | bool isCold(void) { return avg_sync_temp < temp_gun_cold; } 28 | bool isFanWorking(void) { return (fanSpeed() >= min_fan_speed); } 29 | uint16_t maxFanSpeed(void) { return max_fan_speed; } 30 | virtual uint16_t pwrDispersion(void) { return d_power.read(); } 31 | virtual uint16_t tmpDispersion(void) { return d_temp.read(); } 32 | virtual void setTemp(uint16_t temp) { temp_set = constrain(temp, 0, int_temp_max); } 33 | void setFan(uint16_t fan) { fan_speed = constrain(fan, min_working_fan, max_fan_speed); } 34 | void setFastGunCooling(bool on) { fast_cooling = on; } 35 | void fanFixed(uint16_t fan) { TIM2->CCR2 = constrain(fan, 0, max_fan_speed);} 36 | void fanControl(bool on); 37 | void updateTemp(uint16_t value); 38 | virtual void switchPower(bool On); 39 | virtual void autoTunePID(uint16_t base_pwr, uint16_t delta_power, uint16_t base_temp, uint16_t temp); 40 | virtual uint16_t avgPower(void) { return avgPowerPcnt(); } 41 | virtual uint8_t avgPowerPcnt(void); 42 | uint16_t appliedPower(void); 43 | uint16_t fanSpeed(void); // Fan supplied to Fan, PWM duty 44 | virtual void fixPower(uint16_t Power); // Set the specified power to the the hot gun 45 | uint8_t presetFanPcnt(void); 46 | uint16_t power(void); // Required Hot Air Gun power to keep the preset temperature 47 | void safetyRelay(bool activate); 48 | private: 49 | void shutdown(void); 50 | PowerMode mode = POWER_OFF; 51 | uint8_t fix_power = 0; // Fixed power value of the Hot Air Gun (or zero if off) 52 | bool chill = false; // Chill the Hot Air gun if it is over heating 53 | bool reach_cold_temp = true; // Flag indicating the Hot Air Gun has reached the 'temp_gun_cold' temperature 54 | bool fast_cooling = false; // Flag indicating maximum fan speed when cooling 55 | uint16_t temp_set = 0; // The preset temperature of the hot air gun (internal units) 56 | uint16_t fan_speed = 0; // Preset fan speed 57 | uint32_t fan_off_time = 0; // Time when the fan should be powered off in cooling mode (ms) 58 | uint32_t extra_time = 0; // The extra cooling time before switch off the fan 59 | EMP_AVERAGE h_power; // Exponential average of applied power 60 | EMP_AVERAGE h_temp; // Exponential average of Hot Air Gun temperature. Updated in HAL_ADC_ConvCpltCallback() see core.cpp 61 | EMP_AVERAGE d_power; // Exponential average of power dispersion 62 | EMP_AVERAGE d_temp; // Exponential temperature math dispersion 63 | EMP_AVERAGE zero_temp; // Exponential average of minimum (zero) temperature 64 | volatile uint16_t avg_sync_temp = 0; // Average temperature synchronized with TIM1 (used to calculate required power, see power() method) 65 | volatile uint8_t relay_ready_cnt = 0; // The relay ready counter, see HOTHUN::power() 66 | const uint8_t max_fix_power = 70; 67 | const uint8_t max_power = 99; 68 | const uint16_t min_fan_speed = 600; 69 | const uint16_t max_fan_speed = 1999; 70 | const uint16_t max_cool_fan = 1600; 71 | const uint16_t min_working_fan = 800; 72 | const uint16_t temp_gun_cold = 60; // The temperature of the cold Hot Air Gun 73 | const uint32_t fan_off_timeout = 6*60*1000;// The timeout to turn the fan off in cooling mode 74 | const uint32_t extra_cool_to = 60000; // One minute to cool the fan after low temperature detected 75 | const uint16_t fan_off_value = 500; 76 | const uint16_t fan_on_value = 1000; 77 | const uint8_t sw_off_value = 30; 78 | const uint8_t sw_on_value = 60; 79 | const uint8_t sw_avg_len = 13; 80 | const uint32_t relay_activate = 1; // The relay activation delay (loops of TIM1, 1 time per second) 81 | }; 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /SRC/Core/Inc/hw.h: -------------------------------------------------------------------------------- 1 | /* 2 | * hw.h 3 | * 4 | * Created on: 12 july 2021 5 | * Author: Alex 6 | * 7 | * 2023 JAN 01 8 | * Added arguments into HW::init() method to initialize the hardware at startup 9 | */ 10 | 11 | #ifndef HW_H_ 12 | #define HW_H_ 13 | 14 | /* 15 | * This is a fusion file to join c++ project and main.c file generated by CubeMX 16 | */ 17 | 18 | #include "stat.h" 19 | #include "iron.h" 20 | #include "gun.h" 21 | #include "encoder.h" 22 | #include "display.h" 23 | #include "config.h" 24 | #include "buzzer.h" 25 | #include "nls.h" 26 | #include "nls_cfg.h" 27 | 28 | class HW { 29 | public: 30 | HW(void) : cfg(), 31 | i_enc(I_ENC_R_GPIO_Port, I_ENC_R_Pin, I_ENC_L_GPIO_Port, I_ENC_L_Pin), 32 | g_enc(G_ENC_R_GPIO_Port, G_ENC_R_Pin, G_ENC_L_GPIO_Port, G_ENC_L_Pin) { } 33 | CFG_STATUS init(uint16_t t12_temp, uint16_t gun_temp, uint16_t ambient); 34 | uint16_t ambientInternal(void) { return t_amb.read(); } 35 | bool noAmbientSensor(void) { return t_amb.read() >= max_ambient_value; } 36 | void updateAmbient(uint32_t value) { t_amb.update(value); } 37 | int32_t ambientTemp(void); // T12 IRON ambient temperature 38 | CFG cfg; 39 | NLS nls; 40 | DSPL dspl; 41 | IRON iron; 42 | RENC i_enc, g_enc; 43 | HOTGUN hotgun; 44 | BUZZER buzz; 45 | private: 46 | EMP_AVERAGE t_amb; // Exponential average of the ambient temperature 47 | const uint8_t ambient_emp_coeff = 30; // Exponential average coefficient for ambient temperature 48 | const uint16_t max_ambient_value = 3900; // About -30 degrees. If the soldering IRON disconnected completely, "ambient" value is greater than this 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /SRC/Core/Inc/iron.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iron.h 3 | * 4 | * 2022 Nov 6 5 | * Added POWER_HEATING mode to prevent soldering iron overheating in the first phase 6 | * 2022 Nov 9 7 | * Added b_reset bool variable flag to initialize the IRON temperature EMP_AVERAGE values 8 | * 2023 JAN 01 9 | * Added argument into IRON::init() method 10 | * 11 | */ 12 | 13 | #ifndef IRON_H_ 14 | #define IRON_H_ 15 | 16 | #include "stat.h" 17 | #include "unit.h" 18 | 19 | class IRON : public UNIT { 20 | public: 21 | typedef enum { POWER_OFF, POWER_HEATING, POWER_ON, POWER_FIXED, POWER_COOLING, POWER_PID_TUNE, POWER_BOOST } PowerMode; 22 | IRON(void) { } 23 | void init(uint16_t temp); 24 | virtual void switchPower(bool On); 25 | virtual void autoTunePID(uint16_t base_pwr, uint16_t delta_power, uint16_t base_temp, uint16_t temp); 26 | bool isOn(void) { return (mode == POWER_ON); } 27 | uint16_t temp(void) { return temp_curr; } 28 | virtual uint16_t presetTemp(void) { return temp_set; } 29 | virtual uint16_t averageTemp(void) { return h_temp.read(); } 30 | virtual uint16_t tmpDispersion(void) { return d_temp.read(); } 31 | virtual uint16_t pwrDispersion(void) { return d_power.read(); } 32 | virtual uint16_t getMaxFixedPower(void) { return max_fix_power; } 33 | bool isCold(void) { return (mode == POWER_OFF); } 34 | int32_t tempShortAverage(int32_t t) { return t_iron_short.average(t); } 35 | void resetShortTemp(void) { t_iron_short.reset(); } 36 | void setCheckPeriod(uint8_t t) { check_period = check_time = t; } 37 | virtual void setTemp(uint16_t t); // Set the temperature to be kept (internal units) 38 | virtual uint16_t avgPower(void); // Average applied power 39 | virtual uint8_t avgPowerPcnt(void); // Power applied to the IRON in percents 40 | virtual void fixPower(uint16_t Power); // Set the specified power to the the soldering IRON 41 | void adjust(uint16_t t); // Adjust preset temperature depending on ambient temperature 42 | uint16_t power(int32_t t); // Required power to keep preset temperature 43 | void reset(void); // Iron is disconnected, clear the temp history 44 | void lowPowerMode(uint16_t t); // Activate low power mode (preset temp.) To disable, use switchPower(true) 45 | void boostPowerMode(uint16_t t); // Activate boost power mode 46 | private: 47 | uint16_t temp_set = 0; // The temperature that should be kept 48 | uint16_t temp_low = 0; // The temperature in low power mode (if not zero) 49 | uint16_t temp_boost = 0; // The temperature in boost mode (if not zero) 50 | uint16_t fix_power = 0; // Fixed power value of the IRON (or zero if off) 51 | volatile PowerMode mode = POWER_OFF; // Working mode of the IRON 52 | volatile bool chill = false; // Whether the IRON should be cooled (preset temp is lower than current) 53 | volatile uint16_t temp_curr = 0; // The actual IRON temperature 54 | volatile uint8_t check_period= 0; // The period to check the current through the IRON 55 | volatile uint8_t check_time = 0; // The time when to check the current through the IRON 56 | EMP_AVERAGE t_iron_short; // Exponential average of the IRON temperature (short period) 57 | EMP_AVERAGE h_power; // Exponential average of applied power 58 | EMP_AVERAGE h_temp; // Exponential average of temperature 59 | EMP_AVERAGE d_power; // Exponential average of power math dispersion 60 | EMP_AVERAGE d_temp; // Exponential temperature math dispersion 61 | bool t_reset = false; // The temperature value was reset 62 | const uint16_t max_power = 1960; // Maximum power to the IRON 63 | const uint16_t max_fix_power = 1000; // Maximum power in fixed power mode 64 | const uint8_t ec = 20; // Exponential average coefficient 65 | const uint16_t iron_cold = 100; // The internal temperature when the IRON is cold 66 | const uint8_t iron_emp_coeff = 8; // Exponential average coefficient for IRON temperature 67 | const uint16_t iron_off_value = 500; 68 | const uint16_t iron_on_value = 1000; 69 | const uint8_t iron_sw_len = 3; // Exponential coefficient of current through the IRON switch 70 | const uint8_t sw_off_value = 14; 71 | const uint8_t sw_on_value = 20; 72 | const uint8_t sw_avg_len = 5; 73 | const uint8_t sw_tilt_len = 2; 74 | }; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /SRC/Core/Inc/iron_tips.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iron_tips.h 3 | * 4 | * Created on: 15 aug. 2019. 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef IRON_TIPS_H_ 9 | #define IRON_TIPS_H_ 10 | #include "main.h" 11 | 12 | // The length of the tip name 13 | #define tip_name_sz (5) 14 | 15 | class TIPS { 16 | public: 17 | TIPS() { } 18 | uint16_t loaded(void); 19 | const char* name(uint8_t index); 20 | int index(const char *name); 21 | }; 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /SRC/Core/Inc/jsoncfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * jsoncfg.h 3 | * 4 | */ 5 | 6 | #ifndef JSONCFG_H_ 7 | #define JSONCFG_H_ 8 | 9 | #include 10 | #include 11 | #include "JsonParser.h" 12 | #include "ff.h" 13 | #include "nls.h" 14 | 15 | //--------------------------------------------------- Configuration file parser ------------------------------- 16 | class FILE_PARSER: public JsonListener { 17 | public: 18 | FILE_PARSER() : JsonListener() { } 19 | virtual ~FILE_PARSER(void) { } 20 | virtual void key(std::string key) { d_key = key; } 21 | virtual void endObject(); 22 | virtual void startObject(); 23 | virtual void startArray(); 24 | virtual void endArray(); 25 | virtual void startDocument(); 26 | virtual void endDocument() { } 27 | virtual void whitespace(char c) { } 28 | protected: 29 | void readFile(FIL *file); 30 | std::string d_key; 31 | std::stack s_array; 32 | std::stack s_key; // Json structure stack 33 | // std::string d_parent; 34 | // std::string d_array; 35 | // std::stack p_key; // Json structure stack 36 | }; 37 | 38 | //--------------------------------------------------- "cfg.json" main NLS configuration file parser ----------- 39 | typedef struct s_lang_cfg { 40 | std::string lang; 41 | std::string messages_file; 42 | std::string font_file; 43 | } t_lang_cfg; 44 | 45 | typedef std::vector t_lang_list; 46 | 47 | class JSON_LANG_CFG : public FILE_PARSER { 48 | public: 49 | JSON_LANG_CFG() { } 50 | virtual void endDocument(); 51 | virtual void value(std::string value); 52 | void readConfig(FIL *file); 53 | void addEnglish(); // Add default (English) language entry to the list 54 | uint8_t listSize(void) { return lang_list.size(); } 55 | t_lang_list *getLangList(void) { return &lang_list; } 56 | private: 57 | t_lang_cfg data; 58 | t_lang_list lang_list; // Use vector to save language list config 59 | }; 60 | 61 | //--------------------------------------------------- Messages parser ----------------------------------------- 62 | class JSON_MESSAGES : public FILE_PARSER { 63 | public: 64 | JSON_MESSAGES() { } 65 | void readConfig(FIL *file) { readFile(file); } 66 | void setNLS_MSG(NLS_MSG *pMsg) { this->pMsg = pMsg; } 67 | virtual void value(std::string value); 68 | private: 69 | NLS_MSG *pMsg = 0; 70 | }; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /SRC/Core/Inc/main.h: -------------------------------------------------------------------------------- 1 | /* USER CODE BEGIN Header */ 2 | /** 3 | ****************************************************************************** 4 | * @file : main.h 5 | * @brief : Header for main.c file. 6 | * This file contains the common defines of the application. 7 | ****************************************************************************** 8 | * @attention 9 | * 10 | *

© Copyright (c) 2021 STMicroelectronics. 11 | * All rights reserved.

12 | * 13 | * This software component is licensed by ST under BSD 3-Clause license, 14 | * the "License"; You may not use this file except in compliance with the 15 | * License. You may obtain a copy of the License at: 16 | * opensource.org/licenses/BSD-3-Clause 17 | * 18 | ****************************************************************************** 19 | */ 20 | /* USER CODE END Header */ 21 | 22 | /* Define to prevent recursive inclusion -------------------------------------*/ 23 | #ifndef __MAIN_H 24 | #define __MAIN_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /* Includes ------------------------------------------------------------------*/ 31 | #include "stm32f4xx_hal.h" 32 | 33 | /* Private includes ----------------------------------------------------------*/ 34 | /* USER CODE BEGIN Includes */ 35 | 36 | /* USER CODE END Includes */ 37 | 38 | /* Exported types ------------------------------------------------------------*/ 39 | /* USER CODE BEGIN ET */ 40 | 41 | /* USER CODE END ET */ 42 | 43 | /* Exported constants --------------------------------------------------------*/ 44 | /* USER CODE BEGIN EC */ 45 | 46 | /* USER CODE END EC */ 47 | 48 | /* Exported macro ------------------------------------------------------------*/ 49 | /* USER CODE BEGIN EM */ 50 | 51 | /* USER CODE END EM */ 52 | 53 | void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); 54 | 55 | /* Exported functions prototypes ---------------------------------------------*/ 56 | void Error_Handler(void); 57 | 58 | /* USER CODE BEGIN EFP */ 59 | 60 | /* USER CODE END EFP */ 61 | 62 | /* Private defines -----------------------------------------------------------*/ 63 | #define AC_RELAY_Pin GPIO_PIN_13 64 | #define AC_RELAY_GPIO_Port GPIOC 65 | #define G_ENC_B_Pin GPIO_PIN_14 66 | #define G_ENC_B_GPIO_Port GPIOC 67 | #define G_ENC_R_Pin GPIO_PIN_15 68 | #define G_ENC_R_GPIO_Port GPIOC 69 | #define IRON_POWER_Pin GPIO_PIN_0 70 | #define IRON_POWER_GPIO_Port GPIOA 71 | #define FAN_POWER_Pin GPIO_PIN_1 72 | #define FAN_POWER_GPIO_Port GPIOA 73 | #define IRON_CURRENT_Pin GPIO_PIN_2 74 | #define IRON_CURRENT_GPIO_Port GPIOA 75 | #define FAN_CURRENT_Pin GPIO_PIN_3 76 | #define FAN_CURRENT_GPIO_Port GPIOA 77 | #define IRON_TEMP_Pin GPIO_PIN_4 78 | #define IRON_TEMP_GPIO_Port GPIOA 79 | #define GUN_TEMP_Pin GPIO_PIN_5 80 | #define GUN_TEMP_GPIO_Port GPIOA 81 | #define AMBIENT_Pin GPIO_PIN_6 82 | #define AMBIENT_GPIO_Port GPIOA 83 | #define TFT_SDI_Pin GPIO_PIN_7 84 | #define TFT_SDI_GPIO_Port GPIOA 85 | #define I_ENC_L_Pin GPIO_PIN_0 86 | #define I_ENC_L_GPIO_Port GPIOB 87 | #define I_ENC_L_EXTI_IRQn EXTI0_IRQn 88 | #define G_ENC_L_Pin GPIO_PIN_1 89 | #define G_ENC_L_GPIO_Port GPIOB 90 | #define G_ENC_L_EXTI_IRQn EXTI1_IRQn 91 | #define FLASH_SCK_Pin GPIO_PIN_10 92 | #define FLASH_SCK_GPIO_Port GPIOB 93 | #define SD_CS_Pin GPIO_PIN_12 94 | #define SD_CS_GPIO_Port GPIOB 95 | #define FLASH_CS_Pin GPIO_PIN_13 96 | #define FLASH_CS_GPIO_Port GPIOB 97 | #define FLASH_MISO_Pin GPIO_PIN_14 98 | #define FLASH_MISO_GPIO_Port GPIOB 99 | #define FLASH_MOSI_Pin GPIO_PIN_15 100 | #define FLASH_MOSI_GPIO_Port GPIOB 101 | #define I_ENC_R_Pin GPIO_PIN_8 102 | #define I_ENC_R_GPIO_Port GPIOA 103 | #define I_ENC_B_Pin GPIO_PIN_9 104 | #define I_ENC_B_GPIO_Port GPIOA 105 | #define REED_SW_Pin GPIO_PIN_10 106 | #define REED_SW_GPIO_Port GPIOA 107 | #define GUN_POWER_Pin GPIO_PIN_11 108 | #define GUN_POWER_GPIO_Port GPIOA 109 | #define AC_ZERO_Pin GPIO_PIN_12 110 | #define AC_ZERO_GPIO_Port GPIOA 111 | #define TFT_RESET_Pin GPIO_PIN_15 112 | #define TFT_RESET_GPIO_Port GPIOA 113 | #define TFT_SCK_Pin GPIO_PIN_3 114 | #define TFT_SCK_GPIO_Port GPIOB 115 | #define TFT_BRIGHT_Pin GPIO_PIN_4 116 | #define TFT_BRIGHT_GPIO_Port GPIOB 117 | #define TFT_CS_Pin GPIO_PIN_5 118 | #define TFT_CS_GPIO_Port GPIOB 119 | #define TILT_SW_Pin GPIO_PIN_6 120 | #define TILT_SW_GPIO_Port GPIOB 121 | #define TFT_DC_Pin GPIO_PIN_7 122 | #define TFT_DC_GPIO_Port GPIOB 123 | #define BUZZER_Pin GPIO_PIN_9 124 | #define BUZZER_GPIO_Port GPIOB 125 | 126 | /* USER CODE BEGIN Private defines */ 127 | #define FW_VERSION ("1.15") 128 | /* USER CODE END Private defines */ 129 | 130 | #ifdef __cplusplus 131 | } 132 | #endif 133 | 134 | #endif /* __MAIN_H */ 135 | -------------------------------------------------------------------------------- /SRC/Core/Inc/nls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * nls.h 3 | * 4 | * 2022 Nov 6 5 | * Removed 'change tip' menu item from parameters menu 6 | * 2024 OCT 06, v.1.15 7 | * Added "fast gun chill" setup menu item 8 | * Added "display type" setup menu item 9 | * Added "IPS" and "TFT" messages 10 | * 11 | */ 12 | 13 | #ifndef MSG_NLS_H_ 14 | #define MSG_NLS_H_ 15 | 16 | #include 17 | 18 | typedef enum e_msg { MSG_MENU_MAIN, MSG_MENU_SETUP = 12, MSG_MENU_BOOST = 12+18, MSG_MENU_CALIB = 12+18+4, MSG_MENU_GUN = 12+18+4+5, 19 | MSG_ON = 12+18+4+5+6, MSG_OFF, MSG_FAN, MSG_PWR, MSG_REF_POINT, MSG_REED, MSG_TILT, MSG_DEG, MSG_MINUTES, MSG_SECONDS, 20 | MSG_CW, MSG_CCW, MSG_SET, MSG_ERROR, MSG_TUNE_PID, MSG_SELECT_TIP, 21 | MSG_EEPROM_READ, MSG_EEPROM_WRITE, MSG_EEPROM_DIRECTORY, MSG_FORMAT_EEPROM, MSG_FORMAT_FAILED, 22 | MSG_SAVE_ERROR, MSG_HOT_AIR_GUN, MSG_SAVE_Q, MSG_YES, MSG_NO, MSG_DELETE_FILE, MSG_FLASH_DEBUG, 23 | MSG_SD_MOUNT, MSG_SD_NO_CFG, MSG_SD_NO_LANG, MSG_SD_MEMORY, MSG_SD_INCONSISTENT, MSG_DSPL_IPS, MSG_DSPL_TFT, 24 | MSG_LAST, 25 | MSG_ACTIVATE_TIPS = MSG_MENU_MAIN + 5, 26 | MSG_TUNE_IRON = MSG_MENU_MAIN + 6, 27 | MSG_ABOUT = MSG_MENU_MAIN + 10, 28 | MSG_TUNE_GUN = MSG_MENU_GUN + 2, 29 | MSG_AUTO = MSG_MENU_CALIB + 1, 30 | MSG_MANUAL = MSG_MENU_CALIB + 2 31 | } t_msg_id; 32 | 33 | typedef struct s_msg_nls { 34 | const char *msg; 35 | std::string msg_nls; 36 | } t_msg; 37 | 38 | class NLS_MSG { 39 | public: 40 | NLS_MSG() { } 41 | void activate(bool use_nls) { this->use_nls = use_nls; } 42 | const char* msg(t_msg_id id); 43 | std::string str(t_msg_id id); 44 | uint8_t menuSize(t_msg_id id); 45 | bool set(std::string& parameter, std::string& value, std::string& parent); 46 | protected: 47 | bool use_nls = false; 48 | t_msg message[MSG_LAST] = { 49 | // MAIN MENU 50 | {"Main Menu", std::string()}, // Title is the first element of each menu 51 | {"parameters", std::string()}, 52 | {"boost setup", std::string()}, 53 | {"change tip", std::string()}, 54 | {"calibrate tip", std::string()}, 55 | {"activate tips", std::string()}, // Change MSG_ACTIVATE_TIPS if new item menu inserted 56 | {"tune iron", std::string()}, // Change MSG_TUNE_IRON if new item menu inserted 57 | {"gun setup", std::string()}, 58 | {"reset config", std::string()}, 59 | {"tune iron PID", std::string()}, 60 | {"about", std::string()}, // Change MSG_ABOUT if new item menu inserted 61 | {"quit", std::string()}, 62 | // SETUP MENU 63 | {"Parameters", std::string()}, // Title 64 | {"units", std::string()}, 65 | {"buzzer", std::string()}, 66 | {"iron encoder", std::string()}, 67 | {"gun encoder", std::string()}, 68 | {"fast gun chill", std::string()}, 69 | {"switch type", std::string()}, 70 | {"temp. step", std::string()}, 71 | {"auto start", std::string()}, 72 | {"auto off", std::string()}, // Change in-place menu item 73 | {"standby temp", std::string()}, // Change in-place menu item 74 | {"standby time", std::string()}, // Change in-place menu item 75 | {"brightness", std::string()}, // Change in-place menu item 76 | {"rotation", std::string()}, // Change in-place menu item 77 | {"language", std::string()}, // Change in-place menu item 78 | {"display type", std::string()}, 79 | {"save", std::string()}, 80 | {"cancel", std::string()}, 81 | // BOOST MENU 82 | {"Boost setup", std::string()}, // Title 83 | {"temperature", std::string()}, 84 | {"duration", std::string()}, 85 | {"back to menu", std::string()}, 86 | // IRON TIP CALIBRATION MENU 87 | {"Calibrate", std::string()}, // Title 88 | {"automatic", std::string()}, // Change MSG_AUTO if new item menu inserted 89 | {"manual", std::string()}, // Change MSG_MANUAL if new item menu inserted 90 | {"clear", std::string()}, 91 | {"quit", std::string()}, 92 | // GUN MENU 93 | {"Hot Air Gun", std::string()}, // Title 94 | {"calibrate", std::string()}, 95 | {"tune gun", std::string()}, // Change MSG_TUNE_GUN if new item menu inserted 96 | {"tune gun PID", std::string()}, 97 | {"clear", std::string()}, 98 | {"exit", std::string()}, 99 | // SINGLE MESSAGE STRINGS 100 | {"ON", std::string()}, 101 | {"OFF", std::string()}, 102 | {"Fan:", std::string()}, 103 | {"pwr:", std::string()}, 104 | {"Ref. #", std::string()}, 105 | {"REED", std::string()}, 106 | {"TILT", std::string()}, 107 | {"deg.", std::string()}, 108 | {"min", std::string()}, 109 | {"sec", std::string()}, 110 | {"cw", std::string()}, 111 | {"ccw", std::string()}, 112 | {"Set:", std::string()}, 113 | {"ERROR", std::string()}, 114 | {"Tune PID", std::string()}, 115 | {"Select tip", std::string()}, 116 | {"FLASH read error", std::string()}, 117 | {"FLASH write error", std::string()}, 118 | {"No directory", std::string()}, 119 | {"format FLASH?", std::string()}, 120 | {"Failed to format FLASH", std::string()}, 121 | {"saving configuration", std::string()}, 122 | {"Hot Gun", std::string()}, 123 | {"Save?", std::string()}, 124 | {"Yes", std::string()}, 125 | {"No", std::string()}, 126 | {"Delete file?", std::string()}, 127 | {"FLASH debug", std::string()}, 128 | {"Failed mount SD", std::string()}, 129 | {"NO config file", std::string()}, 130 | {"No lang. specified", std::string()}, 131 | {"No memory", std::string()}, 132 | {"Inconsistent lang", std::string()}, 133 | {"IPS", std::string()}, 134 | {"TFT", std::string()} 135 | }; 136 | const t_msg_id menu[5] = { MSG_MENU_MAIN, MSG_MENU_SETUP, MSG_MENU_BOOST, MSG_MENU_CALIB, MSG_MENU_GUN }; 137 | }; 138 | 139 | #endif 140 | -------------------------------------------------------------------------------- /SRC/Core/Inc/nls_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * nls_cfg.h 3 | * 4 | */ 5 | 6 | #ifndef NLS_CFG_H_ 7 | #define NLS_CFG_H_ 8 | 9 | #include 10 | #include "jsoncfg.h" 11 | #include "nls.h" 12 | #include "ff.h" 13 | #include "vars.h" 14 | 15 | typedef std::vector tLangList; 16 | 17 | class NLS { 18 | public: 19 | NLS(void) { } 20 | void init(NLS_MSG *pMsg); 21 | uint8_t numLanguages(void) { return lang_cfg.listSize(); } 22 | uint8_t languageIndex(void) { return language_index; } 23 | uint8_t* font(void) { return font_data; } 24 | void loadLanguageData(const char *language); 25 | void loadLanguageData(uint8_t index); 26 | void defaultNLS(); 27 | std::string languageName(uint8_t index); 28 | private: 29 | uint8_t index(const char *lang); 30 | std::string messageFile(uint8_t index); 31 | std::string fontFile(uint8_t index); 32 | bool loadFont(uint8_t indx); 33 | bool loadMessages(uint8_t indx); 34 | FATFS flashfs; 35 | FIL cfg_f; 36 | JSON_LANG_CFG lang_cfg; 37 | JSON_MESSAGES msg_parser; 38 | uint8_t language_index = 0; // Current language index 39 | uint8_t *font_data = 0; // Loaded font data, memory allocated by malloc() 40 | const TCHAR* fn_cfg = nsl_cfg; // vars.h 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /SRC/Core/Inc/pid.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pid.h 3 | * 4 | * Author: Alex 5 | */ 6 | 7 | #ifndef _PID_H 8 | #define _PID_H 9 | 10 | #include "main.h" 11 | #include "stat.h" 12 | #include "vars.h" 13 | 14 | class PIDparam { 15 | public: 16 | PIDparam(int32_t Kp = 0, int32_t Ki = 0, int32_t Kd = 0); 17 | PIDparam(const PIDparam &p); 18 | int32_t Kp = 0; 19 | int32_t Ki = 0; 20 | int32_t Kd = 0; 21 | }; 22 | 23 | /* The PID algorithm 24 | * Un = Kp*(Xs - Xn) + Ki*summ{j=0; j<=n}(Xs - Xj) + Kd(Xn - Xn-1), 25 | * Where Xs - is the setup temperature, Xn - the temperature on n-iteration step 26 | * In this program the interactive formula is used: 27 | * Un = Un-1 + Kp*(Xn-1 - Xn) + Ki*(Xs - Xn) + Kd*(Xn-2 + Xn - 2*Xn-1) 28 | * With the first step: 29 | * U0 = Kp*(Xs - X0) + Ki*(Xs - X0); Xn-1 = Xn; 30 | * 31 | * The default values of PID coefficients can be found in config.cpp 32 | */ 33 | class PID { 34 | public: 35 | PID(void) { } 36 | void load(const PIDparam &p); 37 | PIDparam dump(void) { return PIDparam(Kp, Ki, Kd); } 38 | void init(uint16_t ms, uint8_t denominator_p = 11); 39 | void resetPID(uint16_t t = 0); // reset PID algorithm history parameters 40 | int32_t reqPower(int16_t temp_set, int16_t temp_curr); 41 | int32_t changePID(uint8_t p, int32_t k); // set or get (if parameter < 0) PID parameter 42 | void newPIDparams(uint16_t delta_power, uint32_t diff, uint32_t period); 43 | void pidStable(void) { power = stable; } 44 | private: 45 | void debugPID(int t_set, int t_curr, long kp, long ki, long kd, long delta_p); 46 | uint32_t T = 20; // Check IRON or Hot Air Gun period, ms (to calculate auto PID parameters) 47 | int16_t temp_h0 = 0; // previously measured temperatures 48 | int16_t temp_h1 = 0; 49 | int32_t power = 0; // The power iterative multiplied by denominator 50 | int32_t Kp = 10; // The PID coefficients multiplied by denominator. 51 | int32_t Ki = 10; 52 | int32_t Kd = 0; 53 | int16_t denominator_p = 11; // The common coefficient denominator power of 2 (11 means 2048) 54 | int32_t stable = 20000; // The power value when the iron reaches the preset temperature 55 | }; 56 | 57 | class PIDTUNE { 58 | public: 59 | PIDTUNE(void) : period(auto_pid_hist_length), temp_max(auto_pid_hist_length), temp_min(auto_pid_hist_length) { } 60 | void start(uint16_t base_pwr, uint16_t delta_power, uint16_t base_temp, uint16_t delta_temp); 61 | uint16_t run(uint32_t t); 62 | uint16_t autoTuneLoops(void) { return loops; } 63 | uint32_t autoTunePeriod(void) { return period.read(); } 64 | uint16_t tempMin(void) { return temp_min.read(); } 65 | uint16_t tempMax(void) { return temp_max.read(); } 66 | bool periodStable(void); 67 | private: 68 | HIST period; // Average value of relay method oscillations period 69 | HIST temp_max; // Average value of maximum temperature 70 | HIST temp_min; // Average value of minimum temperature 71 | volatile uint16_t base_power = 0; // Base power value 72 | volatile uint16_t delta_power = 0; // PLUS delta power applied 73 | volatile uint16_t base_temp = 0; // Base temperature value 74 | volatile uint16_t delta_temp = 0; // The temperature limit (base_temp - delta_temp <= t <= base_temp + delta_temp) 75 | volatile bool app_delta_power = false; // Do apply delta power 76 | volatile uint32_t pwr_change = 0; // The time (ms) when tune extra power changed 77 | volatile bool check_max = false; 78 | volatile bool check_min = false; 79 | volatile uint16_t t_max = 0; 80 | volatile uint16_t t_min = 0; 81 | volatile uint16_t loops = 0; // Whole tune oscillation loop count 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /SRC/Core/Inc/sdload.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sdload.h 3 | * 4 | */ 5 | 6 | #ifndef SDLOAD_H_ 7 | #define SDLOAD_H_ 8 | 9 | #include "jsoncfg.h" 10 | #include "ff.h" 11 | #include "vars.h" 12 | #include "sdspi.h" 13 | 14 | extern SDCARD sd; 15 | 16 | class SDLOAD { 17 | public: 18 | SDLOAD(void) { } 19 | t_msg_id load(void); // Returns number of languages loaded 20 | uint8_t sdStatus(void) { return sd.init_status; } // SD status initialized by SD_Init() function (see sdspi.c) 21 | private: 22 | t_msg_id init(void); 23 | uint8_t copyLanguageData(void); 24 | void umountAll(void); 25 | bool allocateCopyBuffer(void); 26 | bool isLanguageDataConsistent(t_lang_cfg &lang_data); 27 | bool haveToUpdate(std::string &name); 28 | bool copyFile(std::string &name); 29 | uint8_t *buffer = 0; // The buffer to copy the file, allocated later 30 | uint16_t buffer_size = 0; // The allocated buffer size 31 | FATFS sdfs, flashfs; 32 | FIL cfg_f; 33 | JSON_LANG_CFG lang_cfg; 34 | t_lang_list *lang_list = 0; 35 | const TCHAR* fn_cfg = nsl_cfg; // vars.h 36 | const uint16_t b_sizes[3] = { 4096, 1024, 512}; // Possible copy buffer sizes 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /SRC/Core/Inc/stat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * stat.h 3 | * 4 | * Math statistic class 5 | * 6 | * 2022 Nov 6 7 | * added parameter to reset() method to setup initial state. Used to initialize the ambient temperature 8 | */ 9 | 10 | #ifndef STAT_H_ 11 | #define STAT_H_ 12 | 13 | #include "main.h" 14 | 15 | // Exponential average 16 | class EMP_AVERAGE { 17 | public: 18 | EMP_AVERAGE(uint8_t h_length = 8) { emp_k = h_length; emp_data = 0; } 19 | void length(uint8_t h_length) { emp_k = h_length; emp_data = 0; } 20 | void reset(int32_t value = 0) { emp_data = value * emp_k; } 21 | int32_t average(int32_t value); 22 | void update(int32_t value); 23 | int32_t read(void); 24 | private: 25 | volatile uint8_t emp_k = 8; 26 | volatile uint32_t emp_data = 0; 27 | }; 28 | 29 | #define H_LENGTH (16) 30 | // Flat history data with round buffer 31 | class HIST { 32 | public: 33 | HIST(uint8_t h_length = H_LENGTH) { len = index = 0; max_len = h_length; } 34 | void length(uint8_t h_length) { len = index = 0; if (h_length > H_LENGTH) h_length = H_LENGTH; max_len = h_length; } 35 | void reset() { len = index = 0; } 36 | int32_t read(void); 37 | int32_t average(int32_t value); 38 | void update(int32_t value); 39 | uint32_t dispersion(void); // the math dispersion of the data 40 | private: 41 | volatile int32_t queue[H_LENGTH]; 42 | volatile uint8_t len; // The number of elements in the queue 43 | volatile uint8_t max_len; // Maximum length of the queue, not greater than H_LENGTH 44 | volatile uint8_t index; // The current element position, use ring buffer 45 | }; 46 | 47 | class SWITCH : public EMP_AVERAGE { 48 | public: 49 | SWITCH(uint8_t len=8) : EMP_AVERAGE(len) { } 50 | void init(uint8_t h_len, uint16_t on = 500, uint16_t off = 500); 51 | bool status(void) { return mode; } 52 | bool changed(void); 53 | void update(uint16_t value); 54 | private: 55 | bool sw_changed = false; // The status has changed flag 56 | bool mode = false; // The switch mode on (true)/off 57 | int16_t on_val = 400; // Turn on value 58 | int16_t off_val = 500; // Turn off value 59 | }; 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /SRC/Core/Inc/stm32f4xx_it.h: -------------------------------------------------------------------------------- 1 | /* USER CODE BEGIN Header */ 2 | /** 3 | ****************************************************************************** 4 | * @file stm32f4xx_it.h 5 | * @brief This file contains the headers of the interrupt handlers. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | * Copyright (c) 2022 STMicroelectronics. 10 | * All rights reserved. 11 | * 12 | * This software is licensed under terms that can be found in the LICENSE file 13 | * in the root directory of this software component. 14 | * If no LICENSE file comes with this software, it is provided AS-IS. 15 | * 16 | ****************************************************************************** 17 | */ 18 | /* USER CODE END Header */ 19 | 20 | /* Define to prevent recursive inclusion -------------------------------------*/ 21 | #ifndef __STM32F4xx_IT_H 22 | #define __STM32F4xx_IT_H 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* Private includes ----------------------------------------------------------*/ 29 | /* USER CODE BEGIN Includes */ 30 | 31 | /* USER CODE END Includes */ 32 | 33 | /* Exported types ------------------------------------------------------------*/ 34 | /* USER CODE BEGIN ET */ 35 | 36 | /* USER CODE END ET */ 37 | 38 | /* Exported constants --------------------------------------------------------*/ 39 | /* USER CODE BEGIN EC */ 40 | 41 | /* USER CODE END EC */ 42 | 43 | /* Exported macro ------------------------------------------------------------*/ 44 | /* USER CODE BEGIN EM */ 45 | 46 | /* USER CODE END EM */ 47 | 48 | /* Exported functions prototypes ---------------------------------------------*/ 49 | void NMI_Handler(void); 50 | void HardFault_Handler(void); 51 | void MemManage_Handler(void); 52 | void BusFault_Handler(void); 53 | void UsageFault_Handler(void); 54 | void SVC_Handler(void); 55 | void DebugMon_Handler(void); 56 | void PendSV_Handler(void); 57 | void SysTick_Handler(void); 58 | void TIM1_CC_IRQHandler(void); 59 | void TIM2_IRQHandler(void); 60 | void DMA2_Stream0_IRQHandler(void); 61 | void DMA2_Stream3_IRQHandler(void); 62 | /* USER CODE BEGIN EFP */ 63 | 64 | /* USER CODE END EFP */ 65 | 66 | #ifdef __cplusplus 67 | } 68 | #endif 69 | 70 | #endif /* __STM32F4xx_IT_H */ 71 | -------------------------------------------------------------------------------- /SRC/Core/Inc/tools.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/SRC/Core/Inc/tools.h -------------------------------------------------------------------------------- /SRC/Core/Inc/unit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * unit.h 3 | * 4 | */ 5 | 6 | #ifndef UNIT_H_ 7 | #define UNIT_H_ 8 | #include "pid.h" 9 | 10 | // Common interface methods for IRON and Hot Air Gun 11 | class UNIT : public PID, public PIDTUNE { 12 | public: 13 | UNIT(void) { } 14 | virtual ~UNIT(void) { } 15 | void init(uint8_t c_len, uint16_t c_min, uint16_t c_max, uint8_t s_len, uint16_t s_min, uint16_t s_max); 16 | bool isConnected(void) { return current.status(); } 17 | uint16_t unitCurrent(void) { return current.read(); } // Used in debug mode only 18 | void updateCurrent(uint16_t value) { current.update(value); } 19 | uint16_t reedInternal(void) { return sw.read(); } 20 | void updateReedStatus(bool on) { sw.update(on?100:0); } // Update Reed switch status 21 | bool isReedSwitch(bool reed); // REED switch: TRUE if switch is shorten; else: TRUE if status has been changed 22 | virtual void switchPower(bool On) = 0; 23 | virtual uint16_t presetTemp(void) = 0; 24 | virtual void setTemp(uint16_t t) = 0; 25 | virtual uint16_t averageTemp(void) = 0; 26 | virtual uint8_t avgPowerPcnt(void) = 0; 27 | virtual uint16_t avgPower(void) = 0; 28 | virtual uint16_t tmpDispersion(void) = 0; 29 | virtual uint16_t pwrDispersion(void) = 0; 30 | virtual void fixPower(uint16_t Power) = 0; 31 | virtual uint16_t getMaxFixedPower(void) = 0; 32 | virtual void autoTunePID(uint16_t base_pwr, uint16_t delta_power, uint16_t base_temp, uint16_t temp) = 0; 33 | private: 34 | SWITCH current; // The current through the unit 35 | SWITCH sw; // Tilt switch of T12, Reed switch of Hot Air Gun or Standby switch of JBC 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /SRC/Core/Inc/vars.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/SRC/Core/Inc/vars.h -------------------------------------------------------------------------------- /SRC/Core/Src/buzzer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * buzzer.cpp 3 | * 4 | */ 5 | 6 | #include "buzzer.h" 7 | #include "main.h" 8 | 9 | BUZZER::BUZZER(void) { 10 | TIM4->CCR4 = 0; 11 | } 12 | 13 | void BUZZER::playTone(uint16_t period_mks, uint16_t duration_ms) { 14 | TIM4->ARR = period_mks-1; 15 | TIM4->CCR4 = period_mks >> 1; 16 | HAL_Delay(duration_ms); 17 | TIM4->CCR4 = 0; 18 | } 19 | 20 | void BUZZER::shortBeep(void) { 21 | if (!enabled) return; 22 | playTone(284, 160); 23 | } 24 | 25 | void BUZZER::doubleBeep(void) { 26 | if (!enabled) return; 27 | playTone(284, 160); 28 | HAL_Delay(100); 29 | playTone(284, 160); 30 | } 31 | 32 | void BUZZER::lowBeep(void) { 33 | if (!enabled) return; 34 | playTone(2840, 160); 35 | } 36 | 37 | void BUZZER::failedBeep(void) { 38 | if (!enabled) return; 39 | playTone(284, 160); 40 | HAL_Delay(50); 41 | playTone(2840, 60); 42 | HAL_Delay(50); 43 | playTone(1420, 160); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /SRC/Core/Src/encoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * encoder.cpp 3 | * 4 | * Created on: 15 aug. 2019. 5 | * Author: Alex 6 | * 7 | * 2024 OCT 09, v.1.15 8 | * Added RENC::intNuber() method that used in debug mode 9 | */ 10 | 11 | #include "encoder.h" 12 | 13 | RENC::RENC(GPIO_TypeDef* aPORT, uint16_t aPIN, GPIO_TypeDef* bPORT, uint16_t bPIN) { 14 | rpt = 0; 15 | m_port = aPORT; s_port = bPORT; m_pin = aPIN; s_pin = bPIN; 16 | pos = 0; 17 | min_pos = -32767; max_pos = 32766; increment = 1; 18 | changed = 0; 19 | s_up = false; 20 | is_looped = false; 21 | increment = fast_increment = 1; 22 | } 23 | 24 | void RENC::addButton(GPIO_TypeDef* ButtonPORT, uint16_t ButtonPIN) { 25 | bpt = 0; 26 | b_port = ButtonPORT; 27 | b_pin = ButtonPIN; 28 | over_press = def_over_press; 29 | avg.length(avg_length); 30 | } 31 | 32 | void RENC::reset(int16_t initPos, int16_t low, int16_t upp, uint8_t inc, uint8_t fast_inc, bool looped) { 33 | min_pos = low; max_pos = upp; 34 | if (!write(initPos)) initPos = min_pos; 35 | increment = fast_increment = inc; 36 | if (fast_inc > increment) fast_increment = fast_inc; 37 | is_looped = looped; 38 | } 39 | 40 | /* 41 | * The Encoder button current status 42 | * 0 - not pressed 43 | * 1 - short press 44 | * 2 - long press 45 | */ 46 | uint8_t RENC::buttonStatus(void) { 47 | if (HAL_GetTick() >= b_check) { // It is time to check the button status 48 | b_check = HAL_GetTick() + b_check_period; 49 | uint8_t s = 0; 50 | if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(b_port, b_pin)) // if port state is low, the button pressed 51 | s = trigger_on << 1; 52 | if (b_on) { 53 | if (avg.average(s) < trigger_off) 54 | b_on = false; 55 | } else { 56 | if (avg.average(s) > trigger_on) 57 | b_on = true; 58 | } 59 | 60 | if (b_on) { // Button status is 'pressed' 61 | uint32_t n = HAL_GetTick() - bpt; 62 | if ((bpt == 0) || (n > over_press)) { 63 | bpt = HAL_GetTick(); 64 | } else if (n > long_press) { // Long press 65 | if (i_b_rel) { 66 | return 0; 67 | } else{ 68 | i_b_rel = true; 69 | return 2; 70 | } 71 | } 72 | } else { // Button status is 'not pressed' 73 | if (bpt == 0 || i_b_rel) { 74 | bpt = 0; 75 | i_b_rel = false; 76 | return 0; 77 | } 78 | uint32_t e = HAL_GetTick() - bpt; 79 | bpt = 0; // Ready for next press 80 | if (e < over_press) { // Long press already managed 81 | return 1; 82 | } 83 | } 84 | } 85 | return 0; 86 | } 87 | 88 | bool RENC::write(int16_t initPos) { 89 | if ((initPos >= min_pos) && (initPos <= max_pos)) { 90 | pos = initPos; 91 | return true; 92 | } 93 | return false; 94 | } 95 | 96 | void RENC::encoderIntr(void) { // Interrupt function, called when the channel A of encoder changed 97 | bool mUp = (HAL_GPIO_ReadPin(m_port, m_pin) == GPIO_PIN_SET); 98 | uint32_t now_t = HAL_GetTick(); 99 | if (!mUp) { // The main channel has been "pressed" 100 | if ((rpt == 0) || (now_t - rpt > over_press)) { 101 | rpt = now_t; 102 | s_up = HAL_GPIO_ReadPin(s_port, s_pin) == GPIO_PIN_SET; 103 | } 104 | } else { 105 | if (rpt > 0) { 106 | if (s_up == (HAL_GPIO_ReadPin(s_port, s_pin) == GPIO_PIN_RESET)) { // Secondary channel polarity has been changed 107 | uint8_t inc = increment; 108 | if ((now_t - rpt) < over_press) { 109 | if ((now_t - changed) < fast_timeout) inc = fast_increment; 110 | changed = now_t; 111 | if (s_up == clockwise) pos -= inc; else pos += inc; 112 | if (pos > max_pos) { 113 | pos = (is_looped)?min_pos:max_pos; 114 | } else if (pos < min_pos) { 115 | pos = (is_looped)?max_pos:min_pos; 116 | } 117 | } 118 | } 119 | rpt = 0; 120 | } 121 | } 122 | ++enc_int; 123 | } 124 | 125 | uint32_t RENC::intNumber(void) { 126 | uint32_t i = enc_int; 127 | enc_int = 0; 128 | return i; 129 | } 130 | -------------------------------------------------------------------------------- /SRC/Core/Src/graph.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * graph.cpp 3 | * 4 | */ 5 | 6 | #include 7 | #include "graph.h" 8 | #include "tools.h" 9 | 10 | bool GRAPH::allocate(uint16_t size) { 11 | data_index = 0; 12 | full_buff = false; 13 | if (this->size > 0 && this->size < size) { 14 | free(h_temp); 15 | free(h_disp); 16 | this->size = 0; 17 | } 18 | if (this->size == 0) { 19 | h_temp = (int16_t *)malloc(size * sizeof(int16_t)); 20 | if (h_temp) { 21 | h_disp = (uint16_t *)malloc(size * sizeof(uint16_t)); 22 | if (!h_disp) { 23 | free(h_temp); 24 | h_temp = 0; 25 | h_disp = 0; 26 | return false; 27 | } 28 | this->size = size; 29 | } 30 | } 31 | return true; 32 | } 33 | 34 | void GRAPH::freeData(void) { 35 | if (size > 0) { 36 | free(h_temp); 37 | free(h_disp); 38 | } 39 | } 40 | 41 | void GRAPH::put(int16_t t, uint16_t d) { 42 | if (size == 0) return; 43 | uint8_t i = data_index; 44 | t = constrain(t, -500, 500); // Limit graph value 45 | d = constrain(d, 0, 999); 46 | 47 | h_temp[i] = t; 48 | h_disp[i] = d; 49 | if (++i >= size) { 50 | i = 0; 51 | full_buff = true; 52 | } 53 | data_index = i; 54 | } 55 | 56 | int16_t GRAPH::temp(uint16_t index) { 57 | if (size == 0) return 0; 58 | uint16_t i = indx(index); 59 | return h_temp[i]; 60 | } 61 | 62 | uint16_t GRAPH::disp(uint16_t index) { 63 | if (size == 0) return 0; 64 | uint16_t i = indx(index); 65 | return h_disp[i]; 66 | } 67 | 68 | uint16_t GRAPH::indx(uint16_t i) { 69 | uint16_t zero = (full_buff)?data_index+1:0; 70 | i += zero; 71 | if (i >= size) i -= size; 72 | return i; 73 | } 74 | -------------------------------------------------------------------------------- /SRC/Core/Src/hw.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * hw.cpp 3 | * 4 | * Created on: 13 June 2022 5 | * Author: Alex 6 | * 7 | * 2022 Nov 6 8 | * added t_amb.reset() to the HW::init() method to initialize the default ambient temperature 9 | * 2023 JAN 01 10 | * Added hardware initialization code (temperatures) into HW::init() method 11 | * 2024 OCT 06, v.1.15 12 | * Modified the HW::init() to implement fast Hot Gun cooling feature 13 | * Modified the HW::init() to implement two display types ili9341 and ili9341v 14 | */ 15 | 16 | #include 17 | #include "hw.h" 18 | 19 | CFG_STATUS HW::init(uint16_t t12_temp, uint16_t gun_temp, uint16_t ambient) { 20 | t_amb.length(ambient_emp_coeff); 21 | t_amb.reset(ambient); // Initialize the ambient temperature 22 | iron.init(t12_temp); 23 | hotgun.init(); 24 | hotgun.updateTemp(gun_temp); 25 | i_enc.addButton(I_ENC_B_GPIO_Port, I_ENC_B_Pin); 26 | g_enc.addButton(G_ENC_B_GPIO_Port, G_ENC_B_Pin); 27 | CFG_STATUS cfg_init = cfg.init(); 28 | if (cfg_init == CFG_OK || cfg_init == CFG_NO_TIP) { // Load NLS configuration data 29 | dspl.init(cfg.isIPS()); 30 | nls.init(&dspl); // Setup pointer to NLS_MSG class instance to setup messages by NLS_MSG::set() method 31 | const char *l = cfg.getLanguage(); // Configured language name (string) 32 | nls.loadLanguageData(l); 33 | uint8_t *font = nls.font(); 34 | dspl.setLetterFont(font); 35 | uint8_t r = cfg.getDsplRotation(); 36 | dspl.rotate((tRotation)r); 37 | } else { 38 | dspl.init(); 39 | dspl.setLetterFont(0); // Set default font, reallocate the bitmap for 3-digits field 40 | dspl.rotate(TFT_ROTATION_90); 41 | } 42 | cfg.umount(); 43 | PIDparam pp = cfg.pidParams(d_t12); // load IRON PID parameters 44 | iron.load(pp); 45 | pp = cfg.pidParams(d_gun); // load Hot Air Gun PID parameters 46 | hotgun.load(pp); 47 | bool fast_cooling = cfg.isFastGunCooling(); 48 | hotgun.setFastGunCooling(fast_cooling); 49 | buzz.activate(cfg.isBuzzerEnabled()); 50 | i_enc.setClockWise(cfg.isIronEncClockWise()); 51 | g_enc.setClockWise(cfg.isGunEncClockWise()); 52 | return cfg_init; 53 | } 54 | 55 | /* 56 | * Return ambient temperature in Celsius 57 | * Caches previous result to skip expensive calculations 58 | */ 59 | int32_t HW::ambientTemp(void) { 60 | static const uint16_t add_resistor = 10000; // The additional resistor value (10koHm) 61 | static const float normal_temp[2]= { 10000, 25 }; // nominal resistance and the nominal temperature 62 | static const uint16_t beta = 3950; // The beta coefficient of the thermistor (usually 3000-4000) 63 | static int32_t average = 0; // Previous value of analog read 64 | static int cached_ambient = 0; // Previous value of the temperature 65 | 66 | if (noAmbientSensor()) return default_ambient; // If IRON handle is not connected, return default ambient temperature 67 | if (abs(t_amb.read() - average) < 20) 68 | return cached_ambient; 69 | 70 | average = t_amb.read(); 71 | 72 | if (average < max_ambient_value) { // prevent division by zero; About -30 degrees 73 | // convert the value to resistance 74 | float resistance = 4095.0 / (float)average - 1.0; 75 | resistance = (float)add_resistor / resistance; 76 | 77 | float steinhart = resistance / normal_temp[0]; // (R/Ro) 78 | steinhart = log(steinhart); // ln(R/Ro) 79 | steinhart /= beta; // 1/B * ln(R/Ro) 80 | steinhart += 1.0 / (normal_temp[1] + 273.15); // + (1/To) 81 | steinhart = 1.0 / steinhart; // Invert 82 | steinhart -= 273.15; // convert to Celsius 83 | cached_ambient = round(steinhart); 84 | } else { 85 | cached_ambient = default_ambient; 86 | } 87 | return cached_ambient; 88 | } 89 | -------------------------------------------------------------------------------- /SRC/Core/Src/iron_tips.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iron_tips.cpp 3 | * 4 | * Created on: 15 aug. 2019. 5 | * Author: Alex 6 | */ 7 | 8 | #include "iron_tips.h" 9 | //#include "eeprom.h" 10 | #include "string.h" 11 | 12 | static char tip_names[][tip_name_sz] = { 13 | {'H', 'O', 'G', 'U', 'N'}, // The Hot Air Gun is just another virtual tip that has its own calibration. It should be on the top of list!!! 14 | {'B', '\0', '\0', '\0', '\0'}, 15 | {'B', '1', '\0', '\0', '\0'}, 16 | {'B', '2', '\0', '\0', '\0'}, 17 | {'B', '3', '\0', '\0', '\0'}, 18 | {'B', '4', '\0', '\0', '\0'}, 19 | {'B', '2', 'Z', '\0', '\0'}, 20 | {'B', 'C', '1', '\0', '\0'}, 21 | {'B', 'C', '1', '.' , '5'}, 22 | {'B', 'C', '2', '\0', '\0'}, 23 | {'B', 'C', '3', '\0', '\0'}, 24 | {'B', 'C', '1', 'Z', '\0'}, 25 | {'B', 'C', '2', 'Z', '\0'}, 26 | {'B', 'C', '4', 'Z', '\0'}, 27 | {'B', 'C', 'F', '1', '\0'}, 28 | {'B', 'C', 'F', '2', '\0'}, 29 | {'B', 'C', 'F', '3', '\0'}, 30 | {'B', 'C', 'F', '4', '\0'}, 31 | {'B', 'C', 'F', '1', 'Z'}, 32 | {'B', 'C', 'F', '2', 'Z'}, 33 | {'B', 'C', 'F', '3', 'Z'}, 34 | {'B', 'C', 'M', '2', '\0'}, 35 | {'B', 'C', 'M', '3', '\0'}, 36 | {'B', 'L', '\0', '\0', '\0'}, 37 | {'B', 'Z', '\0', '\0', '\0'}, 38 | {'C', '1', '\0', '\0', '\0'}, 39 | {'C', '2', '\0', '\0', '\0'}, 40 | {'C', '3', '\0', '\0', '\0'}, 41 | {'C', '4', '\0', '\0', '\0'}, 42 | {'D', '0', '8', '\0', '\0'}, 43 | {'D', '1', '2', '\0', '\0'}, 44 | {'D', '1', '6', '\0', '\0'}, 45 | {'D', '2', '4', '\0', '\0'}, 46 | {'D', '3', '2', '\0', '\0'}, // Tip added 04/02/2022 47 | {'D', '5', '2', '\0', '\0'}, 48 | {'D', '4', '\0', '\0', '\0'}, 49 | {'D', 'L', '1', '2', '\0'}, 50 | {'D', 'L', '3', '2', '\0'}, 51 | {'D', 'L', '5', '2', '\0'}, 52 | {'D', '1', '2', 'Z', '\0'}, 53 | {'D', '2', '4', 'Z', '\0'}, 54 | {'D', '4', 'Z', '\0', '\0'}, 55 | {'I', '\0', '\0', '\0', '\0'}, 56 | {'I', 'L', '\0', '\0', '\0'}, 57 | {'I', 'L', 'S', '\0', '\0'}, 58 | {'J', '0', '2', '\0', '\0'}, 59 | {'J', 'L', '0', '2', '\0'}, 60 | {'J', 'S', '0', '2', '\0'}, 61 | {'K', '\0', '\0', '\0', '\0'}, 62 | {'K', 'F', '\0', '\0', '\0'}, 63 | {'K', 'L', '\0', '\0', '\0'}, 64 | {'K', 'R', '\0', '\0', '\0'}, 65 | {'K', 'F', 'Z', '\0', '\0'}, 66 | {'K', 'R', 'Z', '\0', '\0'}, 67 | {'K', 'U', '\0', '\0', '\0'}, 68 | {'W', 'B', '2', '\0', '\0'}, 69 | {'W', 'D', '0', '8', '\0'}, 70 | {'W', 'D', '1', '2', '\0'}, 71 | {'W', 'D', '1', '6', '\0'}, 72 | {'W', 'D', '5', '2', '\0'}, 73 | {'W', 'I', '\0', '\0', '\0'}, 74 | {'N', '1', '-', '0', '6'}, 75 | {'N', '1', '-', '0', '8'}, 76 | {'N', '1', '-', '1', '0'}, 77 | {'N', '1', '-', '1', '3'}, 78 | {'N', '1', '-', '1', '6'}, 79 | {'N', '1', '-', '2', '0'}, 80 | {'N', '1', '-', '2', '3'}, 81 | {'N', '1', '-', 'L', '1'}, 82 | {'1', '0', '0', '1', '\0'}, 83 | {'1', '0', '0', '2', '\0'}, 84 | {'1', '0', '0', '3', '\0'}, 85 | {'1', '0', '0', '4', '\0'}, 86 | {'1', '0', '0', '5', '\0'}, 87 | {'1', '0', '0', '6', '\0'}, 88 | {'1', '0', '0', '7', '\0'}, 89 | {'1', '0', '0', '8', '\0'}, 90 | {'1', '0', '0', '9', '\0'}, 91 | {'1', '0', '1', '0', '\0'}, 92 | {'1', '2', '0', '1', '\0'}, 93 | {'1', '2', '0', '2', '\0'}, 94 | {'1', '2', '0', '3', '\0'}, 95 | {'1', '2', '0', '4', '\0'}, 96 | {'1', '2', '0', '5', '\0'}, 97 | {'1', '2', '0', '6', '\0'}, 98 | {'1', '2', '0', '7', '\0'}, 99 | {'1', '2', '0', '8', '\0'}, 100 | {'1', '2', '0', '9', '\0'}, 101 | {'1', '4', '0', '1', '\0'}, 102 | {'1', '4', '0', '2', '\0'}, 103 | {'1', '4', '0', '3', '\0'}, 104 | {'1', '4', '0', '4', '\0'}, 105 | {'1', '4', '0', '5', '\0'}, 106 | {'1', '4', '0', '6', '\0'} 107 | }; 108 | 109 | static uint16_t tip_number = sizeof(tip_names) / tip_name_sz; 110 | 111 | uint16_t TIPS::loaded(void) { 112 | return tip_number; 113 | } 114 | 115 | const char* TIPS::name(uint8_t index) { 116 | if (index < tip_number) { 117 | return tip_names[index]; 118 | } 119 | return 0; 120 | } 121 | 122 | int TIPS::index(const char *name) { 123 | for (uint16_t i = 0; i < tip_number; ++i) { 124 | if (strncmp(name, tip_names[i], tip_name_sz) == 0) 125 | return i; 126 | } 127 | return -1; 128 | } 129 | -------------------------------------------------------------------------------- /SRC/Core/Src/jsoncfg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * jsoncfg.cpp 3 | * 4 | */ 5 | 6 | #include "jsoncfg.h" 7 | #include "vars.h" 8 | 9 | //--------------------------------------------------- Configuration file parser ------------------------------- 10 | /* 11 | void FILE_PARSER::startDocument() { 12 | while (!p_key.empty() ) { 13 | p_key.pop(); 14 | } 15 | d_key = d_parent = ""; 16 | } 17 | 18 | void FILE_PARSER::startObject() { 19 | p_key.push(d_parent); 20 | d_parent = d_key; 21 | } 22 | 23 | void FILE_PARSER::endObject() { 24 | d_parent = p_key.top(); 25 | p_key.pop(); 26 | d_key.clear(); 27 | } 28 | 29 | void FILE_PARSER::startArray() { 30 | p_key.push(d_parent); 31 | d_parent = d_key; 32 | d_array = d_key; 33 | } 34 | 35 | void FILE_PARSER::endArray() { 36 | d_parent = p_key.top(); 37 | p_key.pop(); 38 | d_key.clear(); 39 | d_array = d_parent; 40 | } 41 | */ 42 | 43 | void FILE_PARSER::startDocument() { 44 | while (!s_key.empty() ) { 45 | s_key.pop(); 46 | } 47 | d_key.clear(); 48 | } 49 | 50 | void FILE_PARSER::startObject() { 51 | s_key.push(d_key); 52 | } 53 | 54 | void FILE_PARSER::endObject() { 55 | s_key.pop(); 56 | d_key.clear(); 57 | } 58 | 59 | void FILE_PARSER::startArray() { 60 | s_array.push(d_key); 61 | } 62 | 63 | void FILE_PARSER::endArray() { 64 | s_array.pop(); 65 | d_key.clear(); 66 | } 67 | 68 | void FILE_PARSER::readFile(FIL *file) { 69 | JsonStreamingParser parser; 70 | parser.setListener(this); 71 | 72 | bool is_body = false; 73 | while(true) { 74 | UINT br = 0; // Number of bytes actually read from the file 75 | uint8_t c; // Byte to be read 76 | f_read(file, (void *)&c, 1, &br); 77 | if (br == 1) { // Byte read successfully 78 | if (!is_body && (c == '{' || c == '[')) { 79 | is_body = true; 80 | } 81 | if (is_body) { 82 | parser.parse(c); 83 | } 84 | } else { // end of file reached 85 | f_close(file); 86 | return; 87 | } 88 | } 89 | } 90 | 91 | //--------------------------------------------------- "cfg.json" main NLS configuration file parser ----------- 92 | void JSON_LANG_CFG::readConfig(FIL *file) { 93 | while (!lang_list.empty() ) { // First, clear lang_list 94 | lang_list.pop_back(); 95 | } 96 | readFile(file); 97 | } 98 | 99 | /* 100 | * Language configuration file contains the language list in the following format. 101 | * Each entry has name (a string to be displayed in the main menu) 102 | * messages file contains the message configuration data 103 | * font file contains u8g2 font to be loaded to draw the messages 104 | * { 105 | "languages": [ 106 | { "name": "russian", "messages": "ru_lang.json", "font": "ru.font"}, 107 | { "name": "french", "messages": "fr_lang.json", "font": "fr.font"} 108 | ] 109 | } 110 | */ 111 | void JSON_LANG_CFG::value(std::string value) { 112 | std::string array = s_array.top(); 113 | if (array.compare("languages") == 0) { 114 | if (d_key.compare("name") == 0) { // Found new language entry 115 | if (!data.lang.empty() && data.lang.compare(value) != 0) { 116 | lang_list.push_back(data); // Save previous language data to the language list if the language is different 117 | } 118 | data.lang = value; // Initialize next language data structure 119 | data.font_file.clear(); 120 | data.messages_file.clear(); 121 | } else if (d_key.compare("messages") == 0) { 122 | data.messages_file = value; 123 | } else if (d_key.compare("font") == 0) { 124 | data.font_file = value; 125 | } 126 | } 127 | } 128 | 129 | // Commit last language 130 | void JSON_LANG_CFG::endDocument() { 131 | if (!data.lang.empty() && !data.messages_file.empty()) { // Language can use default font. In this case, font entry will be empty 132 | lang_list.push_back(data); 133 | } 134 | } 135 | 136 | // Add default language (English) to the language list 137 | void JSON_LANG_CFG::addEnglish() { 138 | data.lang = std::string(def_language); // "English" 139 | data.font_file.clear(); // Use default font 140 | data.messages_file.clear(); // Use default messages 141 | t_lang_list::const_iterator first = lang_list.begin(); 142 | lang_list.insert(first, data); 143 | } 144 | 145 | //--------------------------------------------------- Messages parser ----------------------------------------- 146 | void JSON_MESSAGES::value(std::string value) { 147 | if (pMsg) { 148 | pMsg->set(d_key, value, s_key.top()); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /SRC/Core/Src/nls.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * nls.cpp 3 | * 4 | */ 5 | 6 | #include "nls.h" 7 | #include "vars.h" 8 | 9 | const char* NLS_MSG::msg(t_msg_id id) { 10 | if (id < MSG_LAST) { 11 | if (use_nls && message[(uint8_t)id].msg_nls.length() > 0) 12 | return message[(uint8_t)id].msg_nls.c_str(); 13 | else 14 | return message[(uint8_t)id].msg; 15 | } 16 | return 0; 17 | } 18 | 19 | std::string NLS_MSG::str(t_msg_id id) { 20 | std::string ret = std::string(); 21 | if (id < MSG_LAST) { 22 | if (use_nls && message[(uint8_t)id].msg_nls.length() > 0) 23 | ret = message[(uint8_t)id].msg_nls; 24 | else 25 | ret = std::string(message[(uint8_t)id].msg); 26 | } 27 | return ret; 28 | } 29 | 30 | // Each menu starts with menu title, so actual menu size is less by 1 31 | uint8_t NLS_MSG::menuSize(t_msg_id id) { 32 | uint8_t ret = 0; 33 | switch (id) { 34 | case MSG_MENU_MAIN: 35 | ret = MSG_MENU_SETUP - MSG_MENU_MAIN -1; 36 | break; 37 | case MSG_MENU_SETUP: 38 | ret = MSG_MENU_BOOST - MSG_MENU_SETUP -1; 39 | break; 40 | case MSG_MENU_BOOST: 41 | ret = MSG_MENU_CALIB - MSG_MENU_BOOST -1; 42 | break; 43 | case MSG_MENU_CALIB: 44 | ret = MSG_MENU_GUN - MSG_MENU_CALIB -1; 45 | break; 46 | case MSG_MENU_GUN: 47 | ret = MSG_ON - MSG_MENU_GUN -1; 48 | break; 49 | default: 50 | break; 51 | } 52 | return ret; 53 | } 54 | 55 | bool NLS_MSG::set(std::string& parameter, std::string& value, std::string& parent) { 56 | uint8_t first = 0; 57 | uint8_t last = MSG_LAST; 58 | if (!parent.empty()) { 59 | if (parent.compare(standalone_msg) == 0) { // standalone_msg defined in vars.h 60 | first = (uint8_t)MSG_ON; 61 | } else { // Perhaps, menu name specified 62 | for (uint8_t m = 0; m < sizeof(menu)/sizeof(t_msg_id); ++m) { 63 | const char *m_name = message[(uint8_t)menu[m]].msg; 64 | if (parent.compare(m_name) == 0) { // Menu has been found, limit search context 65 | first = (uint8_t)menu[m]; 66 | last = first + menuSize(menu[m]) + 1; // The first menu item is menu title 67 | break; 68 | } 69 | } 70 | } 71 | } 72 | for (uint8_t i = first; i < last; ++i) { 73 | if (parameter.compare(message[i].msg) == 0) { // Parameter has been found 74 | message[i].msg_nls = value; 75 | use_nls = true; // At least one message was loaded 76 | return true; 77 | } 78 | } 79 | return false; // Parameter not found 80 | } 81 | -------------------------------------------------------------------------------- /SRC/Core/Src/nls_cfg.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * nls_cfg.cpp 3 | * 4 | */ 5 | 6 | #include 7 | #include "nls_cfg.h" 8 | 9 | void NLS::init(NLS_MSG *pMsg) { 10 | msg_parser.setNLS_MSG(pMsg); // Setup pointer to the NLS_MSG class instance to use NLS_MSG::set() method in the value callback procedure 11 | if (FR_OK == f_mount(&flashfs, "0:/", 1)) { // Try to mount SPI flash 12 | std::string cfg_path = "0:" + std::string(fn_cfg); // fn_cfg defined in vars.h, "cfg.json" 13 | if (FR_OK == f_open(&cfg_f, cfg_path.c_str(), FA_READ)) { 14 | lang_cfg.readConfig(&cfg_f); // readConfig closes the file automatically 15 | } 16 | } 17 | lang_cfg.addEnglish(); // Add default language to the list 18 | language_index = 0; // Current language index (English) 19 | font_data = 0; // No font loaded 20 | } 21 | 22 | void NLS::loadLanguageData(uint8_t index) { 23 | if (index == language_index) // The language is already loaded 24 | return; 25 | std::string msg_file = messageFile(index); 26 | if (msg_file.empty()) { // No message file for this language, load default messages 27 | defaultNLS(); 28 | return; 29 | } 30 | defaultNLS(); // Free font data 31 | if (loadFont(index)) { 32 | if (loadMessages(index)) { // Both font and messages are loaded successfully 33 | language_index = index; 34 | } 35 | } 36 | } 37 | 38 | void NLS::loadLanguageData(const char *language) { 39 | uint8_t indx = index(language); 40 | loadLanguageData(indx); 41 | } 42 | 43 | void NLS::defaultNLS() { 44 | if (font_data) { 45 | free(font_data); 46 | font_data = 0; 47 | language_index = 0; 48 | } 49 | } 50 | 51 | std::string NLS::languageName(uint8_t index) { 52 | uint8_t num_lang = lang_cfg.listSize(); // Number of loaded languages 53 | if (index < num_lang){ 54 | t_lang_list *ll = lang_cfg.getLangList(); 55 | return ll->at(index).lang; 56 | } 57 | return std::string(""); 58 | } 59 | 60 | uint8_t NLS::index(const char *lang) { 61 | uint8_t num_lang = lang_cfg.listSize(); // Number of loaded languages 62 | for (uint8_t i = 0; i < num_lang; ++i) { 63 | std::string l = languageName(i); 64 | if (strncmp(lang, l.c_str(), LANG_LENGTH) == 0) { // lang_length defined in vars.h 65 | return i; 66 | } 67 | } 68 | return 0; 69 | } 70 | 71 | std::string NLS::messageFile(uint8_t index) { 72 | uint8_t num_lang = lang_cfg.listSize(); // Number of loaded languages 73 | if (index < num_lang){ 74 | t_lang_list *ll = lang_cfg.getLangList(); 75 | return ll->at(index).messages_file; 76 | } 77 | return 0; 78 | } 79 | 80 | std::string NLS::fontFile(uint8_t index) { 81 | uint8_t num_lang = lang_cfg.listSize(); // Number of loaded languages 82 | if (index < num_lang){ 83 | t_lang_list *ll = lang_cfg.getLangList(); 84 | return ll->at(index).font_file; 85 | } 86 | return 0; 87 | } 88 | 89 | bool NLS::loadFont(uint8_t indx) { 90 | if (FR_OK != f_mount(&flashfs, "0:/", 1)) // Try to mount SPI flash 91 | return false; 92 | std::string f = fontFile(indx); 93 | if (f.empty()) 94 | return true; 95 | std::string cfg_path = "0:" + f; 96 | FILINFO fno; 97 | if (FR_OK != f_stat(cfg_path.c_str(), &fno)) 98 | return false; 99 | if (fno.fsize == 0 || (fno.fattrib & AM_ARC) == 0) 100 | return false; 101 | if (FR_OK != f_open(&cfg_f, cfg_path.c_str(), FA_READ)) 102 | return false; 103 | font_data = (uint8_t *)malloc(fno.fsize); // Try to allocate memory for the font 104 | if (!font_data) { 105 | f_close(&cfg_f); 106 | return false; 107 | } 108 | UINT br = 0; // Read bytes 109 | f_read(&cfg_f, (void *)font_data, (UINT)fno.fsize, &br); 110 | f_close(&cfg_f); 111 | if (br != fno.fsize) { 112 | free(font_data); 113 | font_data = 0; 114 | return false; 115 | } 116 | return true; 117 | } 118 | 119 | bool NLS::loadMessages(uint8_t indx) { 120 | if (FR_OK != f_mount(&flashfs, "0:/", 1)) // Try to mount SPI flash 121 | return false; 122 | std::string cfg_path = "0:" + messageFile(indx); // Here messageFile is not null for sure 123 | if (FR_OK != f_open(&cfg_f, cfg_path.c_str(), FA_READ)) 124 | return false; 125 | msg_parser.readConfig(&cfg_f); // readConfig closes the file automatically 126 | return true; 127 | } 128 | 129 | -------------------------------------------------------------------------------- /SRC/Core/Src/pid.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * pid.cpp 3 | * 4 | * Author: Alex 5 | */ 6 | 7 | #include "pid.h" 8 | #include "tools.h" 9 | #include 10 | 11 | PIDparam::PIDparam(int32_t Kp, int32_t Ki, int32_t Kd) { 12 | this->Kp = Kp; 13 | this->Ki = Ki; 14 | this->Kd = Kd; 15 | } 16 | 17 | PIDparam::PIDparam(const PIDparam &p) { 18 | Kp = p.Kp; 19 | Ki = p.Ki; 20 | Kd = p.Kd; 21 | } 22 | 23 | void PID::load(const PIDparam &p) { 24 | Kp = p.Kp; 25 | Ki = p.Ki; 26 | Kd = p.Kd; 27 | } 28 | 29 | void PID::init(uint16_t ms, uint8_t denominator_p) { // PID parameters are initialized from EEPROM by call 30 | Kp = 10; 31 | Ki = 10; 32 | Kd = 0; 33 | T = ms; 34 | this->denominator_p = denominator_p; 35 | } 36 | 37 | void PID::resetPID(uint16_t t) { 38 | temp_h0 = t; 39 | temp_h1 = t; 40 | power = 0; 41 | } 42 | 43 | int32_t PID::changePID(uint8_t p, int32_t k) { 44 | switch(p) { 45 | case 1: 46 | if (k >= 0) Kp = k; 47 | return Kp; 48 | case 2: 49 | if (k >= 0) Ki = k; 50 | return Ki; 51 | case 3: 52 | if (k >= 0) Kd = k; 53 | return Kd; 54 | default: 55 | break; 56 | } 57 | return 0; 58 | } 59 | /* 60 | * Ku = 4 * delta_power / (PI * SQRT(alpha^2-epsion^2), where 61 | * diff = alpha^2-epsion^2, 62 | * alpha - amplitude of temperature oscillation 63 | * epsilon - hysteresis (delta_temp) 64 | * 65 | * Pu = period - the oscillation period, ms 66 | * Kp = 0.6*Ku; Ti = 0.5*Pu; Td = 0.125*Pu; 67 | * Ki = Kp*T/Ti; 68 | * Kd = Kp*Td/T; 69 | */ 70 | void PID::newPIDparams(uint16_t delta_power, uint32_t diff, uint32_t period) { 71 | double Ku = 4 * delta_power; 72 | Ku /= M_PI * sqrt(diff); 73 | uint32_t denominator = 1 << denominator_p; 74 | Kp = round(Ku * 0.6 * denominator); // Translate Kp to the numerator of implemented PID 75 | Ki = (Kp * T * 2 + period/2) / period; 76 | Kd = (Kp * period) >> 3; // 1/8 = 0.125 77 | Kd += T/2; 78 | Kd /= T; 79 | /* 80 | * The algorithm gives very big values for Kd 81 | * The big values of Kd gives us the big power dispersion 82 | * That is why it is better to limit the Kd value. 83 | */ 84 | if (Kd > 10000) Kd = Kp/2; 85 | } 86 | 87 | int32_t PID::reqPower(int16_t temp_set, int16_t temp_curr) { 88 | if (temp_h0 == 0) { // Use direct formulae because do not know previous temperature 89 | power = 0; 90 | int32_t i_summ = temp_set - temp_curr; 91 | power = Kp*(temp_set - temp_curr) + Ki * i_summ; 92 | } else { 93 | int32_t kp = Kp * (temp_h1 - temp_curr); 94 | int32_t ki = Ki * (temp_set - temp_curr); 95 | int32_t kd = Kd * (temp_h0 + temp_curr - 2 * temp_h1); 96 | int32_t delta_p = kp + ki + kd; 97 | power += delta_p; // Power is stored multiplied by denominator! 98 | } 99 | temp_h0 = temp_h1; 100 | temp_h1 = temp_curr; 101 | int32_t pwr = power + (1 << (denominator_p-1)); // prepare the power to divide by denominator, round the result 102 | pwr >>= denominator_p; // divide by the denominator 103 | return pwr; 104 | } 105 | 106 | void PIDTUNE::start(uint16_t base_pwr, uint16_t delta_power, uint16_t base_temp, uint16_t delta_temp) { 107 | if (base_pwr && delta_power) { 108 | this->base_power = base_pwr; // The power required to keep the preset temperature 109 | this->delta_power = delta_power; // Apply +- delta power in relay method 110 | this->base_temp = base_temp; 111 | this->delta_temp = delta_temp; 112 | app_delta_power = false; 113 | pwr_change = 0; 114 | loops = 0; 115 | period.reset(); 116 | temp_min.reset(); 117 | temp_max.reset(); 118 | } 119 | } 120 | 121 | uint16_t PIDTUNE::run(uint32_t t) { 122 | if (app_delta_power) { // Applying extra power 123 | if (check_min && (int16_t)t > base_temp) { // Finish looking for minimum temperature 124 | check_min = false; 125 | temp_min.update(t_min); 126 | } 127 | if ((int16_t)t > base_temp + delta_temp) { // Crossed high temperature limit, decrease the power 128 | app_delta_power = false; 129 | if (pwr_change > 0) { 130 | uint32_t n = HAL_GetTick(); 131 | period.update(n-pwr_change); 132 | pwr_change = n; 133 | ++loops; 134 | } else { 135 | pwr_change = HAL_GetTick(); 136 | } 137 | check_min = false; // Be paranoid 138 | check_max = true; 139 | t_max = t; 140 | } 141 | } else { // Returning to preset temperature 142 | if (check_max && (int16_t)t < base_temp) { // Finish looking for maximum temperature 143 | check_max = false; 144 | temp_max.update(t_max); 145 | } 146 | if ((int16_t)t < base_temp - delta_temp) { // Crossed low temperature limit, increase the power 147 | app_delta_power = true; 148 | check_max = false; // Be paranoid 149 | check_min = true; 150 | t_min = t; 151 | } 152 | } 153 | if (check_max && t > t_max) t_max = t; // Update maximum temperature of this cycle 154 | if (check_min && t < t_min) t_min = t; // Update minimum temperature of this cycle 155 | uint16_t p = base_power; 156 | if (app_delta_power) p += delta_power; else p -= delta_power; 157 | return p; 158 | } 159 | 160 | bool PIDTUNE::periodStable(void) { 161 | uint32_t disp = period.dispersion() * 100; 162 | disp /= period.read(); // Relative dispersion, % 163 | return disp < 10; 164 | } 165 | -------------------------------------------------------------------------------- /SRC/Core/Src/sdload.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * sdload.cpp 3 | * 4 | */ 5 | 6 | #include "sdload.h" 7 | #include "jsoncfg.h" 8 | 9 | t_msg_id SDLOAD::load(void) { 10 | t_msg_id e = init(); 11 | if (MSG_LAST != e) 12 | return e; 13 | if (!allocateCopyBuffer()) 14 | return MSG_SD_MEMORY; 15 | uint8_t l = copyLanguageData(); 16 | umountAll(); 17 | if (buffer) { // Deallocate copy buffer memory 18 | free(buffer); 19 | buffer_size = 0; 20 | } 21 | return (l>0)?MSG_LAST:MSG_SD_INCONSISTENT; 22 | } 23 | 24 | t_msg_id SDLOAD::init(void) { 25 | if (FR_OK != f_mount(&sdfs, "1:/", 1)) 26 | return MSG_SD_MOUNT; 27 | std::string cfg_path = "1:" + std::string(fn_cfg); 28 | if (FR_OK != f_open(&cfg_f, cfg_path.c_str(), FA_READ)) { 29 | f_mount(NULL, "1:/", 0); 30 | return MSG_SD_NO_CFG; 31 | } 32 | lang_cfg.readConfig(&cfg_f); 33 | lang_list = lang_cfg.getLangList(); 34 | if (lang_list->empty()) { 35 | f_mount(NULL, "1:/", 0); 36 | return MSG_SD_NO_LANG; 37 | } 38 | 39 | if (FR_OK != f_mount(&flashfs, "0:/", 1)) { 40 | f_mount(NULL, "1:/", 0); 41 | return MSG_EEPROM_WRITE; 42 | } 43 | return MSG_LAST; // Everything OK, No error message! 44 | } 45 | 46 | void SDLOAD::umountAll(void) { 47 | f_mount(NULL, "0:/", 0); 48 | f_mount(NULL, "1:/", 0); 49 | } 50 | 51 | bool SDLOAD::allocateCopyBuffer(void) { 52 | for (uint8_t i = 0; i < 3; ++i) { 53 | buffer = (uint8_t *)malloc(b_sizes[i]); 54 | if (buffer) { // Successfully allocated 55 | buffer_size = b_sizes[i]; 56 | return true; 57 | } 58 | } 59 | return false; 60 | } 61 | 62 | uint8_t SDLOAD::copyLanguageData(void) { 63 | uint8_t l_copied = 0; 64 | while (!lang_list->empty()) { 65 | t_lang_cfg lang = lang_list->back(); 66 | lang_list->pop_back(); 67 | bool lang_ok = isLanguageDataConsistent(lang); // Check the language files exist 68 | if (lang_ok) 69 | lang_ok = copyFile(lang.messages_file); 70 | if (lang_ok) 71 | lang_ok = copyFile(lang.font_file); 72 | if (lang_ok) 73 | ++l_copied; 74 | } 75 | if (l_copied > 0) { 76 | std::string cfg_name = fn_cfg; 77 | if (copyFile(cfg_name)) 78 | return l_copied; 79 | } 80 | return 0; 81 | } 82 | 83 | bool SDLOAD::isLanguageDataConsistent(t_lang_cfg &lang_data) { 84 | std::string file_path = "1:" + lang_data.messages_file; 85 | FILINFO fno; 86 | // Checking message file 87 | if (FR_OK != f_stat(file_path.c_str(), &fno)) 88 | return false; 89 | if (fno.fsize == 0 || (fno.fattrib & AM_ARC) == 0) 90 | return false; 91 | // Checking font file 92 | file_path = "1:" + lang_data.font_file; 93 | if (FR_OK != f_stat(file_path.c_str(), &fno)) 94 | return false; 95 | if (fno.fsize == 0 || (fno.fattrib & AM_ARC) == 0) 96 | return false; 97 | return true; 98 | } 99 | 100 | bool SDLOAD::haveToUpdate(std::string &name) { 101 | FILINFO fno; 102 | std::string file_path = "1:" + name; // Source file path on SD-CARD 103 | if (FR_OK != f_stat(file_path.c_str(), &fno)) // Failed to get info of the new file 104 | return true; 105 | uint32_t source_date = fno.fdate << 16 | fno.ftime; // The source file timestamp 106 | file_path = "0:" + name; // Destination file path on SPI FLASH 107 | if (FR_OK != f_stat(file_path.c_str(), &fno)) // Failed to get info of the file, perhaps, the destination file does not exist 108 | return true; 109 | if (fno.fsize == 0 || (fno.fattrib & AM_ARC) == 0) // Destination file size is zero or is not a n archive file at all 110 | return false; 111 | uint32_t dest_date = fno.fdate << 16 | fno.ftime; // The destination file timestamp 112 | return (dest_date < source_date); // If the destination file timestamp is older than source one 113 | } 114 | 115 | bool SDLOAD::copyFile(std::string &name) { 116 | FIL sf, df; // Source and destination file descriptors 117 | if (!haveToUpdate(name)) return true; // The file already exists on the SPI FLASH and its date is not older than the source file on SD-CARD 118 | if (!buffer || buffer_size == 0) // Here the copy buffer has to be allocated already, but double check it 119 | return false; 120 | std::string s_file_path = "1:" + name; // Source file path on SD-CARD 121 | if (FR_OK != f_open(&sf, s_file_path.c_str(), FA_READ)) // Failed to open source file for reading 122 | return false; 123 | std::string d_file_path = "0:" + name; // Destination file path on SPI FLASH 124 | if (FR_OK != f_open(&df, d_file_path.c_str(), FA_CREATE_ALWAYS | FA_WRITE)) // Failed to create destination file for writing 125 | return false; 126 | bool copied = true; 127 | while (true) { // The file copy loop 128 | UINT br = 0; // Read bytes 129 | f_read(&sf, (void *)buffer, (UINT)buffer_size, &br); 130 | if (br == 0) // End of source file 131 | break; 132 | UINT written = 0; // Written bytes 133 | f_write(&df, (void *)buffer, br, &written); 134 | if (written != br) { 135 | copied = false; 136 | break; 137 | } 138 | } 139 | f_close(&df); 140 | f_close(&sf); 141 | if (!copied) { 142 | f_unlink(d_file_path.c_str()); // Remove destination file in case on any error 143 | } else { // Copy date and time from the source file to the destination file 144 | FILINFO fno; 145 | if (FR_OK == f_stat(s_file_path.c_str(), &fno)) { 146 | f_utime(d_file_path.c_str(), &fno); 147 | } 148 | } 149 | return copied; 150 | } 151 | -------------------------------------------------------------------------------- /SRC/Core/Src/stat.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * stat.cpp 3 | * 4 | */ 5 | 6 | #include "stat.h" 7 | #include "tools.h" 8 | 9 | int32_t EMP_AVERAGE::average(int32_t value) { 10 | uint8_t round_v = emp_k >> 1; 11 | update(value); 12 | return (emp_data + round_v) / emp_k; 13 | } 14 | 15 | void EMP_AVERAGE::update(int32_t value) { 16 | uint8_t round_v = emp_k >> 1; 17 | emp_data += value - (emp_data + round_v) / emp_k; 18 | } 19 | 20 | int32_t EMP_AVERAGE::read(void) { 21 | uint8_t round_v = emp_k >> 1; 22 | return (emp_data + round_v) / emp_k; 23 | } 24 | 25 | int32_t HIST::read(void) { 26 | int32_t sum = 0; 27 | if (len == 0) return 0; 28 | if (len == 1) return queue[0]; 29 | for (uint8_t i = 0; i < len; ++i) sum += queue[i]; 30 | sum += len >> 1; // round the average 31 | sum /= len; 32 | return sum; 33 | } 34 | 35 | int32_t HIST::average(int32_t value) { 36 | update(value); 37 | return read(); 38 | } 39 | 40 | void HIST::update(int32_t value) { 41 | if (len < max_len) { 42 | queue[len++] = value; 43 | } else { 44 | queue[index] = value; 45 | if (++index >= max_len) index = 0; // Use ring buffer 46 | } 47 | } 48 | 49 | uint32_t HIST::dispersion(void) { 50 | if (len < 3) return 1000; 51 | uint32_t sum = 0; 52 | uint32_t avg = read(); 53 | for (uint8_t i = 0; i < len; ++i) { 54 | int32_t q = queue[i]; 55 | q -= avg; 56 | q *= q; 57 | sum += q; 58 | } 59 | sum += len >> 1; 60 | sum /= len; 61 | return sum; 62 | } 63 | 64 | void SWITCH::init(uint8_t h_len, uint16_t off, uint16_t on) { 65 | EMP_AVERAGE::length(h_len); 66 | if (on < off) on = off; 67 | on_val = on; 68 | off_val = off; 69 | mode = false; 70 | } 71 | 72 | 73 | bool SWITCH::changed(void) { 74 | if (sw_changed) { 75 | sw_changed = false; 76 | return true; 77 | } 78 | return false; 79 | } 80 | 81 | void SWITCH::update(uint16_t value) { 82 | uint16_t max_val = on_val + (on_val >> 1); 83 | uint16_t min_val = off_val - (off_val >> 1); 84 | value = constrain(value, min_val, max_val); 85 | uint16_t avg = EMP_AVERAGE::average(value); 86 | if (mode) { 87 | if (avg < off_val) { 88 | sw_changed = true; 89 | mode = false; 90 | } 91 | } else { 92 | if (avg > on_val) { 93 | sw_changed = true; 94 | mode = true; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /SRC/Core/Src/syscalls.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/SRC/Core/Src/syscalls.c -------------------------------------------------------------------------------- /SRC/Core/Src/tools.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/SRC/Core/Src/tools.cpp -------------------------------------------------------------------------------- /SRC/Core/Src/unit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * unit.cpp 3 | * 4 | * Created on: 13 June 2022 5 | * Author: Alex 6 | */ 7 | 8 | #include "unit.h" 9 | 10 | void UNIT::init(uint8_t c_len, uint16_t c_min, uint16_t c_max, uint8_t s_len, uint16_t s_min, uint16_t s_max) { 11 | current.init(c_len, c_min, c_max); 12 | sw.init(s_len, s_min, s_max); 13 | } 14 | 15 | 16 | bool UNIT::isReedSwitch(bool reed) { 17 | if (reed) 18 | return sw.status(); // TRUE if switch is open (IRON in use) 19 | return sw.changed(); // TRUE if tilt status has been changed 20 | } 21 | 22 | -------------------------------------------------------------------------------- /SRC/Core/Src/vars.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/SRC/Core/Src/vars.cpp -------------------------------------------------------------------------------- /SRC/FatFS/README: -------------------------------------------------------------------------------- 1 | This is a copy of the Generic FAT filesystem library available here http://elm-chan.org/fsw/ff/00index_p.html 2 | I have copied the library to make configuration changes for thr specific project. 3 | -------------------------------------------------------------------------------- /SRC/FatFS/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface modlue include file (C)ChaN, 2019 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | /* Status of Disk Functions */ 13 | typedef BYTE DSTATUS; 14 | 15 | /* Results of Disk Functions */ 16 | typedef enum { 17 | RES_OK = 0, /* 0: Successful */ 18 | RES_ERROR, /* 1: R/W Error */ 19 | RES_WRPRT, /* 2: Write Protected */ 20 | RES_NOTRDY, /* 3: Not Ready */ 21 | RES_PARERR /* 4: Invalid Parameter */ 22 | } DRESULT; 23 | 24 | 25 | /*---------------------------------------*/ 26 | /* Prototypes for disk control functions */ 27 | 28 | 29 | DSTATUS disk_initialize (BYTE pdrv); 30 | DSTATUS disk_status (BYTE pdrv); 31 | DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count); 32 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count); 33 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 34 | 35 | 36 | /* Disk Status Bits (DSTATUS) */ 37 | 38 | #define STA_NOINIT 0x01 /* Drive not initialized */ 39 | #define STA_NODISK 0x02 /* No medium in the drive */ 40 | #define STA_PROTECT 0x04 /* Write protected */ 41 | 42 | 43 | /* Command code for disk_ioctrl fucntion */ 44 | 45 | /* Generic command (Used by FatFs) */ 46 | #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ 47 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ 48 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ 49 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ 50 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ 51 | 52 | /* Generic command (Not used by FatFs) */ 53 | #define CTRL_POWER 5 /* Get/Set power status */ 54 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 55 | #define CTRL_EJECT 7 /* Eject media */ 56 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 57 | 58 | /* MMC/SDC specific ioctl command */ 59 | #define MMC_GET_TYPE 10 /* Get card type */ 60 | #define MMC_GET_CSD 11 /* Get CSD */ 61 | #define MMC_GET_CID 12 /* Get CID */ 62 | #define MMC_GET_OCR 13 /* Get OCR */ 63 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 64 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 65 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 66 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 67 | 68 | /* ATA/CF specific ioctl command */ 69 | #define ATA_GET_REV 20 /* Get F/W revision */ 70 | #define ATA_GET_MODEL 21 /* Get model name */ 71 | #define ATA_GET_SN 22 /* Get serial number */ 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /SRC/FatFS/ffsystem.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Sample Code of OS Dependent Functions for FatFs */ 3 | /* (C)ChaN, 2018 */ 4 | /*------------------------------------------------------------------------*/ 5 | 6 | 7 | #include "ff.h" 8 | 9 | 10 | #if FF_USE_LFN == 3 /* Dynamic memory allocation */ 11 | 12 | /*------------------------------------------------------------------------*/ 13 | /* Allocate a memory block */ 14 | /*------------------------------------------------------------------------*/ 15 | 16 | void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ 17 | UINT msize /* Number of bytes to allocate */ 18 | ) 19 | { 20 | return malloc(msize); /* Allocate a new memory block with POSIX API */ 21 | } 22 | 23 | 24 | /*------------------------------------------------------------------------*/ 25 | /* Free a memory block */ 26 | /*------------------------------------------------------------------------*/ 27 | 28 | void ff_memfree ( 29 | void* mblock /* Pointer to the memory block to free (nothing to do if null) */ 30 | ) 31 | { 32 | free(mblock); /* Free the memory block with POSIX API */ 33 | } 34 | 35 | #endif 36 | 37 | 38 | 39 | #if FF_FS_REENTRANT /* Mutal exclusion */ 40 | 41 | /*------------------------------------------------------------------------*/ 42 | /* Create a Synchronization Object */ 43 | /*------------------------------------------------------------------------*/ 44 | /* This function is called in f_mount() function to create a new 45 | / synchronization object for the volume, such as semaphore and mutex. 46 | / When a 0 is returned, the f_mount() function fails with FR_INT_ERR. 47 | */ 48 | 49 | //const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ 50 | 51 | 52 | int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ 53 | BYTE vol, /* Corresponding volume (logical drive number) */ 54 | FF_SYNC_t* sobj /* Pointer to return the created sync object */ 55 | ) 56 | { 57 | /* Win32 */ 58 | *sobj = CreateMutex(NULL, FALSE, NULL); 59 | return (int)(*sobj != INVALID_HANDLE_VALUE); 60 | 61 | /* uITRON */ 62 | // T_CSEM csem = {TA_TPRI,1,1}; 63 | // *sobj = acre_sem(&csem); 64 | // return (int)(*sobj > 0); 65 | 66 | /* uC/OS-II */ 67 | // OS_ERR err; 68 | // *sobj = OSMutexCreate(0, &err); 69 | // return (int)(err == OS_NO_ERR); 70 | 71 | /* FreeRTOS */ 72 | // *sobj = xSemaphoreCreateMutex(); 73 | // return (int)(*sobj != NULL); 74 | 75 | /* CMSIS-RTOS */ 76 | // *sobj = osMutexCreate(&Mutex[vol]); 77 | // return (int)(*sobj != NULL); 78 | } 79 | 80 | 81 | /*------------------------------------------------------------------------*/ 82 | /* Delete a Synchronization Object */ 83 | /*------------------------------------------------------------------------*/ 84 | /* This function is called in f_mount() function to delete a synchronization 85 | / object that created with ff_cre_syncobj() function. When a 0 is returned, 86 | / the f_mount() function fails with FR_INT_ERR. 87 | */ 88 | 89 | int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ 90 | FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ 91 | ) 92 | { 93 | /* Win32 */ 94 | return (int)CloseHandle(sobj); 95 | 96 | /* uITRON */ 97 | // return (int)(del_sem(sobj) == E_OK); 98 | 99 | /* uC/OS-II */ 100 | // OS_ERR err; 101 | // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); 102 | // return (int)(err == OS_NO_ERR); 103 | 104 | /* FreeRTOS */ 105 | // vSemaphoreDelete(sobj); 106 | // return 1; 107 | 108 | /* CMSIS-RTOS */ 109 | // return (int)(osMutexDelete(sobj) == osOK); 110 | } 111 | 112 | 113 | /*------------------------------------------------------------------------*/ 114 | /* Request Grant to Access the Volume */ 115 | /*------------------------------------------------------------------------*/ 116 | /* This function is called on entering file functions to lock the volume. 117 | / When a 0 is returned, the file function fails with FR_TIMEOUT. 118 | */ 119 | 120 | int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ 121 | FF_SYNC_t sobj /* Sync object to wait */ 122 | ) 123 | { 124 | /* Win32 */ 125 | return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); 126 | 127 | /* uITRON */ 128 | // return (int)(wai_sem(sobj) == E_OK); 129 | 130 | /* uC/OS-II */ 131 | // OS_ERR err; 132 | // OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); 133 | // return (int)(err == OS_NO_ERR); 134 | 135 | /* FreeRTOS */ 136 | // return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); 137 | 138 | /* CMSIS-RTOS */ 139 | // return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); 140 | } 141 | 142 | 143 | /*------------------------------------------------------------------------*/ 144 | /* Release Grant to Access the Volume */ 145 | /*------------------------------------------------------------------------*/ 146 | /* This function is called on leaving file functions to unlock the volume. 147 | */ 148 | 149 | void ff_rel_grant ( 150 | FF_SYNC_t sobj /* Sync object to be signaled */ 151 | ) 152 | { 153 | /* Win32 */ 154 | ReleaseMutex(sobj); 155 | 156 | /* uITRON */ 157 | // sig_sem(sobj); 158 | 159 | /* uC/OS-II */ 160 | // OSMutexPost(sobj); 161 | 162 | /* FreeRTOS */ 163 | // xSemaphoreGive(sobj); 164 | 165 | /* CMSIS-RTOS */ 166 | // osMutexRelease(sobj); 167 | } 168 | 169 | #endif 170 | 171 | -------------------------------------------------------------------------------- /SRC/JSON_PARSER/JsonParser.h: -------------------------------------------------------------------------------- 1 | /**The MIT License (MIT) 2 | 3 | Copyright (c) 2015 by Daniel Eichhorn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | See more at http://blog.squix.ch and https://github.com/squix78/json-streaming-parser 24 | */ 25 | 26 | #ifndef JSON_PARSER_H_ 27 | #define JSON_PARSER_H_ 28 | 29 | #include 30 | 31 | // Maximum string length in JSON configuration file 32 | #define JSON_BUFFER_MAX_LENGTH (40) 33 | 34 | class JsonListener { 35 | public: 36 | JsonListener(void) { } 37 | virtual ~JsonListener(void) { } 38 | virtual void whitespace(char c) = 0; 39 | virtual void startDocument() = 0; 40 | virtual void key(std::string key) = 0; 41 | virtual void value(std::string value) = 0; 42 | virtual void endArray() = 0; 43 | virtual void endObject() = 0; 44 | virtual void endDocument() = 0; 45 | virtual void startArray() = 0; 46 | virtual void startObject() = 0; 47 | }; 48 | 49 | enum e_state { 50 | STATE_START_DOCUMENT = 0, STATE_DONE, STATE_IN_ARRAY, STATE_IN_OBJECT, STATE_END_KEY, 51 | STATE_AFTER_KEY, STATE_IN_STRING, STATE_START_ESCAPE, STATE_UNICODE, STATE_IN_NUMBER, 52 | STATE_IN_TRUE, STATE_IN_FALSE, STATE_IN_NULL, STATE_AFTER_VALUE, STATE_UNICODE_SURROGATE 53 | }; 54 | 55 | enum e_stack { 56 | STACK_OBJECT = 0, STACK_ARRAY, STACK_KEY, STACK_STRING 57 | }; 58 | 59 | class JsonStreamingParser { 60 | public: 61 | JsonStreamingParser(void); 62 | void parse(char c); 63 | void setListener(JsonListener* listener); 64 | void reset(); 65 | private: 66 | void increaseBufferPointer(); 67 | void endString(); 68 | void endArray(); 69 | void startValue(char c); 70 | void startKey(); 71 | void processEscapeCharacters(char c); 72 | bool isDigit(char c); 73 | bool isHexCharacter(char c); 74 | char convertCodepointToCharacter(int num); 75 | void endUnicodeCharacter(int codepoint); 76 | void startNumber(char c); 77 | void startString(); 78 | void startObject(); 79 | void startArray(); 80 | void endNull(); 81 | void endFalse(); 82 | void endTrue(); 83 | void endDocument(); 84 | int convertDecimalBufferToInt(char myArray[], int length); 85 | void endNumber(); 86 | void endUnicodeSurrogateInterstitial(); 87 | bool doesCharArrayContain(char myArray[], int length, char c); 88 | int getHexArrayAsDecimal(char hexArray[], int length); 89 | void processUnicodeCharacter(char c); 90 | void endObject(); 91 | enum e_state state; 92 | int stack[20]; 93 | int stackPos = 0; 94 | JsonListener* myListener; 95 | bool do_emit_whitespace = false; 96 | char buffer[JSON_BUFFER_MAX_LENGTH]; 97 | int buffer_pos = 0; 98 | char unicode_escape_buffer[10]; 99 | uint8_t unicode_escape_buffer_pos = 0; 100 | char unicode_buffer[10]; 101 | uint8_t unicode_buffer_pos = 0; 102 | int16_t character_counter = 0; 103 | int16_t unicode_high_surrogate = 0; 104 | }; 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /SRC/JSON_PARSER/README: -------------------------------------------------------------------------------- 1 | This is a JSON parser library. The NLS configuration data is stored in JSON format. 2 | -------------------------------------------------------------------------------- /SRC/SD_SPI/README: -------------------------------------------------------------------------------- 1 | This is a library to manage SD-cards connected via SPI bus. 2 | -------------------------------------------------------------------------------- /SRC/SD_SPI/sdspi.h: -------------------------------------------------------------------------------- 1 | /* vim: set ai et ts=4 sw=4: */ 2 | #ifndef _SDSPI_H_ 3 | #define _SPSPI_H__ 4 | 5 | #include "main.h" 6 | 7 | #define SD_SPI_PORT hspi2 8 | extern SPI_HandleTypeDef SD_SPI_PORT; 9 | 10 | typedef enum e_sd_type { 11 | TYPE_NOT_READY = 0, TYPE_SDSC, TYPE_SDHC 12 | } SD_TYPE; 13 | 14 | typedef struct s_SDCARD { 15 | SD_TYPE type; 16 | uint32_t blocks; 17 | uint32_t erase_size; 18 | uint8_t init_status; 19 | } SDCARD; 20 | 21 | typedef enum { 22 | CMD0_GO_IDLE_STATE = 0, 23 | CMD8_SEND_IF_COND = 8, 24 | CMD9_SEND_CSD = 9, 25 | CMD12_STOP_TRANSMISSION = 12, 26 | CMD16_SET_BLOCKLEN = 16, 27 | CMD17_READ_SINGLE_BLOCK = 17, 28 | CMD18_READ_MULTIPLE_BLOCK = 18, 29 | CMD24_WRITE_BLOCK = 24, 30 | CMD25_WRITE_MULTIPLE_BLOCK = 25, 31 | CMD55_APP_CMD = 0x37, 32 | ACMD41_APP_SEND_OP_COND = 0x29, 33 | CMD58_READ_OCR = 0x3a 34 | } SPISD_CMD; 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | // all procedures return 0 on success, > 0 on failure 41 | uint8_t SD_Init(SDCARD *sd); 42 | 43 | uint8_t SD_Read(SDCARD *sd, uint32_t start_block, uint8_t count, uint8_t* data); 44 | uint8_t SD_Write(SDCARD *sd, uint32_t start_block, uint8_t count, const uint8_t* data); 45 | 46 | uint8_t SD_ReadSingleBlock(SDCARD *sd, uint32_t block_num, uint8_t* data); // sizeof(data) == 512! 47 | uint8_t SD_WriteSingleBlock(SDCARD *sd, uint32_t block_num, const uint8_t* data); // sizeof(data) == 512! 48 | uint8_t SD_ReadBlocks(SDCARD *sd, uint32_t start_block, uint8_t count, uint8_t* data); 49 | uint8_t SD_WriteSBlocks(SDCARD *sd, uint32_t start_block, uint8_t count, const uint8_t* data); 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /SRC/TFT/ILI9341.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ILI9341.h 3 | * 4 | * Created on: May 20, 2020 5 | * Author: Alex 6 | * 7 | * 2024 AUG 02 8 | * Added ILI9341v support 9 | */ 10 | 11 | #ifndef _ILI9341_H_ 12 | #define _ILI9341_H_ 13 | 14 | #include "common.h" 15 | 16 | // By default the display is in portrait mode 17 | #define ILI9341_SCREEN_WIDTH (240) 18 | #define ILI9341_SCREEN_HEIGHT (320) 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | void ILI9341_Init(void); 25 | void ILI9341v_Init(void); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /SRC/TFT/ILI9488.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ILI9341.h 3 | * 4 | * Created on: May 20, 2020 5 | * Author: Alex 6 | * 7 | * Based on the following libraries: 8 | * martnak /STM32-ILI9341, https://github.com/martnak/STM32-ILI9341 9 | * afiskon /stm32-ili9341, https://github.com/afiskon/stm32-ili9341 10 | * Bodmer /TFT_eSPI, https://github.com/Bodmer/TFT_eSPI 11 | * olikraus /u8glib, https://github.com/olikraus/u8glib 12 | * 13 | * CS & DC pins should share the same CPIO port 14 | */ 15 | 16 | #ifndef _ILI9488_H_ 17 | #define _ILI9488_H_ 18 | 19 | #include "common.h" 20 | 21 | // By default the display is in portrait mode 22 | #define ILI9488_SCREEN_WIDTH (320) 23 | #define ILI9488_SCREEN_HEIGHT (480) 24 | 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | void ILI9488_Init(void); 31 | void ILI9488_IPS_Init(void); 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /SRC/TFT/NT35510.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NT35510.c 3 | * 4 | * Created on: 5 JAN 2023 5 | * Author: Alex 6 | * 7 | * Based on Arduino Adafruit NT35510 library https://github.com/adafruit/Adafruit_NT35510 8 | * and code at http://www.lcdwiki.com/3.97inch_16BIT_Module_NT35510_SKU:MRB3973 9 | * 10 | * 2024 May 16 11 | * Implemented the custom NT35510_Command() function and changed the NT35510_Init() function 12 | */ 13 | 14 | #include 15 | #include "NT35510.h" 16 | #include "gamma.h" 17 | 18 | // Command list starts on page 106 of datasheet 19 | typedef enum { 20 | CMD_NOP_00 = 0x00, 21 | CMD_SWRESET_01 = 0x01, 22 | CMD_RDDID_04 = 0x04, 23 | CMD_RDERR_DSI_05 = 0x05, 24 | CMD_RDDST_09 = 0x09, 25 | CMD_RDDPM_0A = 0x0A, 26 | CMD_RDDMADCTL_0B = 0x0B, 27 | CMD_RDDCOLMOD_0C = 0x0C, 28 | CMD_RDDIM_0D = 0x0D, 29 | CMD_RDDSM_0E = 0x0E, 30 | CMD_RDDSDR_0F = 0x0F, 31 | CMD_SLPIN_10 = 0x10, 32 | CMD_SLPOUT_11 = 0x11, 33 | CMD_PTLON_12 = 0x12, 34 | CMD_NORON_13 = 0x13, 35 | CMD_DINVOFF_20 = 0x20, 36 | CMD_DINVON_21 = 0x21, 37 | CMD_DISPOFF_28 = 0x28, 38 | CMD_DISPON_29 = 0x29, 39 | CMD_CASET_2A = 0x2A, 40 | CMD_PASET_2B = 0x2B, 41 | CMD_RAMWR_2C = 0x2C, 42 | CMD_RAMRD_2E = 0x2E, 43 | CMD_PTLAR_30 = 0x30, 44 | CMD_VSCRDEF_33 = 0x33, 45 | CMD_TEOFF_34 = 0x34, 46 | CMD_TEON_35 = 0x35, 47 | CMD_MADCTL_36 = 0x36, 48 | CMD_VSCRSADD_37 = 0x37, 49 | CMD_IDMOFF_38 = 0x38, 50 | CMD_IDMON_39 = 0x39, 51 | CMD_PIXSET_3A = 0x3A, 52 | CMD_RDMEMCONT_3E = 0x3E, 53 | CMD_TESCAN_44 = 0x44, 54 | CMD_RDTESCAN_45 = 0x45, 55 | CMD_WRDISBV_51 = 0x51, 56 | CMD_RDDISBV_52 = 0x52, 57 | CMD_WRCTRLD_53 = 0x53, 58 | CMD_RDCTRLD_54 = 0x54, 59 | CMD_WRCABC_55 = 0x55, 60 | CMD_RDCABC_56 = 0x56, 61 | CMD_WRCABCMB_5E = 0x5E, 62 | CMD_RDCABCMB_5F = 0x5F, 63 | CMD_RDFCHKSUM_AA = 0xAA, 64 | CMD_RDCCHKSUM_AF = 0xAF, 65 | CMD_RDID1_DA = 0xDA, 66 | CMD_RDID2_DB = 0xDB, 67 | CMD_RDID3_DC = 0xDC, 68 | CMD_IFMODE_B0 = 0xB0, 69 | CMD_FRMCTR1_B1 = 0xB1, 70 | CMD_FRMCTR2_B2 = 0xB2, 71 | CMD_FRMCTR3_B3 = 0xB3, 72 | CMD_INVTR_B4 = 0xB4, 73 | CMD_BPC_B5 = 0xB5, 74 | CMD_DFC_B6 = 0xB6, 75 | CMD_EM_B7 = 0xB7, 76 | CMD_VCL_B8 = 0xB8, 77 | CMD_VGH_B9 = 0xB9, 78 | CMD_VGLX_BA = 0xBA, 79 | CMD_VGSP_BC = 0xBC, 80 | CMD_VGSN_BD = 0xBD, 81 | CMD_VCOM_BE = 0xBE, 82 | CMD_VGH_BF = 0xBF, 83 | CMD_PWCTRL1_C0 = 0xC0, 84 | CMD_PWCTRL2_C1 = 0xC1, 85 | CMD_PWCTRL3_C2 = 0xC2, 86 | CMD_VMCTRL1_C5 = 0xC5, 87 | CMD_VCMOFFS_C6 = 0xC6, 88 | CMD_TIM_C9 = 0xC9, 89 | CMD_BOE_CC = 0xCC, 90 | CMD_NVMADW_D0 = 0xD0, 91 | CMD_GAMMA_D1 = 0xD1, 92 | CMD_GAMMA_D2 = 0xD2, 93 | CMD_GAMMA_D3 = 0xD3, 94 | CMD_GAMMA_D4 = 0xD4, 95 | CMD_GAMMA_D5 = 0xD5, 96 | CMD_GAMMA_D6 = 0xD6, 97 | CMD_PGAMCTRL_E0 = 0xE0, 98 | CMD_NGAMCTRL_E1 = 0xE1, 99 | CMD_DGAMCTRL_E2 = 0xE2, 100 | CMD_DGAMCTRL_E3 = 0xE3, 101 | CMD_DOCA_E8 = 0xE8, 102 | CMD_CSCON_F0 = 0xF0, 103 | CMD_SPIRC_FB = 0xFB, 104 | CMD_TIM_FF = 0xFF 105 | } NT35510_CMD; 106 | 107 | // Initialize the Display 108 | void NT35510_Init(void) { 109 | #ifdef FSMC_LCD_CMD 110 | static tTFT_INT_FUNC iface = { 111 | .pReset = 0, 112 | .pCommand = TFT_FSMC_NT35510_Command, // Customize the command function only 113 | .pDataMode = 0, 114 | .pReadData = 0, 115 | .pColorBlockInit = 0, 116 | .pColorBlockSend = 0, 117 | .pColorBlockFlush = 0, 118 | .pDrawPixel = TFT_FSMC_HIGH_DrawPixel_16bits 119 | }; 120 | 121 | // Initialize display interface. 122 | TFT_InterfaceSetup(TFT_16bits, &iface); 123 | #else 124 | // Initialize display interface. By default the library guess the display interface 125 | TFT_InterfaceSetup(TFT_16bits, 0); 126 | #endif 127 | 128 | // Reset display hardware 129 | TFT_DEF_Reset(); 130 | // SOFTWARE RESET 131 | TFT_Command(CMD_SWRESET_01, 0, 0); 132 | TFT_Delay(150); 133 | 134 | // Most of these registers are not in the datasheet 135 | TFT_Command(CMD_CSCON_F0, (uint8_t *)"\x55\xAA\x52\x08\x01", 5); // 35510h 136 | TFT_Command(CMD_DFC_B6, (uint8_t *)"\x34\x34\x34", 3); // AVDD: manual 137 | TFT_Command(CMD_IFMODE_B0, (uint8_t *)"\x0D\x0D\x0D", 3); // AVDD Set AVDD 5.2V 138 | TFT_Command(CMD_EM_B7, (uint8_t *)"\x24\x24\x24", 3); // AVEE: manual 139 | TFT_Command(CMD_FRMCTR1_B1, (uint8_t *)"\x0D\x0D\x0D", 3); // AVEE -5.2V 140 | TFT_Command(CMD_VCL_B8, (uint8_t *)"\x24\x24\x24", 3); // Power Control for VCL ratio 141 | TFT_Command(CMD_FRMCTR2_B2, (uint8_t *)"\x00", 1); 142 | TFT_Command(CMD_VGH_B9, (uint8_t *)"\x24\x24\x24", 3); // VGH: Clamp Enable 143 | TFT_Command(CMD_FRMCTR3_B3, (uint8_t *)"\x05\x05\x05", 3); 144 | TFT_Command(CMD_VGLX_BA, (uint8_t *)"\x34\x34\x34", 3); // VGL(LVGL) 145 | TFT_Command(CMD_BPC_B5, (uint8_t *)"\x0B\x0B\x0B", 3); // VGL_REG(VGLO) 146 | TFT_Command(CMD_VGSP_BC, (uint8_t *)"\x00\xA3\x00", 3); // VGMP/VGSP 147 | TFT_Command(CMD_VGSN_BD, (uint8_t *)"\x00\xA3\x00", 3); // VGMN/VGSN 148 | TFT_Command(CMD_VCOM_BE, (uint8_t *)"\x00\x63", 2); // VCOM=-0.1 149 | 150 | #ifdef APPLY_GAMMA_PROFILE 151 | TFT_Gamma_NT35510(); // Gamma Setting 152 | #endif 153 | 154 | TFT_Command(CMD_CSCON_F0, (uint8_t *)"\x55\xAA\x52\x08\x00", 5); // LV2 Page 0 enable 155 | TFT_Command(CMD_IFMODE_B0, (uint8_t *)"\x08\x05\x02\x05\x02", 5); // RGB I/F Setting 156 | TFT_Command(CMD_DFC_B6, (uint8_t *)"\x06", 1); // SDT 157 | TFT_Command(CMD_BPC_B5, (uint8_t *)"\x50", 1); 158 | TFT_Command(CMD_EM_B7, (uint8_t *)"\x00\x00", 2); // Set Gate EQ 159 | TFT_Command(CMD_VCL_B8, (uint8_t *)"\x01\x05\x05\x05", 4); // Source EQ control (Mode 2) 160 | TFT_Command(CMD_VGSP_BC, (uint8_t *)"\x00\x00\x00", 3); // Inversion: Column inversion (NVT) 161 | TFT_Command(CMD_BOE_CC, (uint8_t *)"\x03\x00\x00", 3); // BOE's Setting(default) 162 | TFT_Command(CMD_VGSN_BD, (uint8_t *)"\x01\x84\x07\x31\x00", 5); // Display Timing 163 | TFT_Command(CMD_VGLX_BA, (uint8_t *)"\x01", 1); 164 | TFT_Command(CMD_TIM_FF, (uint8_t *)"\xAA\x55\x25\x01", 4); 165 | TFT_Command(CMD_TEON_35, (uint8_t *)"\x00", 1); 166 | TFT_Command(CMD_MADCTL_36, (uint8_t *)"\x00", 1); 167 | TFT_Command(CMD_PIXSET_3A, (uint8_t *)"\x55", 1); // 16-bit pixels everywhere, the display ignores this setup 168 | // Exit sleep mode 169 | TFT_DEF_SleepOut(); 170 | 171 | // Turn On Display 172 | TFT_Command(CMD_DISPON_29, 0, 0); 173 | TFT_Delay(5); 174 | TFT_Command(CMD_RAMWR_2C, 0, 0); 175 | 176 | // Setup display parameters 177 | uint8_t rot[4] = {0x00, 0x20|0x40, 0x80|0x40, 0x80|0x20}; 178 | TFT_Setup(NT35510_SCREEN_WIDTH, NT35510_SCREEN_HEIGHT, rot); 179 | } 180 | -------------------------------------------------------------------------------- /SRC/TFT/NT35510.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NT35510.h 3 | * 4 | * Created on: 5 JAN 2023 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef _NT35510_H 9 | #define _NT35510_H 10 | 11 | #include "common.h" 12 | 13 | // By default the display is in portrait mode 14 | #define NT35510_SCREEN_WIDTH (480) 15 | #define NT35510_SCREEN_HEIGHT (800) 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | void NT35510_Init(void); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | #endif /* _NT35510_H */ 28 | -------------------------------------------------------------------------------- /SRC/TFT/README: -------------------------------------------------------------------------------- 1 | The TFT graphic library 2 | -------------------------------------------------------------------------------- /SRC/TFT/SSD1963.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SSD1963.c 3 | * 4 | * Created on: May 15, 2024 5 | * 6 | * Based of source code of anothermist, https://github.com/anothermist/DISPLAYS 7 | * UNDER GNU v3 licence 8 | */ 9 | 10 | #include 11 | #include "SSD1963.h" 12 | #include "gamma.h" 13 | 14 | // Command list starts on chapter 8 of datasheet 15 | typedef enum { 16 | CMD_NOP_00 = 0x00, 17 | CMD_SWRESET_01 = 0x01, 18 | CMD_RDDID_04 = 0x04, 19 | CMD_RDERR_DSI_05 = 0x05, 20 | CMD_RDDST_09 = 0x09, 21 | CMD_RDDPM_0A = 0x0A, 22 | CMD_RDDMADCTL_0B = 0x0B, 23 | CMD_RDDCOLMOD_0C = 0x0C, 24 | CMD_RDDIM_0D = 0x0D, 25 | CMD_RDDSM_0E = 0x0E, 26 | CMD_RDDSDR_0F = 0x0F, 27 | CMD_SLPIN_10 = 0x10, 28 | CMD_SLPOUT_11 = 0x11, 29 | CMD_PTLON_12 = 0x12, 30 | CMD_NORON_13 = 0x13, 31 | CMD_DINVOFF_20 = 0x20, 32 | CMD_DINVON_21 = 0x21, 33 | CMD_DISPOFF_28 = 0x28, 34 | CMD_DISPON_29 = 0x29, 35 | CMD_CASET_2A = 0x2A, 36 | CMD_PASET_2B = 0x2B, 37 | CMD_RAMWR_2C = 0x2C, 38 | CMD_RAMRD_2E = 0x2E, 39 | CMD_PTLAR_30 = 0x30, 40 | CMD_VSCRDEF_33 = 0x33, 41 | CMD_TEOFF_34 = 0x34, 42 | CMD_TEON_35 = 0x35, 43 | CMD_MADCTL_36 = 0x36, 44 | CMD_VSCRSADD_37 = 0x37, 45 | CMD_IDMOFF_38 = 0x38, 46 | CMD_IDMON_39 = 0x39, 47 | CMD_PIXSET_3A = 0x3A, 48 | CMD_RDMEMCONT_3E = 0x3E, 49 | CMD_TESCAN_44 = 0x44, 50 | CMD_RDTESCAN_45 = 0x45, 51 | CMD_WRDISBV_51 = 0x51, 52 | CMD_RDDISBV_52 = 0x52, 53 | CMD_WRCTRLD_53 = 0x53, 54 | CMD_RDCTRLD_54 = 0x54, 55 | CMD_WRCABC_55 = 0x55, 56 | CMD_RDCABC_56 = 0x56, 57 | CMD_WRCABCMB_5E = 0x5E, 58 | CMD_RDCABCMB_5F = 0x5F, 59 | CMD_RDFCHKSUM_AA = 0xAA, 60 | CMD_RDCCHKSUM_AF = 0xAF, 61 | CMD_RDID1_DA = 0xDA, 62 | CMD_RDID2_DB = 0xDB, 63 | CMD_RDID3_DC = 0xDC, 64 | CMD_IFMODE_B0 = 0xB0, 65 | CMD_FRMCTR1_B1 = 0xB1, 66 | CMD_FRMCTR2_B2 = 0xB2, 67 | CMD_FRMCTR3_B3 = 0xB3, 68 | CMD_INVTR_B4 = 0xB4, 69 | CMD_BPC_B5 = 0xB5, 70 | CMD_DFC_B6 = 0xB6, 71 | CMD_EM_B7 = 0xB7, 72 | CMD_VCL_B8 = 0xB8, 73 | CMD_VGH_B9 = 0xB9, 74 | CMD_VGLX_BA = 0xBA, 75 | CMD_VGSP_BC = 0xBC, 76 | CMD_VGSN_BD = 0xBD, 77 | CMD_VCOM_BE = 0xBE, 78 | CMD_VGH_BF = 0xBF, 79 | CMD_PWCTRL1_C0 = 0xC0, 80 | CMD_PWCTRL2_C1 = 0xC1, 81 | CMD_PWCTRL3_C2 = 0xC2, 82 | CMD_VMCTRL1_C5 = 0xC5, 83 | CMD_VCMOFFS_C6 = 0xC6, 84 | CMD_TIM_C9 = 0xC9, 85 | CMD_BOE_CC = 0xCC, 86 | CMD_NVMADW_D0 = 0xD0, 87 | CMD_GAMMA_D1 = 0xD1, 88 | CMD_GAMMA_D2 = 0xD2, 89 | CMD_GAMMA_D3 = 0xD3, 90 | CMD_GAMMA_D4 = 0xD4, 91 | CMD_GAMMA_D5 = 0xD5, 92 | CMD_GAMMA_D6 = 0xD6, 93 | CMD_PGAMCTRL_E0 = 0xE0, 94 | CMD_NGAMCTRL_E1 = 0xE1, 95 | CMD_DGAMCTRL_E2 = 0xE2, 96 | CMD_DGAMCTRL_E3 = 0xE3, 97 | CMD_LSHIFT_FREQ_E6 = 0xE6, 98 | CMD_DOCA_E8 = 0xE8, 99 | CMD_CSCON_F0 = 0xF0, 100 | CMD_SPIRC_FB = 0xFB, 101 | CMD_TIM_FF = 0xFF 102 | } SSD1963_CMD; 103 | 104 | // Initialize the Display 105 | void SSD1963_Init(void) { 106 | // Initialize display interface. By default the library guess the display interface 107 | TFT_InterfaceSetup(TFT_16bits, 0); 108 | // Reset display hardware 109 | TFT_DEF_Reset(); 110 | // SOFTWARE RESET 111 | TFT_Command(CMD_SWRESET_01, 0, 0); 112 | TFT_Delay(150); 113 | 114 | TFT_Command(CMD_DGAMCTRL_E2, (uint8_t *)"\x1d\x02\xFF", 3); // set frequency^ presceller(M=29), multiplier(N=2), on-off multiplier and presceller 115 | TFT_Command(CMD_PGAMCTRL_E0, (uint8_t *)"\x01", 1); // Turn on the PLL 116 | TFT_Delay(120); // Wait for 100us to let the PLL stable and read the PLL lock status bit. 117 | TFT_Command(CMD_PGAMCTRL_E0, (uint8_t *)"\x03", 1); // Switch the clock source to PLL 118 | TFT_Delay(120); 119 | TFT_Command(CMD_SWRESET_01, 0, 0); 120 | TFT_Delay(120); 121 | 122 | TFT_Command(CMD_LSHIFT_FREQ_E6, (uint8_t *)"\x03\x85\x1d", 3); // Configure the dot clock frequency 123 | TFT_Command(CMD_IFMODE_B0, (uint8_t *)"\xAE\x20\x03\x1F\x01\xDF\x2D", 7); // Set the panel size to 480 x 800 and polarity 124 | TFT_Command(CMD_INVTR_B4, (uint8_t *)"\x03\xA0\x00\x2E\x30\x00\x0F\x00", 8); // Horizontal Display Period 125 | TFT_Command(CMD_DFC_B6, (uint8_t *)"\x02\x0D\x00\x10\x10\x08\x00", 7); 126 | TFT_Command(CMD_VCOM_BE, (uint8_t *)"\x08\xFF\x01", 3); // PWM signal frequency = PLL clock / (256 * (PWMF[7:0] + 1)) / 256 127 | TFT_Command(CMD_MADCTL_36, 0, 0); // set address_mode 128 | TFT_Command(CMD_CSCON_F0, (uint8_t *)"\x03", 1); // mcu interface config, 16 bit interface (565) 129 | 130 | #ifdef APPLY_GAMMA_PROFILE 131 | TFT_Gamma_NT35510(); // Gamma Setting 132 | #endif 133 | 134 | // Exit sleep mode 135 | TFT_DEF_SleepOut(); 136 | 137 | // Turn On Display 138 | TFT_Command(CMD_DISPON_29, 0, 0); 139 | TFT_Delay(5); 140 | TFT_Command(CMD_RAMWR_2C, 0, 0); 141 | 142 | // Setup display parameters 143 | uint8_t rot[4] = {0x00, 0x20|0x40, 0x80|0x40, 0x80|0x20}; 144 | TFT_Setup(SSD1963_SCREEN_WIDTH, SSD1963_SCREEN_HEIGHT, rot); 145 | } 146 | -------------------------------------------------------------------------------- /SRC/TFT/SSD1963.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SSD1963.h 3 | * 4 | * Created on: May 15, 2024 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef _SSD1963_H 9 | #define _SSD1963_H 10 | 11 | #include "common.h" 12 | 13 | // By default the display is in portrait mode 14 | #define SSD1963_SCREEN_WIDTH (800) 15 | #define SSD1963_SCREEN_HEIGHT (480) 16 | 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | void SSD1963_Init(void); 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /SRC/TFT/ST7735.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ST7735.c 3 | * 4 | * Created on: Nov 19 2020 5 | * Author: Alex 6 | */ 7 | 8 | #include 9 | #include "ST7735.h" 10 | #include "common.h" 11 | 12 | typedef enum { 13 | CMD_NOP_00 = 0x00, 14 | CMD_SWRESET_01 = 0x01, 15 | CMD_RDDID_04 = 0x04, 16 | CMD_RDERR_DSI_05 = 0x05, 17 | CMD_RDDST_09 = 0x09, 18 | CMD_RDDPM_0A = 0x0A, 19 | CMD_RDDMADCTL_0B = 0x0B, 20 | CMD_RDDCOLMOD_0C = 0x0C, 21 | CMD_RDDIM_0D = 0x0D, 22 | CMD_RDDSM_0E = 0x0E, 23 | CMD_RDDSDR_0F = 0x0F, 24 | CMD_SLPIN_10 = 0x10, 25 | CMD_SLPOUT_11 = 0x11, 26 | CMD_PTLON_12 = 0x12, 27 | CMD_NORON_13 = 0x13, 28 | CMD_DINVOFF_20 = 0x20, 29 | CMD_DINVON_21 = 0x21, 30 | CMD_DISPOFF_28 = 0x28, 31 | CMD_DISPON_29 = 0x29, 32 | CMD_CASET_2A = 0x2A, 33 | CMD_PASET_2B = 0x2B, 34 | CMD_RAMWR_2C = 0x2C, 35 | CMD_RAMRD_2E = 0x2E, 36 | CMD_PTLAR_30 = 0x30, 37 | CMD_VSCRDEF_33 = 0x33, 38 | CMD_TEOFF_34 = 0x34, 39 | CMD_TEON_35 = 0x35, 40 | CMD_MADCTL_36 = 0x36, 41 | CMD_VSCRSADD_37 = 0x37, 42 | CMD_IDMOFF_38 = 0x38, 43 | CMD_IDMON_39 = 0x39, 44 | CMD_PIXSET_3A = 0x3A, 45 | CMD_RDMEMCONT_3E = 0x3E, 46 | CMD_TESCAN_44 = 0x44, 47 | CMD_RDTESCAN_45 = 0x45, 48 | CMD_WRDISBV_51 = 0x51, 49 | CMD_RDDISBV_52 = 0x52, 50 | CMD_WRCTRLD_53 = 0x53, 51 | CMD_RDCTRLD_54 = 0x54, 52 | CMD_WRCABC_55 = 0x55, 53 | CMD_RDCABC_56 = 0x56, 54 | CMD_WRCABCMB_5E = 0x5E, 55 | CMD_RDCABCMB_5F = 0x5F, 56 | CMD_RDFCHKSUM_AA = 0xAA, 57 | CMD_RDCCHKSUM_AF = 0xAF, 58 | CMD_RDID1_DA = 0xDA, 59 | CMD_RDID2_DB = 0xDB, 60 | CMD_RDID3_DC = 0xDC, 61 | CMD_IFMODE_B0 = 0xB0, 62 | CMD_FRMCTR1_B1 = 0xB1, 63 | CMD_FRMCTR2_B2 = 0xB2, 64 | CMD_FRMCTR3_B3 = 0xB3, 65 | CMD_INVTR_B4 = 0xB4, 66 | CMD_BPC_B5 = 0xB5, 67 | CMD_DFC_B6 = 0xB6, 68 | CMD_EM_B7 = 0xB7, 69 | CMD_PWCTRL1_C0 = 0xC0, 70 | CMD_PWCTRL2_C1 = 0xC1, 71 | CMD_PWCTRL3_C2 = 0xC2, 72 | CMD_VMCTRL1_C5 = 0xC5, 73 | CMD_VCMOFFS_C6 = 0xC6, 74 | CMD_NVMADW_D0 = 0xD0, 75 | CMD_NVMBPROG_D1 = 0xD1, 76 | CMD_NVMSTRD_D2 = 0xD2, 77 | CMD_RDID4_D3 = 0xD3, 78 | CMD_PGAMCTRL_E0 = 0xE0, 79 | CMD_NGAMCTRL_E1 = 0xE1, 80 | CMD_DGAMCTRL_E2 = 0xE2, 81 | CMD_DGAMCTRL_E3 = 0xE3, 82 | CMD_DOCA_E8 = 0xE8, 83 | CMD_CSCON_F0 = 0xF0, 84 | CMD_SPIRC_FB = 0xFB 85 | } ST7796_CMD; 86 | 87 | // Initialize the Display 88 | void ST7735_Init(void) { 89 | // Initialize display interface. By default the library guess the display interface 90 | TFT_InterfaceSetup(TFT_16bits, 0); 91 | // Reset display hardware 92 | TFT_DEF_Reset(); 93 | // SOFTWARE RESET 94 | TFT_Delay(1); 95 | TFT_Command(CMD_SWRESET_01, 0, 0); 96 | TFT_Delay(500); 97 | 98 | // positive gamma control 99 | TFT_Command(CMD_PGAMCTRL_E0, (uint8_t *)"\x09\x16\x09\x20\x21\x1B\x13\x19\x17\x15\x1E\x2B\x04\x05\x02\x0E", 16); 100 | // negative gamma control 101 | TFT_Command(CMD_NGAMCTRL_E1, (uint8_t *)"\x0B\x14\x08\x1E\x22\x1D\x18\x1E\x1B\x1A\x24\x2B\x06\x06\x02\x0F", 16); 102 | // Power Control 1 (Vreg1out, Verg2out) 103 | TFT_Command(CMD_PWCTRL1_C0, (uint8_t *)"\x17\x15", 2); 104 | // Power Control 2 (VGH,VGL) 105 | TFT_Command(CMD_PWCTRL2_C1, (uint8_t *)"\x41", 1); 106 | // Power Control 3 (Vcom) 107 | TFT_Command(CMD_VMCTRL1_C5, (uint8_t *)"\x00\x12\x80", 3); 108 | // Interface Pixel Format (16 bit) 109 | TFT_Command(CMD_PIXSET_3A, (uint8_t *)"\x55", 1); 110 | // Interface Mode Control (SDO NOT USE) 111 | TFT_Command(CMD_IFMODE_B0, (uint8_t *)"\x80", 1); 112 | // Frame rate (60Hz) 113 | TFT_Command(CMD_FRMCTR1_B1, (uint8_t *)"\xA0", 1); 114 | // Display Inversion Control (2-dot) 115 | TFT_Command(CMD_INVTR_B4, (uint8_t *)"\x02", 1); 116 | // Display Function Control RGB/MCU Interface Control 117 | TFT_Command(CMD_DFC_B6, (uint8_t *)"\x02\x02", 2); 118 | // Set Image Function (Disable 24 bit data) 119 | TFT_Command(0xE9, (uint8_t *)"\x00", 1); 120 | // Adjust Control (D7 stream, loose) 121 | TFT_Command(0xF7, (uint8_t *)"\xA9\x51\x2C\x82", 4); 122 | 123 | TFT_Command(CMD_MADCTL_36, (uint8_t *)"\x00", 1); 124 | 125 | // Exit sleep mode 126 | TFT_DEF_SleepOut(); 127 | 128 | // Turn On Display 129 | TFT_Command(CMD_DISPON_29, 0, 0); 130 | TFT_Delay(5); 131 | 132 | // Setup display parameters 133 | uint8_t rot[4] = {0x00, 0x40|0x20, 0x80|0x40, 0x80|0x20}; 134 | TFT_Setup(ST7735_SCREEN_WIDTH, ST7735_SCREEN_HEIGHT, rot); 135 | } 136 | -------------------------------------------------------------------------------- /SRC/TFT/ST7735.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ST7735.h 3 | * 4 | * Created on: Nov 19 2020 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef _ST7735_H 9 | #define _ST7735_H 10 | 11 | #include "common.h" 12 | 13 | // By default the display is in portrait mode 14 | #define ST7735_SCREEN_WIDTH (128) 15 | #define ST7735_SCREEN_HEIGHT (160) 16 | 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | void ST7735_Init(void); 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif 29 | 30 | -------------------------------------------------------------------------------- /SRC/TFT/ST7796.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ILI9341.c 3 | * 4 | * Created on: May 20, 2020 5 | * Author: Alex 6 | */ 7 | 8 | #include 9 | #include "ST7796.h" 10 | #include "common.h" 11 | 12 | typedef enum { 13 | CMD_NOP_00 = 0x00, 14 | CMD_SWRESET_01 = 0x01, 15 | CMD_RDDID_04 = 0x04, 16 | CMD_RDERR_DSI_05 = 0x05, 17 | CMD_RDDST_09 = 0x09, 18 | CMD_RDDPM_0A = 0x0A, 19 | CMD_RDDMADCTL_0B = 0x0B, 20 | CMD_RDDCOLMOD_0C = 0x0C, 21 | CMD_RDDIM_0D = 0x0D, 22 | CMD_RDDSM_0E = 0x0E, 23 | CMD_RDDSDR_0F = 0x0F, 24 | CMD_SLPIN_10 = 0x10, 25 | CMD_SLPOUT_11 = 0x11, 26 | CMD_PTLON_12 = 0x12, 27 | CMD_NORON_13 = 0x13, 28 | CMD_DINVOFF_20 = 0x20, 29 | CMD_DINVON_21 = 0x21, 30 | CMD_DISPOFF_28 = 0x28, 31 | CMD_DISPON_29 = 0x29, 32 | CMD_CASET_2A = 0x2A, 33 | CMD_PASET_2B = 0x2B, 34 | CMD_RAMWR_2C = 0x2C, 35 | CMD_RAMRD_2E = 0x2E, 36 | CMD_PTLAR_30 = 0x30, 37 | CMD_VSCRDEF_33 = 0x33, 38 | CMD_TEOFF_34 = 0x34, 39 | CMD_TEON_35 = 0x35, 40 | CMD_MADCTL_36 = 0x36, 41 | CMD_VSCRSADD_37 = 0x37, 42 | CMD_IDMOFF_38 = 0x38, 43 | CMD_IDMON_39 = 0x39, 44 | CMD_PIXSET_3A = 0x3A, 45 | CMD_RDMEMCONT_3E = 0x3E, 46 | CMD_TESCAN_44 = 0x44, 47 | CMD_RDTESCAN_45 = 0x45, 48 | CMD_WRDISBV_51 = 0x51, 49 | CMD_RDDISBV_52 = 0x52, 50 | CMD_WRCTRLD_53 = 0x53, 51 | CMD_RDCTRLD_54 = 0x54, 52 | CMD_WRCABC_55 = 0x55, 53 | CMD_RDCABC_56 = 0x56, 54 | CMD_WRCABCMB_5E = 0x5E, 55 | CMD_RDCABCMB_5F = 0x5F, 56 | CMD_RDFCHKSUM_AA = 0xAA, 57 | CMD_RDCCHKSUM_AF = 0xAF, 58 | CMD_RDID1_DA = 0xDA, 59 | CMD_RDID2_DB = 0xDB, 60 | CMD_RDID3_DC = 0xDC, 61 | CMD_IFMODE_B0 = 0xB0, 62 | CMD_FRMCTR1_B1 = 0xB1, 63 | CMD_FRMCTR2_B2 = 0xB2, 64 | CMD_FRMCTR3_B3 = 0xB3, 65 | CMD_INVTR_B4 = 0xB4, 66 | CMD_BPC_B5 = 0xB5, 67 | CMD_DFC_B6 = 0xB6, 68 | CMD_EM_B7 = 0xB7, 69 | CMD_PWCTRL1_C0 = 0xC0, 70 | CMD_PWCTRL2_C1 = 0xC1, 71 | CMD_PWCTRL3_C2 = 0xC2, 72 | CMD_VMCTRL1_C5 = 0xC5, 73 | CMD_VCMOFFS_C6 = 0xC6, 74 | CMD_NVMADW_D0 = 0xD0, 75 | CMD_NVMBPROG_D1 = 0xD1, 76 | CMD_NVMSTRD_D2 = 0xD2, 77 | CMD_RDID4_D3 = 0xD3, 78 | CMD_PGAMCTRL_E0 = 0xE0, 79 | CMD_NGAMCTRL_E1 = 0xE1, 80 | CMD_DGAMCTRL_E2 = 0xE2, 81 | CMD_DGAMCTRL_E3 = 0xE3, 82 | CMD_DOCA_E8 = 0xE8, 83 | CMD_CSCON_F0 = 0xF0, 84 | CMD_SPIRC_FB = 0xFB 85 | } ST7796_CMD; 86 | 87 | // Initialize the Display 88 | void ST7796_Init(void) { 89 | // Initialize display interface. By default the library guess the display interface 90 | TFT_InterfaceSetup(TFT_16bits, 0); 91 | // Reset display hardware 92 | TFT_DEF_Reset(); 93 | // SOFTWARE RESET 94 | TFT_Command(CMD_SWRESET_01, 0, 0); 95 | TFT_Delay(1000); 96 | // Exit sleep mode 97 | TFT_DEF_SleepOut(); 98 | 99 | // Command Set control: Enable extension command 2 partI 100 | TFT_Command(CMD_CSCON_F0, (uint8_t *)"\xC3", 1); 101 | // Command Set control: Enable extension command 2 partII 102 | TFT_Command(CMD_CSCON_F0, (uint8_t *)"\x96", 1); 103 | // Memory access mode: X-Mirror, Top-Left to right-Buttom, RGB 104 | TFT_Command(CMD_MADCTL_36, (uint8_t *)"\x48", 1); 105 | // Interface Pixel Format: 16 bits 106 | TFT_Command(CMD_PIXSET_3A, (uint8_t *)"\x55", 1); 107 | //Display Inversion Control: 1-dot inversion 108 | TFT_Command(CMD_INVTR_B4, (uint8_t *)"\x01", 1); 109 | // Display function control: Source Output Scan from S1 to S960, Gate Output scan from G1 to G480, scan cycle=2; LCD Drive Line=8*(59+1) 110 | TFT_Command(CMD_DFC_B6, (uint8_t *)"\x80\x02\x3B", 3); 111 | // Display Output Ctrl Adjust: Source eqaulizing period time= 22.5 us; Timing for "Gate start"=25; Timing for "Gate End"=37 (Tclk), Gate driver EQ function ON 112 | TFT_Command(CMD_DOCA_E8, (uint8_t *)"\x40\x8A\x00\x00\x29\x19\xA5\x33", 8); 113 | // Power Control 2: VGH, VGL 114 | TFT_Command(CMD_PWCTRL2_C1, (uint8_t *)"\x06", 1); 115 | TFT_Delay(5); 116 | // Power Control 3 117 | TFT_Command(CMD_PWCTRL3_C2, (uint8_t *)"\xA7", 1); 118 | // Power Control 3: Vcom 0.9 119 | TFT_Command(CMD_VMCTRL1_C5, (uint8_t *)"\x18", 1); 120 | TFT_Delay(120); 121 | 122 | // Gamma"+" 123 | TFT_Command(CMD_PGAMCTRL_E0, (uint8_t *)"\xF0\x09\x0B\x06\x04\x15\x2F\x54\x42\x3C\x17\x14\x16\x1B", 14); 124 | // Gamma"-" 125 | TFT_Command(CMD_NGAMCTRL_E1, (uint8_t *)"\xE0\x09\x0B\x06\x04\x03\x2B\x43\x42\x3B\x16\x14\x17\x1B", 14); 126 | TFT_Delay(120); 127 | // Command Set control: Disable extension command 2 partI 128 | TFT_Command(CMD_CSCON_F0, (uint8_t *)"\x3C", 1); 129 | // Command Set control: Disable extension command 2 partII 130 | TFT_Command(CMD_CSCON_F0, (uint8_t *)"\x69", 1); 131 | 132 | // Turn On Display 133 | TFT_Command(CMD_DISPON_29, 0, 0); 134 | TFT_Delay(5); 135 | 136 | // Setup display parameters 137 | uint8_t rot[4] = {0x40|0x08, 0x20|0x08, 0x80|0x08, 0x40|0x80|0x20|0x08}; 138 | TFT_Setup(ST7796_SCREEN_WIDTH, ST7796_SCREEN_HEIGHT, rot); 139 | } 140 | -------------------------------------------------------------------------------- /SRC/TFT/ST7796.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ST7796.h 3 | * 4 | * Created on: Nov 18, 2020 5 | * Author: Alex 6 | * 7 | * Based on the following libraries: 8 | * martnak /STM32-ILI9341, https://github.com/martnak/STM32-ILI9341 9 | * afiskon /stm32-ili9341, https://github.com/afiskon/stm32-ili9341 10 | * Bodmer /TFT_eSPI, https://github.com/Bodmer/TFT_eSPI 11 | * olikraus /u8glib, https://github.com/olikraus/u8glib 12 | * 13 | * CS & DC pins should share the same CPIO port 14 | */ 15 | 16 | #ifndef _ST7796_H_ 17 | #define _ST7796_H_ 18 | 19 | #include "common.h" 20 | 21 | // By default the display is in portrait mode 22 | #define ST7796_SCREEN_WIDTH (320) 23 | #define ST7796_SCREEN_HEIGHT (480) 24 | 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | void ST7796_Init(void); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /SRC/TFT/bitmap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * bitpam.cpp 3 | * 4 | * Created on: May 23 2020 5 | * Author: Alex 6 | */ 7 | 8 | #include 9 | #include 10 | #include "bitmap.h" 11 | #include "common.h" 12 | 13 | BITMAP::BITMAP(uint16_t width, uint16_t height) { 14 | ds = 0; 15 | if (width == 0 || height == 0) return; 16 | 17 | uint8_t bytes_per_row = (width+7) >> 3; 18 | ds = (struct data *)calloc(sizeof(struct data) + height * bytes_per_row, sizeof(uint8_t)); 19 | if (!ds) return; 20 | ds->w = width; 21 | ds->h = height; 22 | ds->links = 1; 23 | } 24 | 25 | // Allocate the memory manually, in the CCM region for instance 26 | // Please, ensure the data fits to the memory region 27 | BITMAP::BITMAP(uint8_t* addr, uint32_t max_size, uint16_t width, uint16_t height) { 28 | if (addr == 0 || width == 0 || height == 0) return; 29 | // Check the required memory size 30 | uint8_t bytes_per_row = (width+7) >> 3; 31 | uint32_t b_size = sizeof(struct data) + height * bytes_per_row; 32 | if (b_size > max_size) { // ccm buffer is about to overflow 33 | b_size = max_size - sizeof(struct data); // Remaining bytes available for the forecast string 34 | b_size /= height; // Maximum bytes per horizontal line in the forecast string 35 | width = b_size << 3; // Cut-off the BITMAP width 36 | } 37 | ds = (struct data *)addr; 38 | ds->w = width; 39 | ds->h = height; 40 | ds->links = 255; // Do not free the memory 41 | clear(); 42 | } 43 | 44 | BITMAP::BITMAP(const BITMAP &bm) { 45 | this->ds = bm.ds; 46 | ++ds->links; 47 | } 48 | 49 | BITMAP& BITMAP::operator=(const BITMAP &bm) { 50 | if (this != &bm) { 51 | if (ds != 0 && --(this->ds->links) == 0) { 52 | free(ds); 53 | } 54 | this->ds = bm.ds; 55 | ++ds->links; 56 | } 57 | return *this; 58 | } 59 | 60 | BITMAP::~BITMAP(void) { 61 | if (!ds) return; 62 | if (--ds->links > 0) return; // Destroy yet another copy of the bitmap 63 | free(ds); 64 | ds = 0; 65 | } 66 | 67 | uint32_t BITMAP::totalSize(void) { 68 | if (!ds) return 0; 69 | uint8_t bytes_per_row = (ds->w+7) >> 3; 70 | return sizeof(struct data) + ds->h * bytes_per_row; 71 | } 72 | 73 | void BITMAP::clear(void) { 74 | if (!ds) return; 75 | uint8_t bytes_per_row = (ds->w + 7) >> 3; 76 | uint32_t size = bytes_per_row * ds->h; 77 | TFT_BM_Clear(ds->data, size); 78 | } 79 | 80 | void BITMAP::drawPixel(uint16_t x, uint16_t y) { 81 | if (!ds) return; 82 | TFT_BM_DrawPixel(ds->data, ds->w, ds->h, x, y); 83 | } 84 | 85 | bool BITMAP::pixel(uint16_t x, uint16_t y) { 86 | if (!ds) return false; 87 | return TFT_BM_Pixel(ds->data, ds->w, ds->h, x, y) != 0; 88 | } 89 | 90 | void BITMAP::drawHLine(uint16_t x, uint16_t y, uint16_t length) { 91 | if (!ds) return; 92 | TFT_BM_DrawHLine(ds->data, ds->w, ds->h, x, y, length); 93 | } 94 | 95 | void BITMAP::drawVLine(uint16_t x, uint16_t y, uint16_t length) { 96 | if (!ds) return; 97 | TFT_BM_DrawVLine(ds->data, ds->w, ds->h, x, y, length); 98 | } 99 | 100 | void BITMAP::drawIcon(uint16_t x, uint16_t y, const uint8_t *icon, uint16_t ic_width, uint16_t ic_height) { 101 | if (!ds || !icon) return; 102 | TFT_BM_JoinIcon(ds->data, ds->w, ds->h, x, y, icon, ic_width, ic_height); 103 | } 104 | 105 | void BITMAP::drawVGauge(uint16_t gauge, bool edged) { 106 | if (!ds) return; 107 | TFT_BM_DrawVGauge(ds->data, ds->w, ds->h, gauge, edged); 108 | } 109 | 110 | void BITMAP::draw(uint16_t x, uint16_t y, uint16_t bg_color, uint16_t fg_color) { 111 | TFT_DrawBitmap(x, y, ds->w, ds->h, ds->data, ds->w, bg_color, fg_color); 112 | } 113 | 114 | void BITMAP::drawInsideArea(uint16_t x, uint16_t y, uint16_t area_width, uint16_t area_height, uint16_t bg_color, uint16_t fg_color) { 115 | TFT_DrawBitmap(x, y, area_width, area_height, ds->data, ds->w, bg_color, fg_color); 116 | } 117 | 118 | void BITMAP::scroll(uint16_t x, uint16_t y, uint16_t area_width, int16_t offset, uint8_t gap, uint16_t bg_color, uint16_t fg_color) { 119 | TFT_DrawScrolledBitmap(x, y, area_width, ds->h, ds->data, ds->w, offset, gap, bg_color, fg_color); 120 | } 121 | -------------------------------------------------------------------------------- /SRC/TFT/bitmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * bitmap.h 3 | * 4 | * Created on: May 23 2020 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef _BITMAP_H_ 9 | #define _BITMAP_H_ 10 | 11 | #include "main.h" 12 | #include 13 | #include "u8g_font.h" 14 | 15 | /* 16 | * Bitmap data structure allocated in memory 17 | * the space to store bitmap width and height is allocated together 18 | * with the space for bitmap itself 19 | * Each bitmap instance is allocated just once 20 | * All other copies are just "links" to the main instance 21 | */ 22 | struct data { 23 | uint16_t w; // Bitmap width 24 | uint16_t h; // Bitmap height 25 | uint8_t links; // Number of the links to allocated area 26 | uint8_t data[0]; // Bitmap array 27 | }; 28 | 29 | class BITMAP { 30 | public: 31 | BITMAP(void) { ds = 0; } 32 | BITMAP(uint16_t width, uint16_t height); 33 | BITMAP(uint8_t* addr, uint32_t max_size, uint16_t width, uint16_t height); 34 | BITMAP(const BITMAP &bm); 35 | BITMAP& operator=(const BITMAP &bm); 36 | ~BITMAP(void); 37 | uint8_t* bitmap(void) { return ds->data; } 38 | uint16_t width(void) { return (ds)?ds->w:0; } 39 | uint16_t height(void) { return (ds)?ds->h:0; } 40 | uint32_t totalSize(void); 41 | void clear(void); 42 | void drawPixel(uint16_t x, uint16_t y); 43 | bool pixel(uint16_t x, uint16_t y); 44 | void drawHLine(uint16_t x, uint16_t y, uint16_t length); 45 | void drawVLine(uint16_t x, uint16_t y, uint16_t length); 46 | void drawIcon(uint16_t x, uint16_t y, const uint8_t *icon, uint16_t ic_width, uint16_t ic_height); 47 | void drawVGauge(uint16_t gauge, bool edged); 48 | void draw(uint16_t x, uint16_t y, uint16_t bg_color, uint16_t fg_color); 49 | void scroll(uint16_t x, uint16_t y, uint16_t area_width, int16_t offset, uint8_t gap, uint16_t bg_color, uint16_t fg_color); 50 | void drawInsideArea(uint16_t x, uint16_t y, uint16_t area_width, uint16_t area_height, uint16_t bg_color, uint16_t fg_color); 51 | private: 52 | struct data *ds = 0; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /SRC/TFT/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * common.h 3 | * 4 | * Created on: Nov 4, 2022 5 | * Author: Alex 6 | * 7 | * Base component of a library. Contains set of general functions to manage TFT display family. 8 | * General approach is to set rectangular area on the screen and send array of colors to fill-up that area. 9 | * 10 | * Based on the following libraries: 11 | * martnak /STM32-ILI9341, https://github.com/martnak/STM32-ILI9341 12 | * afiskon /stm32-ili9341, https://github.com/afiskon/stm32-ili9341 13 | * Bodmer /TFT_eSPI, https://github.com/Bodmer/TFT_eSPI 14 | * olikraus /u8glib, https://github.com/olikraus/u8glib 15 | * 16 | * Each particular display driver have to implement two native functions: 17 | * _Init(void) - to initialize the display 18 | * _SetRotation(tRotation rotation) 19 | * because these methods depends on hardware. 20 | */ 21 | 22 | #ifndef _COMMON_H 23 | #define _COMMON_H 24 | 25 | #include 26 | #include "main.h" 27 | #include "interface.h" 28 | #include "config.h" 29 | 30 | typedef enum { 31 | TFT_ROTATION_0 = 0, 32 | TFT_ROTATION_90 = 1, 33 | TFT_ROTATION_180 = 2, 34 | TFT_ROTATION_270 = 3 35 | } tRotation; 36 | 37 | typedef enum { 38 | BLACK = 0x0000, 39 | NAVY = 0x000F, 40 | DARKGREEN = 0x03E0, 41 | DARKCYAN = 0x03EF, 42 | MAROON = 0x7800, 43 | PURPLE = 0x780F, 44 | OLIVE = 0x7BE0, 45 | LIGHTGREY = 0xC618, 46 | DARKGREY = 0x7BEF, 47 | BLUE = 0x001F, 48 | GREEN = 0x07E0, 49 | CYAN = 0x07FF, 50 | RED = 0xF800, 51 | MAGENTA = 0xF81F, 52 | YELLOW = 0xFFE0, 53 | WHITE = 0xFFFF, 54 | ORANGE = 0xFD20, 55 | GREENYELLOW = 0xAFE5, 56 | PINK = 0xF81F, 57 | GREY = 0x52AA 58 | } tColor; 59 | 60 | typedef uint16_t (*t_NextPixel)(uint16_t row, uint16_t col); 61 | typedef double (*LineThickness)(uint16_t pos, uint16_t length); 62 | 63 | #ifdef __cplusplus 64 | extern "C" { 65 | #endif 66 | 67 | // Functions to draw graphic primitives 68 | uint16_t TFT_Width(void); 69 | uint16_t TFT_Height(void); 70 | tRotation TFT_Rotation(void); 71 | uint16_t TFT_WheelColor(uint8_t wheel_pos); 72 | uint16_t TFT_Color(uint8_t red, uint8_t green, uint8_t blue); 73 | void TFT_FillScreen(uint16_t color); 74 | void TFT_DrawFilledRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color); 75 | void TFT_DrawPixel(uint16_t x, uint16_t y, uint16_t color); 76 | void TFT_DrawHLine(uint16_t x, uint16_t y, uint16_t length, uint16_t color); 77 | void TFT_DrawVLine(uint16_t x, uint16_t y, uint16_t length, uint16_t color); 78 | void TFT_DrawRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color); 79 | void TFT_DrawRoundRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, uint16_t color); 80 | void TFT_DrawFilledRoundRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, uint16_t color); 81 | void TFT_DrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color); 82 | void TFT_DrawCircle(uint16_t x, uint16_t y, uint8_t radius, uint16_t color); 83 | void TFT_DrawFilledCircle(uint16_t x, uint16_t y, uint8_t radius, uint16_t color); 84 | void TFT_DrawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color); 85 | void TFT_DrawfilledTriangle (uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color); 86 | void TFT_DrawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, uint16_t color); 87 | void TFT_DrawFilledEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, uint16_t color); 88 | void TFT_DrawArea(uint16_t x0, uint16_t y0, uint16_t area_width, uint16_t area_height, t_NextPixel nextPixelCB); 89 | void TFT_BM_Clear(uint8_t *bitmap, uint32_t size); 90 | void TFT_BM_DrawPixel(uint8_t *bitmap, uint16_t bm_width, uint16_t bm_height, uint16_t x, uint16_t y); 91 | uint8_t TFT_BM_Pixel(const uint8_t *bitmap, uint16_t bm_width, uint16_t bm_height, uint16_t x, uint16_t y); 92 | void TFT_BM_DrawHLine(uint8_t *bitmap, uint16_t bm_width, uint16_t bm_height, uint16_t x, uint16_t y, uint16_t length); 93 | void TFT_BM_DrawVLine(uint8_t *bitmap, uint16_t bm_width, uint16_t bm_height, uint16_t x, uint16_t y, uint16_t length); 94 | void TFT_BM_JoinIcon(uint8_t *bitmap, uint16_t bm_width, uint16_t bm_height, uint16_t x, uint16_t y, const uint8_t *icon, uint16_t ic_width, uint16_t ic_height); 95 | void TFT_BM_DrawVGauge(uint8_t *bitmap, uint16_t bm_width, uint16_t bm_height, uint16_t gauge, uint8_t edged); 96 | void TFT_DrawBitmap(uint16_t x0, uint16_t y0, uint16_t area_width, uint16_t area_height, 97 | const uint8_t *bitmap, uint16_t bm_width, uint16_t bg_color, uint16_t fg_color); 98 | void TFT_DrawScrolledBitmap(uint16_t x0, uint16_t y0, uint16_t area_width, uint16_t area_height, 99 | const uint8_t *bitmap, uint16_t bm_width, int16_t offset, uint8_t gap, uint16_t bg_color, uint16_t fg_color); 100 | void TFT_DrawPixmap(uint16_t x0, uint16_t y0, uint16_t area_width, uint16_t area_height, 101 | const uint8_t *pixmap, uint16_t pm_width, uint8_t depth, uint16_t palette[]); 102 | void TFT_DrawThickLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t thickness, uint16_t color); 103 | void TFT_DrawVarThickLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, LineThickness thickness, uint16_t color); 104 | 105 | // Convert touch coordinates according with rotation. Use with FT6x36 capacitive touch screen. 106 | void TFT_Touch_Adjust_Rotation_XY(uint16_t *x, uint16_t *y); 107 | 108 | // Functions to setup display 109 | void TFT_Setup(uint16_t generic_width, uint16_t generic_height, uint8_t madctl[4]); 110 | void TFT_SetRotation(tRotation rotation); 111 | uint16_t TFT_ReadPixel(uint16_t x, uint16_t y, bool is16bit_color); 112 | void TFT_SetAttrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); 113 | void TFT_StartDrawArea(uint16_t x0, uint16_t y0, uint16_t width, uint16_t height); 114 | 115 | #ifdef __cplusplus 116 | } 117 | #endif 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /SRC/TFT/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * config.h 3 | * 4 | * Created on: 4 Nov 2022 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef _TFT_CONFIG_H_ 9 | #define _TFT_CONFIG_H_ 10 | 11 | #include "main.h" 12 | 13 | // Un-comment the following line to include code for BMP and JPEG drawings, external FAT drive required 14 | //#define TFT_BMP_JPEG_ENABLE 15 | 16 | 17 | // ========================SPI Interface definitions==================== 18 | #define TFT_SPI_PORT hspi1 19 | extern SPI_HandleTypeDef TFT_SPI_PORT; 20 | 21 | // To enable DMA support, Un-comment the next line 22 | #define TFT_USE_DMA 1 23 | // =========================End of SPI Interface definitions============ 24 | 25 | /* 26 | // ========================FSMC Interface definitions=================== 27 | //#define FSMC_8_BITS (1) 28 | #define FSMC_16_BITS_NMIPI (1) 29 | #define FSMC_LCD_CMD 0x60000000 30 | // LCD DATA Bit Mask, FSMC_A16 = 1 0000 0000 0000 0000 31 | #define FSMC_DATA_MASK 0x10000 32 | // ========================End of FSMC Interface definitions============ 33 | */ 34 | // To enable gamma color correction profile, Un-comment the next line 35 | // Works with NT35510 and SSD1963 displays 36 | #define APPLY_GAMMA_PROFILE (1) 37 | 38 | #define TFT_Delay(a) HAL_Delay(a); 39 | 40 | #endif // _TFT_CONFIG_H 41 | -------------------------------------------------------------------------------- /SRC/TFT/gamma.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gamma.c 3 | * 4 | * Created on: 21 May, 2024 5 | * Author: Alex 6 | */ 7 | 8 | #include "gamma.h" 9 | #include "config.h" 10 | #include "interface.h" 11 | 12 | #ifdef APPLY_GAMMA_PROFILE 13 | 14 | typedef enum { 15 | CMD_GAMMA_D1 = 0xD1, 16 | CMD_GAMMA_D2 = 0xD2, 17 | CMD_GAMMA_D3 = 0xD3, 18 | CMD_GAMMA_D4 = 0xD4, 19 | CMD_GAMMA_D5 = 0xD5, 20 | CMD_GAMMA_D6 = 0xD6, 21 | } GAMMA_CMD; 22 | 23 | void TFT_Gamma_NT35510(void) { 24 | static const uint8_t g1[52] = { 0x00, 0x37, 0x00, 0x52, 0x00, 0x7B, 0x00, 0x99, 0x00, 0xB1, 25 | 0x00, 0xD2, 0x00, 0xF6, 0x01, 0x27, 0x01, 0x4E, 0x01, 0x8C, 26 | 0x01, 0xBE, 0x02, 0x0B, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x7E, 27 | 0x02, 0xBC, 0x02, 0xE1, 0x03, 0x10, 0x03, 0x31, 0x03, 0x5A, 28 | 0x03, 0x73, 0x03, 0x94, 0x03, 0x9F, 0x03, 0xB3, 0x03, 0xB9, 0x03, 0xC1 }; 29 | static const uint8_t g2[52] = { 0x00, 0x37, 0x00, 0x52, 0x00, 0x7B, 0x00, 0x99, 0x00, 0xB1, 30 | 0x00, 0xD2, 0x00, 0xF6, 0x01, 0x27, 0x01, 0x4E, 0x01, 0x8C, 31 | 0x01, 0xBE, 0x02, 0x0B, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x7E, 32 | 0x02, 0xBC, 0x02, 0xE1, 0x03, 0x10, 0x03, 0x31, 0x03, 0x5A, 33 | 0x03, 0x73, 0x03, 0x94, 0x03, 0x9F, 0x03, 0xB3, 0x03, 0xB9, 0x03, 0xC1 }; 34 | static const uint8_t g3[52] = { 0x00, 0x37, 0x00, 0x52, 0x00, 0x7B, 0x00, 0x99, 0x00, 0xB1, 35 | 0x00, 0xD2, 0x00, 0xF6, 0x01, 0x27, 0x01, 0x4E, 0x01, 0x8C, 36 | 0x01, 0xBE, 0x02, 0x0B, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x7E, 37 | 0x02, 0xBC, 0x02, 0xE1, 0x03, 0x10, 0x03, 0x31, 0x03, 0x5A, 38 | 0x03, 0x73, 0x03, 0x94, 0x03, 0x9F, 0x03, 0xB3, 0x03, 0xB9, 0x03, 0xC1}; 39 | static const uint8_t g4[52] = { 0x00, 0x37, 0x00, 0x52, 0x00, 0x7B, 0x00, 0x99, 0x00, 0xB1, 40 | 0x00, 0xD2, 0x00, 0xF6, 0x01, 0x27, 0x01, 0x4E, 0x01, 0x8C, 41 | 0x01, 0xBE, 0x02, 0x0B, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x7E, 42 | 0x02, 0xBC, 0x02, 0xE1, 0x03, 0x10, 0x03, 0x31, 0x03, 0x5A, 43 | 0x03, 0x73, 0x03, 0x94, 0x03, 0x9F, 0x03, 0xB3, 0x03, 0xB9, 0x03, 0xC1}; 44 | static const uint8_t g5[52] = { 0x00, 0x37, 0x00, 0x52, 0x00, 0x7B, 0x00, 0x99, 0x00, 0xB1, 45 | 0x00, 0xD2, 0x00, 0xF6, 0x01, 0x27, 0x01, 0x4E, 0x01, 0x8C, 46 | 0x01, 0xBE, 0x02, 0x0B, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x7E, 47 | 0x02, 0xBC, 0x02, 0xE1, 0x03, 0x10, 0x03, 0x31, 0x03, 0x5A, 48 | 0x03, 0x73, 0x03, 0x94, 0x03, 0x9F, 0x03, 0xB3, 0x03, 0xB9, 0x03, 0xC1}; 49 | static const uint8_t g6[52] = { 0x00, 0x37, 0x00, 0x52, 0x00, 0x7B, 0x00, 0x99, 0x00, 0xB1, 50 | 0x00, 0xD2, 0x00, 0xF6, 0x01, 0x27, 0x01, 0x4E, 0x01, 0x8C, 51 | 0x01, 0xBE, 0x02, 0x0B, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x7E, 52 | 0x02, 0xBC, 0x02, 0xE1, 0x03, 0x10, 0x03, 0x31, 0x03, 0x5A, 53 | 0x03, 0x73, 0x03, 0x94, 0x03, 0x9F, 0x03, 0xB3, 0x03, 0xB9, 0x03, 0xC1}; 54 | 55 | TFT_Command(CMD_GAMMA_D1, g1, 52); 56 | TFT_Command(CMD_GAMMA_D2, g2, 52); 57 | TFT_Command(CMD_GAMMA_D3, g3, 52); 58 | TFT_Command(CMD_GAMMA_D4, g4, 52); 59 | TFT_Command(CMD_GAMMA_D5, g5, 52); 60 | TFT_Command(CMD_GAMMA_D6, g6, 52); 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /SRC/TFT/gamma.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gamma.h 3 | * 4 | * Created on: 21 May 2024 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef _GAMMA_H_ 9 | #define _GAMMA_H_ 10 | 11 | void TFT_Gamma_NT35510(void); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /SRC/TFT/interface.c: -------------------------------------------------------------------------------- 1 | /* 2 | * interface.c 3 | * 4 | * Created on: 4 Nov 2022 5 | * Author: Alex 6 | */ 7 | 8 | #include "config.h" 9 | #include "interface.h" 10 | #include "common.h" 11 | 12 | // Hardware specific low-level function used to work with the display depending on the display interface type 13 | #ifdef TFT_SPI_PORT 14 | static t_TFT_Reset pReset = TFT_SPI_Reset; 15 | static t_TFT_Command pCommand = TFT_SPI_Command; 16 | static t_TFT_Data_Mode pDataMode = TFT_SPI_DATA_MODE; 17 | static t_TFT_Read_Data pReadData = TFT_SPI_ReadData; 18 | static t_TFT_Color_Block_Init pColorBlockInit = TFT_SPI_ColorBlockInit; 19 | static t_TFT_Color_Block_Send pColorBlockSend = TFT_SPI_ColorBlockSend_16bits; 20 | static t_TFT_Color_Block_Flush pColorBlockFlush = TFT_SPI_ColorBlockFlush; 21 | static t_TFT_Draw_Pixel pDrawPixel = TFT_DrawPixel_16bits; 22 | 23 | // SPI Interface 24 | void TFT_InterfaceSetup(tTFT_PIXEL_BITS data_size, tTFT_INT_FUNC *pINT) { 25 | if (pINT) { 26 | pReset = (pINT->pReset)?pINT->pReset:TFT_SPI_Reset; 27 | pCommand = (pINT->pCommand)?pINT->pCommand:TFT_SPI_Command; 28 | pDataMode = (pINT->pDataMode)?pINT->pDataMode:TFT_SPI_DATA_MODE; 29 | pReadData = (pINT->pReadData)?pINT->pReadData:TFT_SPI_ReadData; 30 | pColorBlockInit = (pINT->pColorBlockInit)?pINT->pColorBlockInit:TFT_SPI_ColorBlockInit; 31 | pColorBlockFlush = (pINT->pColorBlockFlush)?pINT->pColorBlockFlush:TFT_SPI_ColorBlockFlush; 32 | if (data_size == TFT_16bits) { 33 | pColorBlockSend = (pINT->pColorBlockSend)?pINT->pColorBlockSend:TFT_SPI_ColorBlockSend_16bits; 34 | pDrawPixel = (pINT->pDrawPixel)?pINT->pDrawPixel:TFT_DrawPixel_16bits; 35 | } else { 36 | pColorBlockSend = (pINT->pColorBlockSend)?pINT->pColorBlockSend:TFT_SPI_ColorBlockSend_18bits; 37 | pDrawPixel = (pINT->pDrawPixel)?pINT->pDrawPixel:TFT_DrawPixel_18bits; 38 | } 39 | } else { 40 | pColorBlockSend = (data_size == TFT_16bits)?TFT_SPI_ColorBlockSend_16bits:TFT_SPI_ColorBlockSend_18bits; 41 | pDrawPixel = (data_size == TFT_16bits)?TFT_DrawPixel_16bits:TFT_DrawPixel_18bits; 42 | } 43 | } 44 | #endif 45 | 46 | #ifdef FSMC_LCD_CMD 47 | static t_TFT_Reset pReset = TFT_FSMC_Reset; 48 | static t_TFT_Command pCommand = TFT_FSMC_Command; 49 | static t_TFT_Data_Mode pDataMode = TFT_FSMC_DATA_MODE; 50 | static t_TFT_Read_Data pReadData = TFT_FSMC_ReadData; 51 | static t_TFT_Color_Block_Init pColorBlockInit = TFT_FSMC_ColorBlockInit; 52 | static t_TFT_Color_Block_Send pColorBlockSend = TFT_FSMC_ColorBlockSend_16bits; 53 | static t_TFT_Color_Block_Flush pColorBlockFlush = TFT_FSMC_ColorBlockFlush; 54 | static t_TFT_Draw_Pixel pDrawPixel = TFT_DrawPixel_16bits; 55 | 56 | // FSMC Interface 57 | void TFT_InterfaceSetup(tTFT_PIXEL_BITS data_size, tTFT_INT_FUNC *pINT) { 58 | if (pINT) { 59 | pReset = (pINT->pReset)?pINT->pReset:TFT_FSMC_Reset; 60 | pCommand = (pINT->pCommand)?pINT->pCommand:TFT_FSMC_Command; 61 | pDataMode = (pINT->pDataMode)?pINT->pDataMode:TFT_FSMC_DATA_MODE; 62 | pReadData = (pINT->pReadData)?pINT->pReadData:TFT_FSMC_ReadData; 63 | pColorBlockInit = (pINT->pColorBlockInit)?pINT->pColorBlockInit:TFT_FSMC_ColorBlockInit; 64 | pColorBlockFlush = (pINT->pColorBlockFlush)?pINT->pColorBlockFlush:TFT_FSMC_ColorBlockFlush; 65 | if (data_size == TFT_16bits) { 66 | pColorBlockSend = (pINT->pColorBlockSend)?pINT->pColorBlockSend:TFT_FSMC_ColorBlockSend_16bits; 67 | pDrawPixel = (pINT->pDrawPixel)?pINT->pDrawPixel:TFT_FSMC_DrawPixel_16bits; 68 | } else { 69 | pColorBlockSend = (pINT->pColorBlockSend)?pINT->pColorBlockSend:TFT_FSMC_ColorBlockSend_18bits; 70 | pDrawPixel = (pINT->pDrawPixel)?pINT->pDrawPixel:TFT_FSMC_DrawPixel_18bits; 71 | } 72 | } else { 73 | pColorBlockSend = (data_size == TFT_16bits)?TFT_FSMC_ColorBlockSend_16bits:TFT_FSMC_ColorBlockSend_18bits; 74 | pDrawPixel = (data_size == TFT_16bits)?TFT_FSMC_DrawPixel_16bits:TFT_FSMC_DrawPixel_18bits; 75 | } 76 | } 77 | #endif 78 | 79 | void TFT_Command(uint8_t cmd, const uint8_t* buff, size_t buff_size) { 80 | (*pCommand)(cmd, buff, buff_size); 81 | } 82 | 83 | void IFACE_DataMode(void) { 84 | (*pDataMode)(); 85 | } 86 | 87 | void IFACE_ColorBlockInit(void) { 88 | (*pColorBlockInit)(); 89 | } 90 | 91 | void TFT_ColorBlockSend(uint16_t color, uint32_t size) { 92 | (*pColorBlockSend)(color, size); 93 | } 94 | 95 | void TFT_FinishDrawArea(void) { 96 | (*pColorBlockFlush)(); // Flush color block buffer 97 | } 98 | 99 | void IFACE_DrawPixel(uint16_t x, uint16_t y, uint16_t color) { 100 | (*pDrawPixel)(x, y, color); 101 | } 102 | 103 | bool TFT_ReadData(uint8_t cmd, uint8_t *data, uint16_t size) { 104 | return (*pReadData)(cmd, data, size); 105 | } 106 | 107 | void TFT_DEF_Reset(void) { 108 | (*pReset)(); 109 | } 110 | 111 | // Turn display to the sleep mode. Make sure particular display command is the same 112 | void TFT_DEF_SleepIn(void) { 113 | (*pCommand)(0x10, 0, 0); 114 | TFT_Delay(5); 115 | } 116 | 117 | // Deactivates sleep mode. Make sure particular display command is the same 118 | void TFT_DEF_SleepOut(void) { 119 | (*pCommand)(0x11, 0, 0); 120 | TFT_Delay(120); 121 | } 122 | 123 | // Turn display to Inversion mode. Make sure particular display command is the same 124 | void TFT_DEF_InvertDisplay(bool on) { 125 | uint8_t cmd = on?0x21:0x20; 126 | (*pCommand)(cmd, 0, 0); 127 | } 128 | 129 | // Turn display on or off. Make sure particular display command is the same 130 | void TFT_DEF_DisplayOn(bool on) { 131 | uint8_t cmd = on?0x29:0x28; 132 | (*pCommand)(cmd, 0, 0); 133 | } 134 | 135 | // Turn display to idle/normal mode. Make sure particular display command is the same 136 | void TFT_DEF_IdleMode(bool on) { 137 | uint8_t cmd = on?0x39:0x38; 138 | (*pCommand)(cmd, 0, 0); 139 | } 140 | 141 | // Draws single pixel using display working in 16 bits mode 142 | void TFT_DrawPixel_16bits(uint16_t x, uint16_t y, uint16_t color) { 143 | if ((x >=TFT_Width()) || (y >=TFT_Height())) return; 144 | uint8_t clr[2] = { (color>>8) & 0xFF, color & 0xFF }; 145 | TFT_SetAttrWindow(x, y, x, y); 146 | TFT_Command(0x2C, clr, 2); 147 | } 148 | 149 | // Draws single pixel using display working in 18 bits SPI mode (ILI9488 supports 3 bits or 18 bits per pixel in SPI mode) 150 | void TFT_DrawPixel_18bits(uint16_t x, uint16_t y, uint16_t color) { 151 | if ((x >=TFT_Width()) || (y >=TFT_Height())) return; 152 | uint8_t clr[3] = { (color & 0xF800) >> 8, (color & 0x7E0) >> 3, (color & 0x1F) << 3 }; 153 | TFT_SetAttrWindow(x, y, x, y); 154 | TFT_Command(0x2C, clr, 3); // write to RAM 155 | } 156 | -------------------------------------------------------------------------------- /SRC/TFT/interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * interface.h 3 | * 4 | * Created on: 4 Nov 2022 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef _INTERFACE_H_ 9 | #define _INTERFACE_H_ 10 | 11 | #include 12 | #include "main.h" 13 | #include "ll_spi.h" 14 | #include "ll_fsmc.h" 15 | 16 | // Hardware specific low-level function used to work with the display depending on the display interface type 17 | typedef void (*t_TFT_Reset)(void); 18 | typedef void (*t_TFT_Command)(uint8_t cmd, const uint8_t* buff, size_t buff_size); 19 | typedef void (*t_TFT_Data_Mode)(void); 20 | typedef bool (*t_TFT_Read_Data)(uint8_t cmd, uint8_t *data, uint16_t size); 21 | typedef void (*t_TFT_Color_Block_Init)(void); 22 | typedef void (*t_TFT_Color_Block_Send)(uint16_t color, uint32_t size); 23 | typedef void (*t_TFT_Color_Block_Flush)(void); 24 | typedef void (*t_TFT_Draw_Pixel)(uint16_t x, uint16_t y, uint16_t color); 25 | 26 | typedef struct { 27 | t_TFT_Reset pReset; 28 | t_TFT_Command pCommand; 29 | t_TFT_Data_Mode pDataMode; 30 | t_TFT_Read_Data pReadData; 31 | t_TFT_Color_Block_Init pColorBlockInit; 32 | t_TFT_Color_Block_Send pColorBlockSend; 33 | t_TFT_Color_Block_Flush pColorBlockFlush; 34 | t_TFT_Draw_Pixel pDrawPixel; 35 | } tTFT_INT_FUNC; 36 | 37 | typedef enum { 38 | TFT_16bits = 0, 39 | TFT_18bits = 1 40 | } tTFT_PIXEL_BITS; 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | // Function that setups connection 47 | void TFT_InterfaceSetup(tTFT_PIXEL_BITS data_size, tTFT_INT_FUNC *pINT); 48 | 49 | // Interface functions 50 | void TFT_Command(uint8_t cmd, const uint8_t* buff, size_t buff_size); 51 | void TFT_ColorBlockSend(uint16_t color, uint32_t size); 52 | void TFT_FinishDrawArea(); 53 | bool TFT_ReadData(uint8_t cmd, uint8_t *data, uint16_t size); 54 | void TFT_DrawPixel_16bits(uint16_t x, uint16_t y, uint16_t color); 55 | void TFT_DrawPixel_18bits(uint16_t x, uint16_t y, uint16_t color); 56 | 57 | // Interface functions 58 | void IFACE_DataMode(void); 59 | void IFACE_ColorBlockInit(void); 60 | void IFACE_DrawPixel(uint16_t x, uint16_t y, uint16_t color); 61 | 62 | // Functions to manage display 63 | void TFT_DEF_Reset(void); 64 | void TFT_DEF_SleepIn(void); 65 | void TFT_DEF_SleepOut(void); 66 | void TFT_DEF_InvertDisplay(bool on); 67 | void TFT_DEF_DisplayOn(bool on); 68 | void TFT_DEF_IdleMode(bool on); 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif 73 | 74 | #endif /* INTERFACE_H_ */ 75 | -------------------------------------------------------------------------------- /SRC/TFT/ll_fsmc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ll_fsmc.c 3 | * 4 | * Created on: 4 Nov 2022 5 | * Author: Alex 6 | */ 7 | 8 | #include "ll_fsmc.h" 9 | 10 | #ifdef FSMC_LCD_CMD 11 | 12 | #ifdef FSMC_8_BITS 13 | static uint8_t *LCD_CMD_PORT = (uint8_t *)FSMC_LCD_CMD; 14 | static uint8_t *LCD_DATA_PORT = (uint8_t *)(FSMC_LCD_CMD | FSMC_DATA_MASK); 15 | #else 16 | static uint16_t *LCD_CMD_PORT = (uint16_t *)FSMC_LCD_CMD; 17 | static uint16_t *LCD_DATA_PORT = (uint16_t *)(FSMC_LCD_CMD | (FSMC_DATA_MASK) << 1); 18 | #endif 19 | 20 | // Hard reset pin management 21 | static void TFT_FSMC_RST(GPIO_PinState state) { 22 | HAL_GPIO_WritePin(TFT_RESET_GPIO_Port, TFT_RESET_Pin, state); 23 | } 24 | 25 | // HARDWARE RESET 26 | void TFT_FSMC_Reset(void) { 27 | TFT_FSMC_RST(GPIO_PIN_RESET); 28 | HAL_Delay(200); 29 | TFT_FSMC_RST(GPIO_PIN_SET); 30 | } 31 | 32 | static void TFT_FSMC_SetAttrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { 33 | uint8_t data[4]; 34 | 35 | // column address set 36 | data[0] = (x0 >> 8) & 0xFF; 37 | data[1] = x0 & 0xFF; 38 | data[2] = (x1 >> 8) & 0xFF; 39 | data[3] = x1 & 0xFF; 40 | TFT_FSMC_Command(0x2A, data, 4); 41 | 42 | // row address set 43 | data[0] = (y0 >> 8) & 0xFF; 44 | data[1] = y0 & 0xFF; 45 | data[2] = (y1 >> 8) & 0xFF; 46 | data[3] = y1 & 0xFF; 47 | TFT_FSMC_Command(0x2B, data, 4); 48 | } 49 | 50 | #ifdef FSMC_8_BITS 51 | // Send command (byte) to the Display followed by the command arguments 52 | void TFT_FSMC_Command(uint8_t cmd, const uint8_t* buff, size_t buff_size) { 53 | *LCD_CMD_PORT = cmd; 54 | if (buff && buff_size > 0) { 55 | for (uint16_t i = 0; i < buff_size; ++i) { 56 | *LCD_DATA_PORT = buff[i]; 57 | } 58 | } 59 | } 60 | 61 | bool TFT_FSMC_ReadData(uint8_t cmd, uint8_t *data, uint16_t size) { 62 | if (!data || size == 0) return 0; 63 | 64 | *LCD_CMD_PORT = cmd; 65 | for (uint16_t i = 0; i < size; ++i) { 66 | data[i] = *LCD_DATA_PORT; 67 | } 68 | return true; 69 | } 70 | 71 | void TFT_FSMC_ColorBlockSend_16bits(uint16_t color, uint32_t size) { 72 | uint8_t clr_hi = color >> 8; 73 | uint8_t clr_lo = color & 0xff; 74 | for (uint32_t i = 0; i < size; ++i) { 75 | *LCD_DATA_PORT = clr_hi; 76 | *LCD_DATA_PORT = clr_lo; 77 | } 78 | } 79 | 80 | void TFT_FSMC_ColorBlockSend_18bits(uint16_t color, uint32_t size) { 81 | // Convert to 18-bits color 82 | uint8_t r = (color & 0xF800) >> 8; 83 | uint8_t g = (color & 0x7E0) >> 3; 84 | uint8_t b = (color & 0x1F) << 3; 85 | for (uint32_t i = 0; i < size; ++i) { 86 | *LCD_DATA_PORT = r; 87 | *LCD_DATA_PORT = g; 88 | *LCD_DATA_PORT = b; 89 | } 90 | } 91 | #endif 92 | 93 | #ifdef FSMC_16_BITS 94 | // Send command (byte) to the Display followed by the command arguments 95 | void TFT_FSMC_Command(uint8_t cmd, const uint8_t* buff, size_t buff_size) { 96 | *LCD_CMD_PORT = cmd; // First send the command 97 | if (buff && buff_size > 0) { 98 | for (uint16_t i = 0; i < buff_size; ++i) { // Then send the arguments (if they are exist) 99 | *LCD_DATA_PORT = buff[i]; 100 | } 101 | } 102 | } 103 | 104 | void TFT_FSMC_NT35510_Command(uint8_t cmd, const uint8_t* buff, size_t buff_size) { 105 | uint16_t f_cmd = cmd << 8; 106 | if (buff && buff_size > 0) { 107 | for (uint16_t i = 0; i < buff_size; ++i) { 108 | *LCD_CMD_PORT = f_cmd ++; 109 | *LCD_DATA_PORT = buff[i]; 110 | } 111 | } else { 112 | *LCD_CMD_PORT = f_cmd; // Single command without argument 113 | } 114 | } 115 | 116 | // Draws single pixel using display working in 16 bits mode 117 | void TFT_FSMC_DrawPixel_16bits(uint16_t x, uint16_t y, uint16_t color) { 118 | TFT_FSMC_SetAttrWindow(x, y, x, y); 119 | *LCD_CMD_PORT = 0x2C; 120 | *LCD_DATA_PORT = color; 121 | } 122 | 123 | // Draws single pixel using display working in 18 bits mode 124 | void TFT_FSMC_DrawPixel_18bits(uint16_t x, uint16_t y, uint16_t color) { 125 | uint16_t rg = (color & 0xF800); 126 | rg |= (color & 0x7E0) >> 3; 127 | uint16_t b = (color & 0x1F) << 11; 128 | TFT_FSMC_SetAttrWindow(x, y, x, y); 129 | *LCD_CMD_PORT = 0x2C; 130 | *LCD_DATA_PORT = rg; 131 | *LCD_DATA_PORT = b; 132 | } 133 | 134 | // Draws single pixel using display working in 16 bits mode; High-byte command 135 | void TFT_FSMC_HIGH_DrawPixel_16bits(uint16_t x, uint16_t y, uint16_t color) { 136 | TFT_FSMC_SetAttrWindow(x, y, x, y); 137 | *LCD_CMD_PORT = 0x2C00; 138 | *LCD_DATA_PORT = color; 139 | } 140 | 141 | // Draws single pixel using display working in 18 bits mode; High-byte command 142 | void TFT_FSMC_HIGH_DrawPixel_18bits(uint16_t x, uint16_t y, uint16_t color) { 143 | uint16_t rg = (color & 0xF800); 144 | rg |= (color & 0x7E0) >> 3; 145 | uint16_t b = (color & 0x1F) << 11; 146 | TFT_FSMC_SetAttrWindow(x, y, x, y); 147 | *LCD_CMD_PORT = 0x2C00; 148 | *LCD_DATA_PORT = rg; 149 | *LCD_DATA_PORT = b; 150 | } 151 | 152 | bool TFT_FSMC_ReadData(uint8_t cmd, uint8_t *data, uint16_t size) { 153 | if (!data || size == 0) return 0; 154 | 155 | *LCD_CMD_PORT = cmd << 8; 156 | for (uint16_t i = 0; i < size / 2; ++i) { 157 | uint16_t value = *LCD_DATA_PORT; 158 | data[i++] = value >> 8; 159 | data[i] = value & 0xFF; 160 | } 161 | return true; 162 | } 163 | 164 | void TFT_FSMC_ColorBlockSend_16bits(uint16_t color, uint32_t size) { 165 | for (uint32_t i = 0; i < size; ++i) { 166 | *LCD_DATA_PORT = color; 167 | } 168 | } 169 | 170 | void TFT_FSMC_ColorBlockSend_18bits(uint16_t color, uint32_t size) { 171 | uint8_t r = (color & 0xF800) >> 8; 172 | uint8_t g = (color & 0x7E0) >> 3; 173 | uint8_t b = (color & 0x1F) << 3; 174 | // Send data by couple of pixels sending 3 words: R1-G1, B1-R2, G2-B2 175 | uint32_t copules = (size + 1) >> 1; 176 | for (uint32_t i = 0; i < copules; ++i) { 177 | *LCD_DATA_PORT = ((uint16_t)r << 8) | g; 178 | *LCD_DATA_PORT = ((uint16_t)b << 8) | r; 179 | *LCD_DATA_PORT = ((uint16_t)g << 8) | b; 180 | } 181 | } 182 | #endif 183 | 184 | void TFT_FSMC_DATA_MODE(void) { } 185 | void TFT_FSMC_ColorBlockInit(void) { } 186 | void TFT_FSMC_ColorBlockFlush(void) { } 187 | 188 | #endif // FSMC_LCD_CMD 189 | -------------------------------------------------------------------------------- /SRC/TFT/ll_fsmc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ll_fsmc.h 3 | * 4 | * Created on: 4 Nov 2022 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef _LL_FSMC_H_ 9 | #define _LL_FSMC_H_ 10 | 11 | #include 12 | #include "main.h" 13 | #include "config.h" 14 | 15 | #ifdef FSMC_LCD_CMD 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | void TFT_FSMC_Reset(void); 22 | void TFT_FSMC_Command(uint8_t cmd, const uint8_t* buff, size_t buff_size); 23 | void TFT_FSMC_NT35510_Command(uint8_t cmd, const uint8_t* buff, size_t buff_size); 24 | void TFT_FSMC_DrawPixel_16bits(uint16_t x, uint16_t y, uint16_t color); 25 | void TFT_FSMC_DrawPixel_18bits(uint16_t x, uint16_t y, uint16_t color); 26 | void TFT_FSMC_HIGH_DrawPixel_16bits(uint16_t x, uint16_t y, uint16_t color); 27 | void TFT_FSMC_HIGH_DrawPixel_18bits(uint16_t x, uint16_t y, uint16_t color); 28 | void TFT_FSMC_DATA_MODE(void); 29 | bool TFT_FSMC_ReadData(uint8_t cmd, uint8_t *data, uint16_t size); 30 | void TFT_FSMC_ColorBlockInit(void); 31 | void TFT_FSMC_ColorBlockSend_16bits(uint16_t color, uint32_t size); 32 | void TFT_FSMC_ColorBlockSend_18bits(uint16_t color, uint32_t size); 33 | void TFT_FSMC_ColorBlockFlush(void); 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #endif // FSMC_LCD_CMD 40 | 41 | #endif // _LL_FSMC_H_ 42 | -------------------------------------------------------------------------------- /SRC/TFT/ll_spi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * low_level.h 3 | * 4 | * Created on: Nov 20, 2020 5 | * Author: Alex 6 | * 7 | * Low-level functions to deal with TFT displays 8 | * 9 | */ 10 | #ifndef _LL_SPI_H 11 | #define _LL_SPI_H 12 | 13 | #include 14 | #include "main.h" 15 | #include "config.h" 16 | 17 | #ifdef TFT_SPI_PORT 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | void TFT_SPI_Reset(void); 24 | void TFT_SPI_Command(uint8_t cmd, const uint8_t* buff, size_t buff_size); 25 | void TFT_SPI_DATA_MODE(void); 26 | bool TFT_SPI_ReadData(uint8_t cmd, uint8_t *data, uint16_t size); 27 | void TFT_SPI_ColorBlockInit(void); 28 | void TFT_SPI_ColorBlockSend_16bits(uint16_t color, uint32_t size); 29 | void TFT_SPI_ColorBlockSend_18bits(uint16_t color, uint32_t size); 30 | void TFT_SPI_ColorBlockFlush(void); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif // TFT_SPI_PORT 37 | #endif // _LL_SPI_H 38 | -------------------------------------------------------------------------------- /SRC/TFT/picture.h: -------------------------------------------------------------------------------- 1 | /* 2 | * picture.h 3 | * 4 | * Created on: May 27 2020 5 | * Author: Alex 6 | */ 7 | 8 | #ifdef TFT_BMP_JPEG_ENABLE 9 | 10 | #ifndef _PICTURE_H_ 11 | #define _PICTURE_H_ 12 | 13 | #ifndef __cplusplus 14 | #include 15 | #endif 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | bool TFT_jpegAllocate(void); 22 | void TFT_jpegDeallocate(void); 23 | bool TFT_DrawJPEG(const char *filename, int16_t x, int16_t y); 24 | 25 | /* 26 | * Draw clipped JPEG file image. Put Upper-Left corner of JPEG image to (x, y) 27 | * and draw only a rectangular area with coordinates (area_x, area_y) and size of area_width, area_height 28 | * As slow as a drawJPEG() function because need to read whole jpeg file 29 | */ 30 | bool TFT_ClipJPEG(const char *filename, int16_t x, int16_t y, uint16_t area_x, uint16_t area_y, uint16_t area_width, uint16_t area_height); 31 | 32 | /* 33 | * Get BMP image size 34 | * Return value 32-bits word: high 16-bits word is width, low 16-bits word is height 35 | */ 36 | uint32_t TFT_BMPsize(const char *filename); 37 | 38 | /* Draw clipped BMP file image. Put Upper-Left corner of BMP image to (x, y) 39 | * and draw only a rectangular area with coordinates (area_x, area_y) and size of area_width, area_height 40 | * Only two BMP formats are supported: 24-bit per pixel, not-compressed and 16-bit per pixel R5-G6-B5 41 | */ 42 | bool TFT_ClipBMP(const char *filename, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t bmp_x, uint16_t bmp_y); 43 | 44 | /* 45 | * Draw scrolled bitmap on BMP background loaded from file 46 | */ 47 | bool TFT_ScrollBitmapOverBMP(const char *filename, int16_t x, int16_t y, uint16_t area_x, uint16_t area_y, uint16_t area_width, uint16_t area_height, 48 | const uint8_t *bitmap, uint16_t bm_width, int16_t offset, uint8_t gap, uint16_t txt_color); 49 | 50 | /* 51 | * Load BMP file image at the given coordinates (x, y) to the memory region. 52 | * The memory region has dimensions rw and rh pixels 53 | * Both coordinates can be less than zero. In this case, top-left area of the BMP image will be clipped 54 | * If use_transparent is true, do not load the transparent color from BMP file 55 | * Only two BMP formats are supported: 24-bit per pixel, not-compressed and 16-bit per pixel R5-G6-B5 56 | * For best performance, save BMP file as 16-bits R6-G5-B6 format and flipped row order 57 | */ 58 | bool TFT_LoadBMP(uint16_t region[], uint16_t rw, uint16_t rh, const char *filename, int16_t bmp_x, int16_t bmp_y, 59 | uint16_t transparent, bool use_transparent); 60 | 61 | /* 62 | * Draw the memory region to the screen 63 | */ 64 | void TFT_DrawRegion(uint16_t x, uint16_t y, uint16_t region[], uint16_t rw, uint16_t rh); 65 | 66 | /* 67 | * Scroll bitmap (usually text line) over region and draw the result on the screen 68 | * Speed-up the scrolling string over background image 69 | */ 70 | void TFT_ScrollBitmapOverRegion(uint16_t x, uint16_t y, uint16_t region[], uint16_t rw, uint16_t rh, uint16_t y_offset, 71 | const uint8_t *bitmap, uint16_t bm_width, uint16_t bm_height, int16_t offset, uint8_t gap, uint16_t txt_color); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /SRC/TFT/pixmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pixmap.h 3 | * 4 | * Created on: Sep 09 2021 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef _PIXMAP_H_ 9 | #define _PIXMAP_H_ 10 | 11 | #include "main.h" 12 | #include 13 | 14 | /* 15 | * Pixmap is a multi-color icon with predefined palette of colors. 16 | * Supported depth: 1-8, number of colors 2, 4, 8, 16, ... 256 17 | * Each pixel coded by several bits in the pixmap-array. 18 | * Pixmap data structure is allocated in memory by malloc() call. 19 | * The space to store pixmap, pallete, width and height is allocated together 20 | * with the space for pixmap itself 21 | * Each pixmap instance is allocated just once 22 | * All other copies are just "links" to the main instance 23 | */ 24 | struct p_data { 25 | uint16_t w; // Pixmap width 26 | uint16_t h; // Pixmap height 27 | uint8_t links; // Number of the links to allocated area 28 | uint8_t depth; // The number of bits per pixel. Colors supported by pixmap is 2^depth 29 | uint8_t colors; // The number of colors actually allocated in the palette 30 | uint8_t data[0]; // Data array. The Last elements are palette colors (uint16_t per color code) 31 | }; 32 | 33 | class PIXMAP { 34 | public: 35 | PIXMAP(void) { } 36 | PIXMAP(uint16_t width, uint16_t height, uint8_t depth); 37 | PIXMAP(const PIXMAP &bm); 38 | PIXMAP& operator=(const PIXMAP &pm); 39 | ~PIXMAP(void); 40 | uint8_t* pixmap(void) { return (ds)?ds->data:0; } 41 | uint8_t depth(void) { return (ds)?ds->depth:0; } 42 | uint16_t width(void) { return (ds)?ds->w:0; } 43 | uint16_t height(void) { return (ds)?ds->h:0; } 44 | void clear(void); 45 | void setupPalette(uint16_t p[], uint8_t colors); 46 | uint8_t colorCode(uint16_t color); 47 | void drawPixelCode(uint16_t x, uint16_t y, uint8_t color_code); 48 | void drawPixel(uint16_t x, uint16_t y, uint16_t color); 49 | uint8_t pixelCode(uint16_t x, uint16_t y); 50 | uint16_t pixel(uint16_t x, uint16_t y); 51 | uint16_t* palette(void); 52 | void drawHLineCode(uint16_t x, uint16_t y, uint16_t length, uint8_t color_code); 53 | void drawHLine(uint16_t x, uint16_t y, uint16_t length, uint16_t color); 54 | void drawVLineCode(uint16_t x, uint16_t y, uint16_t length, uint8_t color_code); 55 | void drawVLine(uint16_t x, uint16_t y, uint16_t length, uint16_t color); 56 | void draw(uint16_t x, uint16_t y, uint16_t area_width, uint16_t area_height); 57 | void draw(uint16_t x, uint16_t y); 58 | private: 59 | struct p_data *ds = 0; 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /SRC/TFT/region.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * region.cpp 3 | * 4 | * Created on: 2023 MAR 12 5 | * Author: Alex 6 | */ 7 | #ifdef TFT_BMP_JPEG_ENABLE 8 | 9 | #include "region.h" 10 | #include "ff.h" 11 | #include "picture.h" 12 | 13 | 14 | REGION::REGION(uint32_t size) { 15 | if (size == 0) return; 16 | // Allocate memory to store whole data structure and the pixmap data 17 | ds = (struct r_data *)malloc(sizeof(struct r_data) + size * 2); // Size is the number of 16-bits words 18 | if (!ds) return; 19 | ds->w = 1; // Non-zero means the data allocated successfully 20 | ds->h = 1; 21 | ds->links = 1; 22 | ds->size = size; // Size is the number of 16-bits words 23 | } 24 | 25 | REGION::REGION(uint16_t width, uint16_t height) { 26 | if (width == 0 || height == 0) return; 27 | 28 | // Allocate memory to store whole data structure and the pixmap data 29 | ds = (struct r_data *)calloc(sizeof(struct r_data) + width * height, sizeof(uint16_t)); 30 | if (!ds) return; 31 | ds->w = width; 32 | ds->h = height; 33 | ds->links = 1; 34 | ds->size = (uint32_t)height * width; // Size is the number of 16-bits words 35 | } 36 | 37 | // Allocate the memory manually, in the CCM region for instance 38 | REGION::REGION(uint8_t* addr, uint16_t width, uint16_t height) { 39 | if (addr == 0 || width == 0 || height == 0) return; 40 | ds = (struct r_data *)addr; 41 | ds->w = width; 42 | ds->h = height; 43 | ds->links = 255; // Do not free the memory 44 | ds->size = (uint32_t)height * width; // Size is the number of 16-bits words 45 | } 46 | 47 | REGION::REGION(const REGION &rn) { 48 | this->ds = rn.ds; 49 | ++ds->links; 50 | } 51 | 52 | REGION& REGION::operator=(const REGION &rg) { 53 | if (this != &rg) { 54 | if (ds != 0 && --(ds->links) == 0) { 55 | free(ds); 56 | } 57 | this->ds = rg.ds; 58 | ++ds->links; 59 | } 60 | return *this; 61 | } 62 | 63 | REGION::~REGION(void) { 64 | if (!ds) return; 65 | if (--ds->links > 0) return; // Destroy yet another copy of the region 66 | free(ds); 67 | ds = 0; 68 | } 69 | 70 | uint32_t REGION::totalSize(void) { 71 | if (!ds) return 0; 72 | return sizeof(struct r_data) + ds->h * ds->w * 2; 73 | } 74 | 75 | void REGION::clear(void) { 76 | if (!ds) return; 77 | for (uint32_t i = 0; i < ds->size; ++i) 78 | ds->data[i] = 0; 79 | } 80 | 81 | // Setup picture size inside the region, cannot be greater than actual size 82 | bool REGION::setSize(uint16_t width, uint16_t height) { 83 | if (!ds) return false; 84 | if (ds->size < (uint32_t)width * height) return false; 85 | ds->w = width; 86 | ds->h = height; 87 | return true; 88 | } 89 | 90 | void REGION::draw(uint16_t x, uint16_t y) { 91 | if (!ds) return; 92 | TFT_DrawRegion(x, y, ds->data, ds->w, ds->h); 93 | } 94 | 95 | void REGION::fill(uint16_t color) { 96 | if (!ds) return; 97 | for (uint32_t i = 0; i < (ds->w * ds->h); ++i) 98 | ds->data[i] = color; 99 | } 100 | 101 | void REGION::drawPixel(uint16_t x, uint16_t y, uint16_t color) { 102 | if (!ds) return; 103 | if (x >= ds->w || y >= ds->h) return; 104 | uint32_t pos = ds->w * y + x; // pixel position in the data array 105 | ds->data[pos] = color; 106 | } 107 | 108 | uint16_t REGION::pixel(uint16_t x, uint16_t y) { 109 | if (!ds) return 0; 110 | if (x >= ds->w || y >= ds->h) return 0; 111 | uint32_t pos = ds->w * y + x; // pixel position in the data array 112 | return ds->data[pos]; 113 | } 114 | 115 | void REGION::drawHLine(uint16_t x, uint16_t y, uint16_t length, uint16_t color) { 116 | if (!ds) return; 117 | if (x >= ds->w || y >= ds->h) return; 118 | if (x + length >= ds->w) 119 | length = ds->w - x - 1; 120 | uint32_t pos = ds->w * y + x; 121 | for (uint16_t i = 0; i < length; ++i) 122 | ds->data[pos+i] = color; 123 | } 124 | 125 | void REGION::drawVLine(uint16_t x, uint16_t y, uint16_t length, uint16_t color) { 126 | if (!ds) return; 127 | if (x >= ds->w || y >= ds->h) return; 128 | if (y + length >= ds->h) 129 | length = ds->h - y - 1; 130 | uint32_t pos = ds->w * y + x; 131 | for (uint16_t i = 0; i < length; ++i) 132 | ds->data[pos + i*ds->w] = color; 133 | } 134 | 135 | bool REGION::loadBMP(const char *filename, int16_t bmp_x, int16_t bmp_y, uint16_t transparent, bool use_transparent) { 136 | if (!ds) return false; 137 | return TFT_LoadBMP(ds->data, ds->w, ds->h, filename, bmp_x, bmp_y, transparent, use_transparent); 138 | } 139 | 140 | void REGION::scrollBitmap(uint16_t x, uint16_t y, uint16_t y_offset, BITMAP &bm, int16_t offset, uint8_t gap, uint16_t color) { 141 | if (!ds) return; 142 | TFT_ScrollBitmapOverRegion(x, y, ds->data, ds->w, ds->h, y_offset, bm.bitmap(), bm.width(), bm.height(), offset, gap, color); 143 | } 144 | 145 | void REGION::drawIcon(uint16_t x, uint16_t y, BITMAP &bm, uint16_t color, BM_ALIGN x_align, BM_ALIGN y_align) { 146 | if (!ds) return; 147 | uint16_t y_offset = 0; 148 | if (ds->h > bm.height()) { 149 | if (y_align != align_left) 150 | y_offset = ds->h - bm.height(); 151 | if (y_align == align_center) 152 | y_offset >>= 1; 153 | } 154 | int16_t offset = 0; 155 | if (ds->w > bm.width()) { 156 | if (y_align != align_left) 157 | offset = ds->w - bm.width(); 158 | if (y_align == align_center) 159 | offset >>= 1; 160 | } 161 | // Negative offset means shift bitmap right 162 | TFT_ScrollBitmapOverRegion(x, y, ds->data, ds->w, ds->h, y_offset, bm.bitmap(), bm.width(), bm.height(), -offset, 0, color); 163 | } 164 | 165 | void REGION::drawIcon(uint16_t x, uint16_t y, uint16_t y_offset, BITMAP &bm, uint16_t color) { 166 | if (!ds) return; 167 | TFT_ScrollBitmapOverRegion(x, y, ds->data, ds->w, ds->h, y_offset, bm.bitmap(), bm.width(), bm.height(), 0, 0, color); 168 | } 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /SRC/TFT/region.h: -------------------------------------------------------------------------------- 1 | /* 2 | * region.h 3 | * 4 | * Created on: 2023 MAR 12 5 | * Author: Alex 6 | */ 7 | 8 | #ifndef _REGION_H_ 9 | #define _REGION_H_ 10 | 11 | #include "config.h" 12 | #include 13 | #include "bitmap.h" 14 | #include "u8g_font.h" 15 | 16 | #ifdef TFT_BMP_JPEG_ENABLE 17 | 18 | /* 19 | * Region is a full-color rectangular area to be drawn in the screen. 20 | * Region data structure is allocated in memory by malloc() call. 21 | * Each Region instance is allocated just once 22 | * All other copies are just "links" to the main instance 23 | */ 24 | struct r_data { 25 | uint16_t w; // Region active width 26 | uint16_t h; // Region active height 27 | uint16_t links; // Number of the links to allocated area 28 | uint32_t size; // Region full size (16-bits WORDS) 29 | uint16_t data[0]; // Data array 30 | }; 31 | 32 | class REGION { 33 | public: 34 | REGION(void) { } 35 | REGION(uint32_t size); 36 | REGION(uint16_t width, uint16_t height); 37 | REGION(uint8_t* addr, uint16_t width, uint16_t height); 38 | REGION(const REGION &rg); 39 | REGION& operator=(const REGION &rg); 40 | ~REGION(void); 41 | uint32_t totalSize(void); 42 | uint16_t* region(void) { return (ds)?ds->data:0; } 43 | uint16_t width(void) { return (ds)?ds->w:0; } 44 | uint16_t height(void) { return (ds)?ds->h:0; } 45 | uint32_t size(void) { return (ds)?ds->size:0; } 46 | void clear(); 47 | bool setSize(uint16_t width, uint16_t height); // Setup picture size inside the region, cannot be greater than actual size 48 | void draw(uint16_t x, uint16_t y); 49 | void fill(uint16_t color); 50 | void drawPixel(uint16_t x, uint16_t y, uint16_t color); 51 | uint16_t pixel(uint16_t x, uint16_t y); 52 | void drawHLine(uint16_t x, uint16_t y, uint16_t length, uint16_t color); 53 | void drawVLine(uint16_t x, uint16_t y, uint16_t length, uint16_t color); 54 | bool loadBMP(const char *filename, int16_t bmp_x, int16_t bmp_y, uint16_t transparent = 0, bool use_transparent = false); 55 | void drawIcon(uint16_t x, uint16_t y, BITMAP &bm, uint16_t color, BM_ALIGN x_align = align_left, BM_ALIGN y_align = align_left); 56 | void drawIcon(uint16_t x, uint16_t y, uint16_t y_offset, BITMAP &bm, uint16_t color); 57 | void scrollBitmap(uint16_t x, uint16_t y, uint16_t y_offset, BITMAP &bm, int16_t offset, uint8_t gap, uint16_t color); 58 | private: 59 | struct r_data *ds = 0; 60 | }; 61 | 62 | 63 | #endif 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /SRC/TFT/tjpgd.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / TJpgDec - Tiny JPEG Decompressor include file (C)ChaN, 2019 3 | /----------------------------------------------------------------------------*/ 4 | #ifndef DEF_TJPGDEC 5 | #define DEF_TJPGDEC 6 | /*---------------------------------------------------------------------------*/ 7 | /* System Configurations */ 8 | 9 | #define JD_SZBUF 512 /* Size of stream input buffer */ 10 | #define JD_FORMAT 1 /* Output pixel format 0:RGB888 (3 BYTE/pix), 1:RGB565 (1 WORD/pix) */ 11 | #define JD_USE_SCALE 1 /* Use descaling feature for output */ 12 | #define JD_TBLCLIP 1 /* Use table for saturation (might be a bit faster but increases 1K bytes of code size) */ 13 | 14 | /*---------------------------------------------------------------------------*/ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #if defined(_WIN32) /* Main development platform */ 21 | typedef unsigned char uint8_t; 22 | typedef unsigned short uint16_t; 23 | typedef short int16_t; 24 | typedef unsigned long uint32_t; 25 | typedef long int32_t; 26 | #else 27 | #include "stdint.h" 28 | #endif 29 | 30 | /* Error code */ 31 | typedef enum { 32 | JDR_OK = 0, /* 0: Succeeded */ 33 | JDR_INTR, /* 1: Interrupted by output function */ 34 | JDR_INP, /* 2: Device error or wrong termination of input stream */ 35 | JDR_MEM1, /* 3: Insufficient memory pool for the image */ 36 | JDR_MEM2, /* 4: Insufficient stream input buffer */ 37 | JDR_PAR, /* 5: Parameter error */ 38 | JDR_FMT1, /* 6: Data format error (may be damaged data) */ 39 | JDR_FMT2, /* 7: Right format but not supported */ 40 | JDR_FMT3 /* 8: Not supported JPEG standard */ 41 | } JRESULT; 42 | 43 | 44 | 45 | /* Rectangular structure */ 46 | typedef struct { 47 | uint16_t left, right, top, bottom; 48 | } JRECT; 49 | 50 | 51 | 52 | /* Decompressor object structure */ 53 | typedef struct JDEC JDEC; 54 | struct JDEC { 55 | uint16_t dctr; /* Number of bytes available in the input buffer */ 56 | uint8_t* dptr; /* Current data read ptr */ 57 | uint8_t* inbuf; /* Bit stream input buffer */ 58 | uint8_t dmsk; /* Current bit in the current read byte */ 59 | uint8_t scale; /* Output scaling ratio */ 60 | uint8_t msx, msy; /* MCU size in unit of block (width, height) */ 61 | uint8_t qtid[3]; /* Quantization table ID of each component */ 62 | int16_t dcv[3]; /* Previous DC element of each component */ 63 | uint16_t nrst; /* Restart inverval */ 64 | uint16_t width, height; /* Size of the input image (pixel) */ 65 | uint8_t* huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ 66 | uint16_t* huffcode[2][2]; /* Huffman code word tables [id][dcac] */ 67 | uint8_t* huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ 68 | int32_t* qttbl[4]; /* Dequantizer tables [id] */ 69 | void* workbuf; /* Working buffer for IDCT and RGB output */ 70 | uint8_t* mcubuf; /* Working buffer for the MCU */ 71 | void* pool; /* Pointer to available memory pool */ 72 | uint16_t sz_pool; /* Size of momory pool (bytes available) */ 73 | uint16_t (*infunc)(JDEC*, uint8_t*, uint16_t);/* Pointer to jpeg stream input function */ 74 | void* device; /* Pointer to I/O device identifiler for the session */ 75 | }; 76 | 77 | 78 | 79 | /* TJpgDec API functions */ 80 | JRESULT jd_prepare (JDEC*, uint16_t(*)(JDEC*,uint8_t*,uint16_t), void*, uint16_t, void*); 81 | JRESULT jd_decomp (JDEC*, uint16_t(*)(JDEC*,void*,JRECT*), uint8_t); 82 | 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif /* _TJPGDEC */ 89 | -------------------------------------------------------------------------------- /SRC/TFT/u8g2_fonts.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/SRC/TFT/u8g2_fonts.c -------------------------------------------------------------------------------- /SRC/TFT/u8g_font.h: -------------------------------------------------------------------------------- 1 | /* 2 | * u8g_font.h 3 | * 4 | */ 5 | 6 | #ifndef _U8G_FONT_H_ 7 | #define _U8G_FONT_H_ 8 | 9 | #include "main.h" 10 | #include "u8g2_fonts.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | #define U8G2_FONT_HEIGHT_MODE_TEXT (0) 17 | #define U8G2_FONT_HEIGHT_MODE_XTEXT (1) 18 | #define U8G2_FONT_HEIGHT_MODE_ALL (2) 19 | #define U8G2_FONT_MAX_SCALE (4) 20 | 21 | typedef uint16_t u8g2_uint_t; // for pixel position only 22 | typedef int16_t u8g2_int_t; // introduced for circle calculation 23 | typedef int32_t u8g2_long_t; // introduced for ellipse calculation 24 | typedef struct u8g2_struct u8g2_t; 25 | typedef u8g2_uint_t (*u8g2_font_calc_vref_fnptr)(u8g2_t *u8g2); 26 | 27 | struct _u8g2_font_info_t { 28 | /* offset 0 */ 29 | uint8_t glyph_cnt; 30 | uint8_t bbx_mode; 31 | uint8_t bits_per_0; 32 | uint8_t bits_per_1; 33 | /* offset 4 */ 34 | uint8_t bits_per_char_width; 35 | uint8_t bits_per_char_height; 36 | uint8_t bits_per_char_x; 37 | uint8_t bits_per_char_y; 38 | uint8_t bits_per_delta_x; 39 | /* offset 9 */ 40 | int8_t max_char_width; 41 | int8_t max_char_height; // overall height, NOT ascent. Instead ascent = max_char_height + y_offset 42 | int8_t x_offset; 43 | int8_t y_offset; 44 | /* offset 13 */ 45 | int8_t ascent_A; 46 | int8_t descent_g; // usually a negative value 47 | int8_t ascent_para; 48 | int8_t descent_para; 49 | /* offset 17 */ 50 | uint16_t start_pos_upper_A; 51 | uint16_t start_pos_lower_a; 52 | /* offset 21 */ 53 | uint16_t start_pos_unicode; 54 | }; 55 | typedef struct _u8g2_font_info_t u8g2_font_info_t; 56 | 57 | struct _u8g2_font_decode_t { 58 | const uint8_t *decode_ptr; // pointer to the compressed data 59 | u8g2_uint_t target_x; 60 | u8g2_uint_t target_y; 61 | int8_t x; // local coordinates, (0,0) is upper left 62 | int8_t y; 63 | int8_t glyph_width; 64 | int8_t glyph_height; 65 | uint8_t decode_bit_pos; // bitpos inside a byte of the compressed data 66 | uint8_t is_transparent; 67 | uint16_t fg_color; 68 | uint16_t bg_color; 69 | // To decode string into memory buffer 70 | uint8_t* buff; // Buffer to decode string into 71 | uint16_t buff_width; // String buffer width in pixels 72 | }; 73 | typedef struct _u8g2_font_decode_t u8g2_font_decode_t; 74 | 75 | struct _u8g2_kerning_t { 76 | uint16_t first_table_cnt; 77 | uint16_t second_table_cnt; 78 | const uint16_t *first_encoding_table; 79 | const uint16_t *index_to_second_table; 80 | const uint16_t *second_encoding_table; 81 | const uint8_t *kerning_values; 82 | }; 83 | typedef struct _u8g2_kerning_t u8g2_kerning_t; 84 | 85 | typedef struct u8x8_struct u8x8_t; 86 | typedef uint16_t (*u8x8_char_cb)(u8x8_t *u8x8, uint8_t b); 87 | 88 | struct u8x8_struct { 89 | u8x8_char_cb next_cb; // procedure, which will be used to get the next char from the string 90 | uint8_t utf8_state; // number of chars which are still to scan 91 | uint16_t encoding; // encoding result for utf8 decoder in next_cb 92 | }; 93 | 94 | struct u8g2_struct { 95 | u8x8_t u8x8; 96 | const uint8_t *font; // current font for all text procedures 97 | u8g2_font_calc_vref_fnptr font_calc_vref; 98 | u8g2_font_decode_t font_decode; // new font decode structure 99 | u8g2_font_info_t font_info; // new font info structure 100 | uint8_t font_height_mode; 101 | int8_t font_ref_ascent; 102 | int8_t font_ref_descent; 103 | int8_t glyph_x_offset; // set by u8g2_GetGlyphWidth as a side effect 104 | uint8_t bitmap_transparency; // black pixels will be treated as transparent (not drawn) 105 | uint8_t scale; // Font scale factor, default 1. Maximum value is U8G2_FONT_MAX_SCALE 106 | }; 107 | 108 | typedef enum { 109 | align_left = 0, align_center, align_right 110 | } BM_ALIGN; 111 | 112 | void u8g2_u8gFont(u8g2_t *u8g2); 113 | void u8g2_SetFont(u8g2_t *u8g2, const uint8_t *font); 114 | void u8g2_SetFontMode(u8g2_t *u8g2, uint8_t is_transparent, uint16_t bg_color); 115 | void u8g2_SetFontScale(u8g2_t *u8g2, uint8_t scale); 116 | uint8_t u8g2_GetFontScale(u8g2_t *u8g2); 117 | uint8_t u8g2_IsGlyph(u8g2_t *u8g2, uint16_t requested_encoding); 118 | int8_t u8g2_GetGlyphWidth(u8g2_t *u8g2, uint16_t requested_encoding); 119 | 120 | u8g2_uint_t u8g2_DrawStr(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str, uint16_t color); 121 | u8g2_uint_t u8g2_DrawUTF8(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str, uint16_t color); 122 | 123 | u8g2_uint_t u8g2_allocateBitmap(u8g2_t *u8g2, uint8_t** buff, const char *str, uint8_t utf8); 124 | u8g2_uint_t u8g2_StrToBitmap(u8g2_t *u8g2, uint8_t* buff, uint16_t width, const char *str, BM_ALIGN align, uint16_t margin, uint8_t utf8); 125 | 126 | uint8_t u8g2_IsAllValidUTF8(u8g2_t *u8g2, const char *str); // checks whether all codes are valid 127 | 128 | u8g2_uint_t u8g2_GetStrWidth(u8g2_t *u8g2, const char *s); 129 | u8g2_uint_t u8g2_GetUTF8Width(u8g2_t *u8g2, const char *str); 130 | 131 | void u8g2_SetFontRefHeightText(u8g2_t *u8g2); 132 | void u8g2_SetFontRefHeightExtendedText(u8g2_t *u8g2); 133 | void u8g2_SetFontRefHeightAll(u8g2_t *u8g2); 134 | 135 | void u8g2_SetFontPosBaseline(u8g2_t *u8g2); 136 | void u8g2_SetFontPosBottom(u8g2_t *u8g2); 137 | void u8g2_SetFontPosTop(u8g2_t *u8g2); 138 | void u8g2_SetFontPosCenter(u8g2_t *u8g2); 139 | 140 | int8_t u8g2_GetMaxCharHeight(u8g2_t *u8g2); 141 | int8_t u8g2_GetMaxCharWidth(u8g2_t *u8g2); 142 | int8_t u8g2_GetAscent(u8g2_t *u8g2); 143 | int8_t u8g2_GetDescent(u8g2_t *u8g2); 144 | 145 | /* 146 | #define u8g2_GetMaxCharHeight(u8g2) ((u8g2)->font_info.max_char_height) 147 | #define u8g2_GetMaxCharWidth(u8g2) ((u8g2)->font_info.max_char_width) 148 | #define u8g2_GetAscent(u8g2) ((u8g2)->font_ref_ascent) 149 | #define u8g2_GetDescent(u8g2) ((u8g2)->font_ref_descent) 150 | #define u8g2_GetFontAscent(u8g2) ((u8g2)->font_ref_ascent) 151 | #define u8g2_GetFontDescent(u8g2) ((u8g2)->font_ref_descent) 152 | */ 153 | #ifdef __cplusplus 154 | } 155 | #endif 156 | 157 | #endif 158 | -------------------------------------------------------------------------------- /SRC/W25Qxx/README: -------------------------------------------------------------------------------- 1 | This is a library to manage W24Qxx flash SPI ICs. 2 | -------------------------------------------------------------------------------- /SRC/W25Qxx/W25Qxx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * W25Qxx.h 3 | * 4 | * Created on: 2020 June 14 5 | * Author: Alex 6 | * 7 | * 2023 Nov 11 8 | * Added Quad SPI support. To use quad SPI mode, define QSPI macro below 9 | * 10 | * W25QXX SPI flash IC driver. Tested on W25Q16 device at 42 Mbit/s SPI bus. 11 | * Read can be performed from any available address, 12 | * Write operation should be aligned to 256-byte page 13 | * 14 | * Driver is working with FatFS library. 15 | * As soon as data on the flash drive can be erased by sector (4k) 16 | * block size of FAT file system should be setup as 4096 bytes 17 | * Read and Write operations will work with 4K aligned blocks 18 | * 19 | * Before used as disk device, the flash should be formated like this: 20 | * 21 | * bool formatFlashDrive(void) { 22 | * MKFS_PARM p; 23 | * p.fmt = FM_FAT | FM_SFD; 24 | * p.au_size = 4096; // W25Q16 sector size 25 | * p.align = 0; // 8 26 | * p.n_fat = 1; 27 | * p.n_root = 128; // Number of files in root directory. Can be 256 or 512. 32 bytes per entry, 4096 bytes, 1 sector! 28 | * 29 | * uint8_t *wrk = malloc(4096); 30 | * if (wrk) { 31 | * if (FR_OK == f_mkfs ("0:/", &p, wrk, 4096)) { 32 | * free(wrk); 33 | * return true; 34 | * } 35 | * } 36 | * return false; 37 | *} 38 | * 39 | * Performance metrix: 40 | * SPI single wire mode, 18.75 MHz. Read whole 8-MByte flash (2048 4k sectors) takes 11 s 41 | * SPI quad wire mode, 170 GHz, prescaler = 1, dummy cycles = 6. Read whole 8-MByte flash (2048 4k sectors) takes 5.9 s 42 | * SPI quad wire mode + memory mapping, 170 GHz, prescaler = 1, dummy cycles = 6. Read whole 8-MByte flash takes 1.4 s 43 | * 44 | * 2024 Feb 10. Failed to enable write mode, do not know why. 45 | */ 46 | 47 | #ifndef W25QXX_H_ 48 | #define W25QXX_H_ 49 | 50 | #include "main.h" 51 | 52 | // Comment out the next line to use SPI based flash IC 53 | //#define QSPI 54 | 55 | #ifdef QSPI 56 | 57 | #define FLASH_QSPI hqspi 58 | extern QSPI_HandleTypeDef FLASH_QSPI; 59 | 60 | #else 61 | 62 | // You have to declare FLASH_CS in CubeMx - FLASH IC chip select pin 63 | #define FLASH_SPI_PORT hspi2 64 | extern SPI_HandleTypeDef FLASH_SPI_PORT; 65 | 66 | #endif 67 | 68 | typedef enum { 69 | W25Qxx_RET_OK = 0, 70 | W25Qxx_RET_ALIGN, 71 | W25Qxx_RET_SIZE, 72 | W25Qxx_RET_ADDR, 73 | W25Qxx_RET_ERASE, 74 | W25Qxx_RET_WRITE, 75 | W25Qxx_RET_READ, 76 | W25Qxx_RES_RO, 77 | W25Qxx_RES_BUSY 78 | } W25Qxx_RET; 79 | 80 | #ifndef __cplusplus 81 | #include 82 | #endif 83 | 84 | #ifdef __cplusplus 85 | extern "C" { 86 | #endif 87 | 88 | bool W25Qxx_Init(void); 89 | uint16_t W25Qxx_SectorCount(void); 90 | W25Qxx_RET W25Qxx_Read(uint32_t addr, uint8_t buff[], uint16_t size); 91 | W25Qxx_RET W25Qxx_Write(uint32_t addr, uint8_t buff[], uint16_t size); 92 | W25Qxx_RET W25Qxx_Erase(uint16_t start_sector, uint16_t n_sectors); 93 | 94 | #ifdef QSPI 95 | bool W25Qxx_QSPI_MemoryMapped(void); 96 | #endif 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /ctrl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/ctrl.png -------------------------------------------------------------------------------- /high_voltage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/high_voltage.png -------------------------------------------------------------------------------- /iron_sensors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/iron_sensors.png -------------------------------------------------------------------------------- /tft_board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/tft_board.png -------------------------------------------------------------------------------- /title.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/title.JPG -------------------------------------------------------------------------------- /Паяльная и ремонтная станция на STM32 с дисплеем TFT.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfrwmaker/TFT_Rework_station/9ef5bd495d76f33efeb8f5a6c962dd46016fb866/Паяльная и ремонтная станция на STM32 с дисплеем TFT.pdf --------------------------------------------------------------------------------