Explorar el Código

First try. Display works

Thomas Chef hace 6 días
commit
890fc6861b

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 172 - 0
.cproject


+ 58 - 0
.gitignore

@@ -0,0 +1,58 @@
+.DS_Store
+
+#settings
+.settings/
+
+#metadata
+.metadata/
+
+#Debug
+Debug/
+debug/
+Release/
+release
+
+Drivers/
+Middlewares/
+USB_DEVICE/
+
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+*.bin
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 25 - 0
.mxproject


+ 32 - 0
.project

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>BoatLogger</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+			<triggers>clean,full,incremental,</triggers>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+			<triggers>full,incremental,</triggers>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>com.st.stm32cube.ide.mcu.MCUProjectNature</nature>
+		<nature>com.st.stm32cube.ide.mcu.MCUCubeProjectNature</nature>
+		<nature>org.eclipse.cdt.core.cnature</nature>
+		<nature>com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature</nature>
+		<nature>com.st.stm32cube.ide.mcu.MCUAdvancedStructureProjectNature</nature>
+		<nature>com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature</nature>
+		<nature>com.st.stm32cube.ide.mcu.MCURootProjectNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+	</natures>
+</projectDescription>

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 86 - 0
BoatLogger Debug.launch


+ 192 - 0
BoatLogger.ioc

@@ -0,0 +1,192 @@
+#MicroXplorer Configuration settings - do not modify
+CAD.formats=
+CAD.pinconfig=
+CAD.provider=
+File.Version=6
+GPIO.groupedBy=Group By Peripherals
+KeepUserPlacement=false
+Mcu.CPN=STM32F103C8T6
+Mcu.Family=STM32F1
+Mcu.IP0=NVIC
+Mcu.IP1=RCC
+Mcu.IP2=SPI1
+Mcu.IP3=SYS
+Mcu.IP4=USART1
+Mcu.IPNb=5
+Mcu.Name=STM32F103C(8-B)Tx
+Mcu.Package=LQFP48
+Mcu.Pin0=PC13-TAMPER-RTC
+Mcu.Pin1=PD0-OSC_IN
+Mcu.Pin10=PA13
+Mcu.Pin11=PA14
+Mcu.Pin12=PB4
+Mcu.Pin13=VP_SYS_VS_Systick
+Mcu.Pin2=PD1-OSC_OUT
+Mcu.Pin3=PA1
+Mcu.Pin4=PA2
+Mcu.Pin5=PA4
+Mcu.Pin6=PA5
+Mcu.Pin7=PA7
+Mcu.Pin8=PA9
+Mcu.Pin9=PA10
+Mcu.PinsNb=14
+Mcu.ThirdPartyNb=0
+Mcu.UserConstants=
+Mcu.UserName=STM32F103C8Tx
+MxCube.Version=6.15.0
+MxDb.Version=DB.6.0.150
+NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
+NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
+NVIC.ForceEnableDMAVector=true
+NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
+NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
+NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
+NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
+NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
+NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
+NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
+NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false
+PA1.GPIOParameters=PinState,GPIO_Label
+PA1.GPIO_Label=RST
+PA1.Locked=true
+PA1.PinState=GPIO_PIN_SET
+PA1.Signal=GPIO_Output
+PA10.Mode=Asynchronous
+PA10.Signal=USART1_RX
+PA13.Mode=Serial_Wire
+PA13.Signal=SYS_JTMS-SWDIO
+PA14.Mode=Serial_Wire
+PA14.Signal=SYS_JTCK-SWCLK
+PA2.GPIOParameters=PinState,GPIO_Label
+PA2.GPIO_Label=DC
+PA2.Locked=true
+PA2.PinState=GPIO_PIN_SET
+PA2.Signal=GPIO_Output
+PA4.GPIOParameters=PinState,GPIO_Label
+PA4.GPIO_Label=CS
+PA4.Locked=true
+PA4.PinState=GPIO_PIN_SET
+PA4.Signal=GPIO_Output
+PA5.Mode=TX_Only_Simplex_Unidirect_Master
+PA5.Signal=SPI1_SCK
+PA7.Mode=TX_Only_Simplex_Unidirect_Master
+PA7.Signal=SPI1_MOSI
+PA9.Mode=Asynchronous
+PA9.Signal=USART1_TX
+PB4.GPIOParameters=GPIO_Label
+PB4.GPIO_Label=BUSY
+PB4.Locked=true
+PB4.Signal=GPIO_Input
+PC13-TAMPER-RTC.GPIOParameters=GPIO_Label
+PC13-TAMPER-RTC.GPIO_Label=LED
+PC13-TAMPER-RTC.Locked=true
+PC13-TAMPER-RTC.Signal=GPIO_Output
+PCC.Checker=false
+PCC.Line=STM32F103
+PCC.MCU=STM32F103C(8-B)Tx
+PCC.PartNumber=STM32F103C8Tx
+PCC.Seq0=2
+PCC.Seq0.Step0.Average_Current=27 mA
+PCC.Seq0.Step0.CPU_Frequency=72 MHz
+PCC.Seq0.Step0.Category=In DS Table
+PCC.Seq0.Step0.DMIPS=90.0
+PCC.Seq0.Step0.Duration=0.1 ms
+PCC.Seq0.Step0.Frequency=8 MHz
+PCC.Seq0.Step0.Memory=FLASH
+PCC.Seq0.Step0.Mode=RUN
+PCC.Seq0.Step0.Oscillator=HSE PLL
+PCC.Seq0.Step0.Peripherals=
+PCC.Seq0.Step0.TaMax=100.1
+PCC.Seq0.Step0.User's_Consumption=0 mA
+PCC.Seq0.Step0.Vcore=No Scale
+PCC.Seq0.Step0.Vdd=3.3
+PCC.Seq0.Step0.Voltage_Source=Battery
+PCC.Seq0.Step1.Average_Current=2 \u00B5A
+PCC.Seq0.Step1.CPU_Frequency=0 Hz
+PCC.Seq0.Step1.Category=In DS Table
+PCC.Seq0.Step1.DMIPS=0.0
+PCC.Seq0.Step1.Duration=0.9 ms
+PCC.Seq0.Step1.Frequency=0 Hz
+PCC.Seq0.Step1.Memory=n/a
+PCC.Seq0.Step1.Mode=STANDBY
+PCC.Seq0.Step1.Oscillator=ALL CLOCKS OFF
+PCC.Seq0.Step1.Peripherals=
+PCC.Seq0.Step1.TaMax=105
+PCC.Seq0.Step1.User's_Consumption=0 mA
+PCC.Seq0.Step1.Vcore=No Scale
+PCC.Seq0.Step1.Vdd=3.3
+PCC.Seq0.Step1.Voltage_Source=Battery
+PCC.Series=STM32F1
+PCC.Temperature=25
+PCC.Vdd=3.3
+PD0-OSC_IN.Mode=HSE-External-Oscillator
+PD0-OSC_IN.Signal=RCC_OSC_IN
+PD1-OSC_OUT.Mode=HSE-External-Oscillator
+PD1-OSC_OUT.Signal=RCC_OSC_OUT
+PinOutPanel.RotationAngle=0
+ProjectManager.AskForMigrate=true
+ProjectManager.BackupPrevious=false
+ProjectManager.CompilerLinker=GCC
+ProjectManager.CompilerOptimize=6
+ProjectManager.ComputerToolchain=false
+ProjectManager.CoupleFile=false
+ProjectManager.CustomerFirmwarePackage=
+ProjectManager.DefaultFWLocation=true
+ProjectManager.DeletePrevious=true
+ProjectManager.DeviceId=STM32F103C8Tx
+ProjectManager.FirmwarePackage=STM32Cube FW_F1 V1.8.6
+ProjectManager.FreePins=false
+ProjectManager.HalAssertFull=false
+ProjectManager.HeapSize=0x200
+ProjectManager.KeepUserCode=true
+ProjectManager.LastFirmware=true
+ProjectManager.LibraryCopy=1
+ProjectManager.MainLocation=Core/Src
+ProjectManager.NoMain=false
+ProjectManager.PreviousToolchain=STM32CubeIDE
+ProjectManager.ProjectBuild=false
+ProjectManager.ProjectFileName=BoatLogger.ioc
+ProjectManager.ProjectName=BoatLogger
+ProjectManager.ProjectStructure=
+ProjectManager.RegisterCallBack=
+ProjectManager.StackSize=0x400
+ProjectManager.TargetToolchain=STM32CubeIDE
+ProjectManager.ToolChainLocation=
+ProjectManager.UAScriptAfterPath=
+ProjectManager.UAScriptBeforePath=
+ProjectManager.UnderRoot=true
+ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_SPI1_Init-SPI1-false-HAL-true,4-MX_USART1_UART_Init-USART1-false-HAL-true
+RCC.ADCFreqValue=24000000
+RCC.AHBFreq_Value=48000000
+RCC.APB1CLKDivider=RCC_HCLK_DIV2
+RCC.APB1Freq_Value=24000000
+RCC.APB1TimFreq_Value=48000000
+RCC.APB2Freq_Value=48000000
+RCC.APB2TimFreq_Value=48000000
+RCC.FCLKCortexFreq_Value=48000000
+RCC.FamilyName=M
+RCC.HCLKFreq_Value=48000000
+RCC.IPParameters=ADCFreqValue,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,MCOFreq_Value,PLLCLKFreq_Value,PLLMCOFreq_Value,PLLMUL,PLLSourceVirtual,SYSCLKFreq_VALUE,SYSCLKSource,TimSysFreq_Value,USBFreq_Value,VCOOutput2Freq_Value
+RCC.MCOFreq_Value=48000000
+RCC.PLLCLKFreq_Value=48000000
+RCC.PLLMCOFreq_Value=24000000
+RCC.PLLMUL=RCC_PLL_MUL6
+RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE
+RCC.SYSCLKFreq_VALUE=48000000
+RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
+RCC.TimSysFreq_Value=48000000
+RCC.USBFreq_Value=48000000
+RCC.VCOOutput2Freq_Value=8000000
+SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_8
+SPI1.CalculateBaudRate=6.0 MBits/s
+SPI1.Direction=SPI_DIRECTION_2LINES
+SPI1.IPParameters=VirtualType,Mode,Direction,BaudRatePrescaler,CalculateBaudRate
+SPI1.Mode=SPI_MODE_MASTER
+SPI1.VirtualType=VM_MASTER
+USART1.BaudRate=9600
+USART1.IPParameters=VirtualMode,BaudRate
+USART1.VirtualMode=VM_ASYNC
+VP_SYS_VS_Systick.Mode=SysTick
+VP_SYS_VS_Systick.Signal=SYS_VS_Systick
+board=custom
+isbadioc=false

+ 24 - 0
Core/Inc/debug.h

@@ -0,0 +1,24 @@
+/*****************************************************************************
+* | File      	:	Debug.h
+* | Author      :   Waveshare team
+* | Function    :	debug with printf
+* | Info        :
+*   Image scanning
+*      Please use progressive scanning to generate images or fonts
+*----------------
+* |	This version:   V1.0
+* | Date        :   2018-01-11
+* | Info        :   Basic version
+*
+******************************************************************************/
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+#define DEBUG 1
+#if DEBUG
+	#define Debug(__info,...) printf("Debug: " __info,##__VA_ARGS__)
+#else
+	#define Debug(__info,...)
+#endif
+
+#endif

+ 53 - 0
Core/Inc/epd.h

@@ -0,0 +1,53 @@
+/*****************************************************************************
+* | File      	:   EPD_2Iin13_V4.h
+* | Author      :   Waveshare team
+* | Function    :   2.13inch e-paper V4
+* | Info        :
+*----------------
+* |	This version:   V1.1
+* | Date        :   2021-10-30
+* | Info        :
+* -----------------------------------------------------------------------------
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documnetation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to  whom the Software is
+# furished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+******************************************************************************/
+#ifndef __EPD_2in13_V4_H_
+#define __EPD_2in13_V4_H_
+
+#include "epd_config.h"
+
+
+// Display resolution
+#define EPD_2in13_V4_WIDTH       122
+#define EPD_2in13_V4_HEIGHT      250
+
+void EPD_2in13_V4_Init(void);
+void EPD_2in13_V4_Init_Fast(void);
+void EPD_2in13_V4_Init_GUI(void);
+void EPD_2in13_V4_Clear(void);
+void EPD_2in13_V4_Clear_Black(void);
+void EPD_2in13_V4_Display(UBYTE *Image);
+void EPD_2in13_V4_Display_Fast(UBYTE *Image);
+void EPD_2in13_V4_Display_Base(UBYTE *Image);
+void EPD_2in13_V4_Display_Partial(UBYTE *Image);
+void EPD_2in13_V4_Sleep(void);
+
+
+#endif

+ 95 - 0
Core/Inc/epd_config.h

@@ -0,0 +1,95 @@
+/*****************************************************************************
+* | File      	:   DEV_Config.h
+* | Author      :   Waveshare team
+* | Function    :   Hardware underlying interface
+* | Info        :
+*                Used to shield the underlying layers of each master
+*                and enhance portability
+*----------------
+* |	This version:   V2.0
+* | Date        :   2018-10-30
+* | Info        :
+* 1.add:
+*   UBYTE\UWORD\UDOUBLE
+* 2.Change:
+*   EPD_RST -> EPD_RST_PIN
+*   EPD_DC -> EPD_DC_PIN
+*   EPD_CS -> EPD_CS_PIN
+*   EPD_BUSY -> EPD_BUSY_PIN
+* 3.Remote:
+*   EPD_RST_1\EPD_RST_0
+*   EPD_DC_1\EPD_DC_0
+*   EPD_CS_1\EPD_CS_0
+*   EPD_BUSY_1\EPD_BUSY_0
+* 3.add:
+*   #define DEV_Digital_Write(_pin, _value) bcm2835_gpio_write(_pin, _value)
+*   #define DEV_Digital_Read(_pin) bcm2835_gpio_lev(_pin)
+*   #define DEV_SPI_WriteByte(__value) bcm2835_spi_transfer(__value)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documnetation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to  whom the Software is
+# furished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+******************************************************************************/
+#ifndef _DEV_CONFIG_H_
+#define _DEV_CONFIG_H_
+
+#include "main.h"
+#include "stm32f1xx_hal.h"
+#include "stm32f1xx_hal_gpio.h"
+#include <stdint.h>
+#include <stdio.h>
+
+/**
+ * data
+**/
+#define UBYTE   uint8_t
+#define UWORD   uint16_t
+#define UDOUBLE uint32_t
+
+/**
+ * e-Paper GPIO
+**/
+#define EPD_RST_PIN     RST_GPIO_Port, RST_Pin
+#define EPD_DC_PIN      DC_GPIO_Port, DC_Pin
+//#define EPD_PWR_PIN     PWR_GPIO_Port, PWR_Pin
+#define EPD_CS_PIN      CS_GPIO_Port, CS_Pin
+#define EPD_BUSY_PIN    BUSY_GPIO_Port, BUSY_Pin
+#define EPD_MOSI_PIN    DIN_GPIO_Port, DIN_Pin
+#define EPD_SCLK_PIN    SCK_GPIO_Port, SCK_Pin
+
+/**
+ * GPIO read and write
+**/
+#define DEV_Digital_Write(_pin, _value) HAL_GPIO_WritePin(_pin, _value == 0? GPIO_PIN_RESET:GPIO_PIN_SET)
+#define DEV_Digital_Read(_pin) HAL_GPIO_ReadPin(_pin)
+
+/**
+ * delay x ms
+**/
+#define DEV_Delay_ms(__xms) HAL_Delay(__xms);
+
+void DEV_SPI_WriteByte(UBYTE value);
+void DEV_SPI_Write_nByte(UBYTE *value, UDOUBLE len);
+
+int DEV_Module_Init(void);
+void DEV_Module_Exit(void);
+void DEV_GPIO_Init(void);
+void DEV_SPI_Init(void);
+void DEV_SPI_SendData(UBYTE Reg);
+UBYTE DEV_SPI_ReadData(void);
+#endif

+ 41 - 0
Core/Inc/epd_test.h

@@ -0,0 +1,41 @@
+/*****************************************************************************
+* | File      	:	  EPD_Test.h
+* | Author      :   Waveshare team
+* | Function    :   e-Paper test Demo
+* | Info        :
+*----------------
+* |	This version:   V1.0
+* | Date        :   2019-06-11
+* | Info        :
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documnetation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to  whom the Software is
+# furished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+******************************************************************************/
+#ifndef _EPD_TEST_H_
+#define _EPD_TEST_H_
+
+#include "epd_config.h"
+#include "GUI_Paint.h"
+//#include "imagedata.h"
+#include "Debug.h"
+#include <stdlib.h> // malloc() free()
+
+int EPD_test(void);
+
+#endif

+ 97 - 0
Core/Inc/fonts.h

@@ -0,0 +1,97 @@
+/**
+  ******************************************************************************
+  * @file    fonts.h
+  * @author  MCD Application Team
+  * @version V1.0.0
+  * @date    18-February-2014
+  * @brief   Header for fonts.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
+  *
+  * Redistribution and use in source and binary forms, with or without modification,
+  * are permitted provided that the following conditions are met:
+  *   1. Redistributions of source code must retain the above copyright notice,
+  *      this list of conditions and the following disclaimer.
+  *   2. Redistributions in binary form must reproduce the above copyright notice,
+  *      this list of conditions and the following disclaimer in the documentation
+  *      and/or other materials provided with the distribution.
+  *   3. Neither the name of STMicroelectronics nor the names of its contributors
+  *      may be used to endorse or promote products derived from this software
+  *      without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __FONTS_H
+#define __FONTS_H
+
+/*�������΢���ź�24 (32x41) */
+#define MAX_HEIGHT_FONT         41
+#define MAX_WIDTH_FONT          32
+#define OFFSET_BITMAP
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include <stdint.h>
+
+//ASCII
+typedef struct _tFont
+{
+  const uint8_t *table;
+  uint16_t Width;
+  uint16_t Height;
+
+} sFONT;
+
+
+//GB2312
+typedef struct                                          // ������ģ���ݽṹ
+{
+  unsigned char index[2];                               // ������������
+  const char matrix[MAX_HEIGHT_FONT*MAX_WIDTH_FONT/8];  // ����������
+}CH_CN;
+
+
+typedef struct
+{
+  const CH_CN *table;
+  uint16_t size;
+  uint16_t ASCII_Width;
+  uint16_t Width;
+  uint16_t Height;
+
+}cFONT;
+
+extern sFONT Font24;
+extern sFONT Font20;
+extern sFONT Font16;
+extern sFONT Font12;
+extern sFONT Font8;
+
+extern cFONT Font12CN;
+extern cFONT Font24CN;
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __FONTS_H */
+
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 217 - 0
Core/Inc/gui_paint.h

@@ -0,0 +1,217 @@
+/******************************************************************************
+* | File      	:   GUI_Paint.h
+* | Author      :   Waveshare electronics
+* | Function    :	Achieve drawing: draw points, lines, boxes, circles and
+*                   their size, solid dotted line, solid rectangle hollow
+*                   rectangle, solid circle hollow circle.
+* | Info        :
+*   Achieve display characters: Display a single character, string, number
+*   Achieve time display: adaptive size display time minutes and seconds
+*----------------
+* |	This version:   V3.0
+* | Date        :   2019-04-18
+* | Info        :
+* -----------------------------------------------------------------------------
+* V3.0(2019-04-18):
+* 1.Change:
+*    Paint_DrawPoint(..., DOT_STYLE DOT_STYLE)
+* => Paint_DrawPoint(..., DOT_STYLE Dot_Style)
+*    Paint_DrawLine(..., LINE_STYLE Line_Style, DOT_PIXEL Dot_Pixel)
+* => Paint_DrawLine(..., DOT_PIXEL Line_width, LINE_STYLE Line_Style)
+*    Paint_DrawRectangle(..., DRAW_FILL Filled, DOT_PIXEL Dot_Pixel)
+* => Paint_DrawRectangle(..., DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
+*    Paint_DrawCircle(..., DRAW_FILL Draw_Fill, DOT_PIXEL Dot_Pixel)
+* => Paint_DrawCircle(..., DOT_PIXEL Line_width, DRAW_FILL Draw_Filll)
+*
+* -----------------------------------------------------------------------------
+* V2.0(2018-11-15):
+* 1.add: Paint_NewImage()
+*    Create an image's properties
+* 2.add: Paint_SelectImage()
+*    Select the picture to be drawn
+* 3.add: Paint_SetRotate()
+*    Set the direction of the cache
+* 4.add: Paint_RotateImage()
+*    Can flip the picture, Support 0-360 degrees,
+*    but only 90.180.270 rotation is better
+* 4.add: Paint_SetMirroring()
+*    Can Mirroring the picture, horizontal, vertical, origin
+* 5.add: Paint_DrawString_CN()
+*    Can display Chinese(GB1312)
+*
+* -----------------------------------------------------------------------------
+* V1.0(2018-07-17):
+*   Create library
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documnetation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to  whom the Software is
+* furished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*
+******************************************************************************/
+#ifndef __GUI_PAINT_H
+#define __GUI_PAINT_H
+
+#include "epd_config.h"
+#include "fonts.h"
+
+/**
+ * Image attributes
+**/
+typedef struct {
+    UBYTE *Image;
+    UWORD Width;
+    UWORD Height;
+    UWORD WidthMemory;
+    UWORD HeightMemory;
+    UWORD Color;
+    UWORD Rotate;
+    UWORD Mirror;
+    UWORD WidthByte;
+    UWORD HeightByte;
+    UWORD Scale;
+} PAINT;
+extern PAINT Paint;
+
+/**
+ * Display rotate
+**/
+#define ROTATE_0            0
+#define ROTATE_90           90
+#define ROTATE_180          180
+#define ROTATE_270          270
+
+/**
+ * Display Flip
+**/
+typedef enum {
+    MIRROR_NONE  = 0x00,
+    MIRROR_HORIZONTAL = 0x01,
+    MIRROR_VERTICAL = 0x02,
+    MIRROR_ORIGIN = 0x03,
+} MIRROR_IMAGE;
+#define MIRROR_IMAGE_DFT MIRROR_NONE
+
+/**
+ * image color
+**/
+#define WHITE          0xFF
+#define BLACK          0x00
+#define RED            BLACK
+
+#define IMAGE_BACKGROUND    WHITE
+#define FONT_FOREGROUND     BLACK
+#define FONT_BACKGROUND     WHITE
+
+#define TRUE 1
+#define FALSE 0
+
+//4 Gray level
+#define  GRAY1 0x03 //Blackest
+#define  GRAY2 0x02
+#define  GRAY3 0x01 //gray
+#define  GRAY4 0x00 //white
+
+/**
+ * The size of the point
+**/
+typedef enum {
+    DOT_PIXEL_1X1  = 1,		// 1 x 1
+    DOT_PIXEL_2X2  , 		// 2 X 2
+    DOT_PIXEL_3X3  ,		// 3 X 3
+    DOT_PIXEL_4X4  ,		// 4 X 4
+    DOT_PIXEL_5X5  , 		// 5 X 5
+    DOT_PIXEL_6X6  , 		// 6 X 6
+    DOT_PIXEL_7X7  , 		// 7 X 7
+    DOT_PIXEL_8X8  , 		// 8 X 8
+} DOT_PIXEL;
+#define DOT_PIXEL_DFT  DOT_PIXEL_1X1  //Default dot pilex
+
+/**
+ * Point size fill style
+**/
+typedef enum {
+    DOT_FILL_AROUND  = 1,		// dot pixel 1 x 1
+    DOT_FILL_RIGHTUP  , 		// dot pixel 2 X 2
+} DOT_STYLE;
+#define DOT_STYLE_DFT  DOT_FILL_AROUND  //Default dot pilex
+
+/**
+ * Line style, solid or dashed
+**/
+typedef enum {
+    LINE_STYLE_SOLID = 0,
+    LINE_STYLE_DOTTED,
+} LINE_STYLE;
+
+/**
+ * Whether the graphic is filled
+**/
+typedef enum {
+    DRAW_FILL_EMPTY = 0,
+    DRAW_FILL_FULL,
+} DRAW_FILL;
+
+/**
+ * Custom structure of a time attribute
+**/
+typedef struct {
+    UWORD Year;  //0000
+    UBYTE  Month; //1 - 12
+    UBYTE  Day;   //1 - 30
+    UBYTE  Hour;  //0 - 23
+    UBYTE  Min;   //0 - 59
+    UBYTE  Sec;   //0 - 59
+} PAINT_TIME;
+extern PAINT_TIME sPaint_time;
+
+//init and Clear
+void Paint_NewImage(UBYTE *image, UWORD Width, UWORD Height, UWORD Rotate, UWORD Color);
+void Paint_SelectImage(UBYTE *image);
+void Paint_SetRotate(UWORD Rotate);
+void Paint_SetMirroring(UBYTE mirror);
+void Paint_SetPixel(UWORD Xpoint, UWORD Ypoint, UWORD Color);
+void Paint_SetScale(UBYTE scale);
+
+void Paint_Clear(UWORD Color);
+void Paint_ClearWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color);
+
+//Drawing
+void Paint_DrawPoint(UWORD Xpoint, UWORD Ypoint, UWORD Color, DOT_PIXEL Dot_Pixel, DOT_STYLE Dot_FillWay);
+void Paint_DrawLine(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color, DOT_PIXEL Line_width, LINE_STYLE Line_Style);
+void Paint_DrawRectangle(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill);
+void Paint_DrawCircle(UWORD X_Center, UWORD Y_Center, UWORD Radius, UWORD Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill);
+
+//Display string
+void Paint_DrawChar(UWORD Xstart, UWORD Ystart, const char Acsii_Char, sFONT* Font, UWORD Color_Foreground, UWORD Color_Background);
+void Paint_DrawString_EN(UWORD Xstart, UWORD Ystart, const char * pString, sFONT* Font, UWORD Color_Foreground, UWORD Color_Background);
+void Paint_DrawString_CN(UWORD Xstart, UWORD Ystart, const char * pString, cFONT* font, UWORD Color_Foreground, UWORD Color_Background);
+void Paint_DrawNum(UWORD Xpoint, UWORD Ypoint, int32_t Nummber, sFONT* Font, UWORD Color_Foreground, UWORD Color_Background);
+void Paint_DrawNumDecimals(UWORD Xpoint, UWORD Ypoint, double Nummber, sFONT* Font, UWORD Digit, UWORD Color_Foreground, UWORD Color_Background); // Able to display decimals
+void Paint_DrawTime(UWORD Xstart, UWORD Ystart, PAINT_TIME *pTime, sFONT* Font, UWORD Color_Foreground, UWORD Color_Background);
+
+//pic
+void Paint_DrawBitMap(const unsigned char* image_buffer);
+void Paint_DrawBitMap_Paste(const unsigned char* image_buffer, UWORD Xstart, UWORD Ystart, UWORD imageWidth, UWORD imageHeight, UBYTE flipColor);
+//void Paint_DrawBitMap_Half(const unsigned char* image_buffer, UBYTE Region);
+//void Paint_DrawBitMap_OneQuarter(const unsigned char* image_buffer, UBYTE Region);
+//void Paint_DrawBitMap_OneEighth(const unsigned char* image_buffer, UBYTE Region);
+void Paint_DrawBitMap_Block(const unsigned char* image_buffer, UBYTE Region);
+#endif
+
+
+
+

+ 83 - 0
Core/Inc/main.h

@@ -0,0 +1,83 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : main.h
+  * @brief          : Header for main.c file.
+  *                   This file contains the common defines of the application.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2025 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __MAIN_H
+#define __MAIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f1xx_hal.h"
+
+/* Private includes ----------------------------------------------------------*/
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* Exported types ------------------------------------------------------------*/
+/* USER CODE BEGIN ET */
+
+/* USER CODE END ET */
+
+/* Exported constants --------------------------------------------------------*/
+/* USER CODE BEGIN EC */
+
+/* USER CODE END EC */
+
+/* Exported macro ------------------------------------------------------------*/
+/* USER CODE BEGIN EM */
+
+/* USER CODE END EM */
+
+/* Exported functions prototypes ---------------------------------------------*/
+void Error_Handler(void);
+
+/* USER CODE BEGIN EFP */
+
+/* USER CODE END EFP */
+
+/* Private defines -----------------------------------------------------------*/
+#define LED_Pin GPIO_PIN_13
+#define LED_GPIO_Port GPIOC
+#define RST_Pin GPIO_PIN_1
+#define RST_GPIO_Port GPIOA
+#define DC_Pin GPIO_PIN_2
+#define DC_GPIO_Port GPIOA
+#define CS_Pin GPIO_PIN_4
+#define CS_GPIO_Port GPIOA
+#define BUSY_Pin GPIO_PIN_4
+#define BUSY_GPIO_Port GPIOB
+
+/* USER CODE BEGIN Private defines */
+#define DIN_GPIO_Port GPIOA
+#define DIN_Pin GPIO_PIN_7
+#define SCK_GPIO_Port GPIOA
+#define SCK_Pin GPIO_PIN_5
+
+/* USER CODE END Private defines */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MAIN_H */

+ 391 - 0
Core/Inc/stm32f1xx_hal_conf.h

@@ -0,0 +1,391 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file    stm32f1xx_hal_conf.h
+  * @brief   HAL configuration file.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2017 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F1xx_HAL_CONF_H
+#define __STM32F1xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+  * @brief This is the list of modules to be used in the HAL driver
+  */
+
+#define HAL_MODULE_ENABLED
+  /*#define HAL_ADC_MODULE_ENABLED   */
+/*#define HAL_CRYP_MODULE_ENABLED   */
+/*#define HAL_CAN_MODULE_ENABLED   */
+/*#define HAL_CAN_LEGACY_MODULE_ENABLED   */
+/*#define HAL_CEC_MODULE_ENABLED   */
+/*#define HAL_CORTEX_MODULE_ENABLED   */
+/*#define HAL_CRC_MODULE_ENABLED   */
+/*#define HAL_DAC_MODULE_ENABLED   */
+/*#define HAL_DMA_MODULE_ENABLED   */
+/*#define HAL_ETH_MODULE_ENABLED   */
+/*#define HAL_FLASH_MODULE_ENABLED   */
+#define HAL_GPIO_MODULE_ENABLED
+/*#define HAL_I2C_MODULE_ENABLED   */
+/*#define HAL_I2S_MODULE_ENABLED   */
+/*#define HAL_IRDA_MODULE_ENABLED   */
+/*#define HAL_IWDG_MODULE_ENABLED   */
+/*#define HAL_NOR_MODULE_ENABLED   */
+/*#define HAL_NAND_MODULE_ENABLED   */
+/*#define HAL_PCCARD_MODULE_ENABLED   */
+/*#define HAL_PCD_MODULE_ENABLED   */
+/*#define HAL_HCD_MODULE_ENABLED   */
+/*#define HAL_PWR_MODULE_ENABLED   */
+/*#define HAL_RCC_MODULE_ENABLED   */
+/*#define HAL_RTC_MODULE_ENABLED   */
+/*#define HAL_SD_MODULE_ENABLED   */
+/*#define HAL_MMC_MODULE_ENABLED   */
+/*#define HAL_SDRAM_MODULE_ENABLED   */
+/*#define HAL_SMARTCARD_MODULE_ENABLED   */
+#define HAL_SPI_MODULE_ENABLED
+/*#define HAL_SRAM_MODULE_ENABLED   */
+/*#define HAL_TIM_MODULE_ENABLED   */
+#define HAL_UART_MODULE_ENABLED
+/*#define HAL_USART_MODULE_ENABLED   */
+/*#define HAL_WWDG_MODULE_ENABLED   */
+
+#define HAL_CORTEX_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_EXTI_MODULE_ENABLED
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+
+/* ########################## Oscillator Values adaptation ####################*/
+/**
+  * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+  *        This value is used by the RCC HAL module to compute the system frequency
+  *        (when HSE is used as system clock source, directly or through the PLL).
+  */
+#if !defined  (HSE_VALUE)
+  #define HSE_VALUE    8000000U /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined  (HSE_STARTUP_TIMEOUT)
+  #define HSE_STARTUP_TIMEOUT    100U   /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+  * @brief Internal High Speed oscillator (HSI) value.
+  *        This value is used by the RCC HAL module to compute the system frequency
+  *        (when HSI is used as system clock source, directly or through the PLL).
+  */
+#if !defined  (HSI_VALUE)
+  #define HSI_VALUE    8000000U /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+  * @brief Internal Low Speed oscillator (LSI) value.
+  */
+#if !defined  (LSI_VALUE)
+ #define LSI_VALUE               40000U    /*!< LSI Typical Value in Hz */
+#endif /* LSI_VALUE */                     /*!< Value of the Internal Low Speed oscillator in Hz
+                                                The real value may vary depending on the variations
+                                                in voltage and temperature. */
+
+/**
+  * @brief External Low Speed oscillator (LSE) value.
+  *        This value is used by the UART, RTC HAL module to compute the system frequency
+  */
+#if !defined  (LSE_VALUE)
+  #define LSE_VALUE    32768U /*!< Value of the External oscillator in Hz*/
+#endif /* LSE_VALUE */
+
+#if !defined  (LSE_STARTUP_TIMEOUT)
+  #define LSE_STARTUP_TIMEOUT    5000U   /*!< Time out for LSE start up, in ms */
+#endif /* LSE_STARTUP_TIMEOUT */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+   ===  you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+  * @brief This is the HAL system configuration section
+  */
+#define  VDD_VALUE                    3300U /*!< Value of VDD in mv */
+#define  TICK_INT_PRIORITY            15U    /*!< tick interrupt priority (lowest by default)  */
+#define  USE_RTOS                     0U
+#define  PREFETCH_ENABLE              1U
+
+#define  USE_HAL_ADC_REGISTER_CALLBACKS         0U /* ADC register callback disabled       */
+#define  USE_HAL_CAN_REGISTER_CALLBACKS         0U /* CAN register callback disabled       */
+#define  USE_HAL_CEC_REGISTER_CALLBACKS         0U /* CEC register callback disabled       */
+#define  USE_HAL_DAC_REGISTER_CALLBACKS         0U /* DAC register callback disabled       */
+#define  USE_HAL_ETH_REGISTER_CALLBACKS         0U /* ETH register callback disabled       */
+#define  USE_HAL_HCD_REGISTER_CALLBACKS         0U /* HCD register callback disabled       */
+#define  USE_HAL_I2C_REGISTER_CALLBACKS         0U /* I2C register callback disabled       */
+#define  USE_HAL_I2S_REGISTER_CALLBACKS         0U /* I2S register callback disabled       */
+#define  USE_HAL_MMC_REGISTER_CALLBACKS         0U /* MMC register callback disabled       */
+#define  USE_HAL_NAND_REGISTER_CALLBACKS        0U /* NAND register callback disabled      */
+#define  USE_HAL_NOR_REGISTER_CALLBACKS         0U /* NOR register callback disabled       */
+#define  USE_HAL_PCCARD_REGISTER_CALLBACKS      0U /* PCCARD register callback disabled    */
+#define  USE_HAL_PCD_REGISTER_CALLBACKS         0U /* PCD register callback disabled       */
+#define  USE_HAL_RTC_REGISTER_CALLBACKS         0U /* RTC register callback disabled       */
+#define  USE_HAL_SD_REGISTER_CALLBACKS          0U /* SD register callback disabled        */
+#define  USE_HAL_SMARTCARD_REGISTER_CALLBACKS   0U /* SMARTCARD register callback disabled */
+#define  USE_HAL_IRDA_REGISTER_CALLBACKS        0U /* IRDA register callback disabled      */
+#define  USE_HAL_SRAM_REGISTER_CALLBACKS        0U /* SRAM register callback disabled      */
+#define  USE_HAL_SPI_REGISTER_CALLBACKS         0U /* SPI register callback disabled       */
+#define  USE_HAL_TIM_REGISTER_CALLBACKS         0U /* TIM register callback disabled       */
+#define  USE_HAL_UART_REGISTER_CALLBACKS        0U /* UART register callback disabled      */
+#define  USE_HAL_USART_REGISTER_CALLBACKS       0U /* USART register callback disabled     */
+#define  USE_HAL_WWDG_REGISTER_CALLBACKS        0U /* WWDG register callback disabled      */
+
+/* ########################## Assert Selection ############################## */
+/**
+  * @brief Uncomment the line below to expanse the "assert_param" macro in the
+  *        HAL drivers code
+  */
+/* #define USE_FULL_ASSERT    1U */
+
+/* ################## Ethernet peripheral configuration ##################### */
+
+/* Section 1 : Ethernet peripheral configuration */
+
+/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
+#define MAC_ADDR0   2U
+#define MAC_ADDR1   0U
+#define MAC_ADDR2   0U
+#define MAC_ADDR3   0U
+#define MAC_ADDR4   0U
+#define MAC_ADDR5   0U
+
+/* Definition of the Ethernet driver buffers size and count */
+#define ETH_RX_BUF_SIZE                ETH_MAX_PACKET_SIZE /* buffer size for receive               */
+#define ETH_TX_BUF_SIZE                ETH_MAX_PACKET_SIZE /* buffer size for transmit              */
+#define ETH_RXBUFNB                    8U       /* 4 Rx buffers of size ETH_RX_BUF_SIZE  */
+#define ETH_TXBUFNB                    4U       /* 4 Tx buffers of size ETH_TX_BUF_SIZE  */
+
+/* Section 2: PHY configuration section */
+
+/* DP83848_PHY_ADDRESS Address*/
+#define DP83848_PHY_ADDRESS           0x01U
+/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
+#define PHY_RESET_DELAY                 0x000000FFU
+/* PHY Configuration delay */
+#define PHY_CONFIG_DELAY                0x00000FFFU
+
+#define PHY_READ_TO                     0x0000FFFFU
+#define PHY_WRITE_TO                    0x0000FFFFU
+
+/* Section 3: Common PHY Registers */
+
+#define PHY_BCR                         ((uint16_t)0x00)    /*!< Transceiver Basic Control Register   */
+#define PHY_BSR                         ((uint16_t)0x01)    /*!< Transceiver Basic Status Register    */
+
+#define PHY_RESET                       ((uint16_t)0x8000)  /*!< PHY Reset */
+#define PHY_LOOPBACK                    ((uint16_t)0x4000)  /*!< Select loop-back mode */
+#define PHY_FULLDUPLEX_100M             ((uint16_t)0x2100)  /*!< Set the full-duplex mode at 100 Mb/s */
+#define PHY_HALFDUPLEX_100M             ((uint16_t)0x2000)  /*!< Set the half-duplex mode at 100 Mb/s */
+#define PHY_FULLDUPLEX_10M              ((uint16_t)0x0100)  /*!< Set the full-duplex mode at 10 Mb/s  */
+#define PHY_HALFDUPLEX_10M              ((uint16_t)0x0000)  /*!< Set the half-duplex mode at 10 Mb/s  */
+#define PHY_AUTONEGOTIATION             ((uint16_t)0x1000)  /*!< Enable auto-negotiation function     */
+#define PHY_RESTART_AUTONEGOTIATION     ((uint16_t)0x0200)  /*!< Restart auto-negotiation function    */
+#define PHY_POWERDOWN                   ((uint16_t)0x0800)  /*!< Select the power down mode           */
+#define PHY_ISOLATE                     ((uint16_t)0x0400)  /*!< Isolate PHY from MII                 */
+
+#define PHY_AUTONEGO_COMPLETE           ((uint16_t)0x0020)  /*!< Auto-Negotiation process completed   */
+#define PHY_LINKED_STATUS               ((uint16_t)0x0004)  /*!< Valid link established               */
+#define PHY_JABBER_DETECTION            ((uint16_t)0x0002)  /*!< Jabber condition detected            */
+
+/* Section 4: Extended PHY Registers */
+#define PHY_SR                          ((uint16_t)0x10U)    /*!< PHY status register Offset                      */
+
+#define PHY_SPEED_STATUS                ((uint16_t)0x0002U)  /*!< PHY Speed mask                                  */
+#define PHY_DUPLEX_STATUS               ((uint16_t)0x0004U)  /*!< PHY Duplex mask                                 */
+
+/* ################## SPI peripheral configuration ########################## */
+
+/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
+* Activated: CRC code is present inside driver
+* Deactivated: CRC code cleaned from driver
+*/
+
+#define USE_SPI_CRC                     0U
+
+/* Includes ------------------------------------------------------------------*/
+/**
+  * @brief Include module's header file
+  */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+#include "stm32f1xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+#include "stm32f1xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_EXTI_MODULE_ENABLED
+#include "stm32f1xx_hal_exti.h"
+#endif /* HAL_EXTI_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+#include "stm32f1xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+#include "stm32f1xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_CAN_MODULE_ENABLED
+#include "stm32f1xx_hal_can.h"
+#endif /* HAL_CAN_MODULE_ENABLED */
+
+#ifdef HAL_CAN_LEGACY_MODULE_ENABLED
+  #include "Legacy/stm32f1xx_hal_can_legacy.h"
+#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */
+
+#ifdef HAL_CEC_MODULE_ENABLED
+#include "stm32f1xx_hal_cec.h"
+#endif /* HAL_CEC_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+#include "stm32f1xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+#include "stm32f1xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+#include "stm32f1xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+#include "stm32f1xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+#include "stm32f1xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+#include "stm32f1xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+#include "stm32f1xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+#include "stm32f1xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+#include "stm32f1xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+#include "stm32f1xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+#include "stm32f1xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+#include "stm32f1xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_PCCARD_MODULE_ENABLED
+#include "stm32f1xx_hal_pccard.h"
+#endif /* HAL_PCCARD_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+#include "stm32f1xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+#include "stm32f1xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+#include "stm32f1xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+#include "stm32f1xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+#include "stm32f1xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+#include "stm32f1xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+#include "stm32f1xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+#include "stm32f1xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+#include "stm32f1xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+#include "stm32f1xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+#include "stm32f1xx_hal_hcd.h"
+#endif /* HAL_HCD_MODULE_ENABLED */
+
+#ifdef HAL_MMC_MODULE_ENABLED
+#include "stm32f1xx_hal_mmc.h"
+#endif /* HAL_MMC_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef  USE_FULL_ASSERT
+/**
+  * @brief  The assert_param macro is used for function's parameters check.
+  * @param  expr If expr is false, it calls assert_failed function
+  *         which reports the name of the source file and the source
+  *         line number of the call that failed.
+  *         If expr is true, it returns no value.
+  * @retval None
+  */
+#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+void assert_failed(uint8_t* file, uint32_t line);
+#else
+#define assert_param(expr) ((void)0U)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F1xx_HAL_CONF_H */
+

+ 58 - 0
Core/Inc/stm32f1xx_it.h

@@ -0,0 +1,58 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file    stm32f1xx_it.h
+  * @brief   This file contains the headers of the interrupt handlers.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2025 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F1xx_IT_H
+#define __STM32F1xx_IT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Private includes ----------------------------------------------------------*/
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* Exported types ------------------------------------------------------------*/
+/* USER CODE BEGIN ET */
+
+/* USER CODE END ET */
+
+/* Exported constants --------------------------------------------------------*/
+/* USER CODE BEGIN EC */
+
+/* USER CODE END EC */
+
+/* Exported macro ------------------------------------------------------------*/
+/* USER CODE BEGIN EM */
+
+/* USER CODE END EM */
+
+/* Exported functions prototypes ---------------------------------------------*/
+void SysTick_Handler(void);
+/* USER CODE BEGIN EFP */
+
+/* USER CODE END EFP */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F1xx_IT_H */

+ 370 - 0
Core/Src/epd.c

@@ -0,0 +1,370 @@
+/*****************************************************************************
+* | File      	:  	EPD_2in13_V4.c
+* | Author      :   Waveshare team
+* | Function    :   2.13inch e-paper V4
+* | Info        :
+*----------------
+* |	This version:   V1.1
+* | Date        :   2021-10-30
+* | Info        :
+* -----------------------------------------------------------------------------
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documnetation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to  whom the Software is
+# furished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+******************************************************************************/
+#include "epd.h"
+#include "debug.h"
+
+/******************************************************************************
+function :	Software reset
+parameter:
+******************************************************************************/
+static void EPD_2in13_V4_Reset(void)
+{
+    DEV_Digital_Write(EPD_RST_PIN, 1);
+    DEV_Delay_ms(20);
+    DEV_Digital_Write(EPD_RST_PIN, 0);
+    DEV_Delay_ms(2);
+    DEV_Digital_Write(EPD_RST_PIN, 1);
+    DEV_Delay_ms(20);
+}
+
+/******************************************************************************
+function :	send command
+parameter:
+     Reg : Command register
+******************************************************************************/
+static void EPD_2in13_V4_SendCommand(UBYTE Reg)
+{
+    DEV_Digital_Write(EPD_DC_PIN, 0);
+    DEV_Digital_Write(EPD_CS_PIN, 0);
+    DEV_SPI_WriteByte(Reg);
+    DEV_Digital_Write(EPD_CS_PIN, 1);
+}
+
+/******************************************************************************
+function :	send data
+parameter:
+    Data : Write data
+******************************************************************************/
+static void EPD_2in13_V4_SendData(UBYTE Data)
+{
+    DEV_Digital_Write(EPD_DC_PIN, 1);
+    DEV_Digital_Write(EPD_CS_PIN, 0);
+    DEV_SPI_WriteByte(Data);
+    DEV_Digital_Write(EPD_CS_PIN, 1);
+}
+
+/******************************************************************************
+function :	Wait until the busy_pin goes LOW
+parameter:
+******************************************************************************/
+void EPD_2in13_V4_ReadBusy(void)
+{
+    Debug("e-Paper busy\r\n");
+	while(1)
+	{	 //=1 BUSY
+		if(DEV_Digital_Read(EPD_BUSY_PIN)==0)
+			break;
+		DEV_Delay_ms(10);
+	}
+	DEV_Delay_ms(10);
+    Debug("e-Paper busy release\r\n");
+}
+
+/******************************************************************************
+function :	Setting the display window
+parameter:
+	Xstart : X-axis starting position
+	Ystart : Y-axis starting position
+	Xend : End position of X-axis
+	Yend : End position of Y-axis
+******************************************************************************/
+static void EPD_2in13_V4_SetWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend)
+{
+    EPD_2in13_V4_SendCommand(0x44); // SET_RAM_X_ADDRESS_START_END_POSITION
+    EPD_2in13_V4_SendData((Xstart>>3) & 0xFF);
+    EPD_2in13_V4_SendData((Xend>>3) & 0xFF);
+
+    EPD_2in13_V4_SendCommand(0x45); // SET_RAM_Y_ADDRESS_START_END_POSITION
+    EPD_2in13_V4_SendData(Ystart & 0xFF);
+    EPD_2in13_V4_SendData((Ystart >> 8) & 0xFF);
+    EPD_2in13_V4_SendData(Yend & 0xFF);
+    EPD_2in13_V4_SendData((Yend >> 8) & 0xFF);
+}
+
+/******************************************************************************
+function :	Set Cursor
+parameter:
+	Xstart : X-axis starting position
+	Ystart : Y-axis starting position
+******************************************************************************/
+static void EPD_2in13_V4_SetCursor(UWORD Xstart, UWORD Ystart)
+{
+    EPD_2in13_V4_SendCommand(0x4E); // SET_RAM_X_ADDRESS_COUNTER
+    EPD_2in13_V4_SendData(Xstart & 0xFF);
+
+    EPD_2in13_V4_SendCommand(0x4F); // SET_RAM_Y_ADDRESS_COUNTER
+    EPD_2in13_V4_SendData(Ystart & 0xFF);
+    EPD_2in13_V4_SendData((Ystart >> 8) & 0xFF);
+}
+
+/******************************************************************************
+function :	Turn On Display
+parameter:
+******************************************************************************/
+static void EPD_2in13_V4_TurnOnDisplay(void)
+{
+	EPD_2in13_V4_SendCommand(0x22); // Display Update Control
+	EPD_2in13_V4_SendData(0xf7);
+	EPD_2in13_V4_SendCommand(0x20); // Activate Display Update Sequence
+	EPD_2in13_V4_ReadBusy();
+}
+
+static void EPD_2in13_V4_TurnOnDisplay_Fast(void)
+{
+	EPD_2in13_V4_SendCommand(0x22); // Display Update Control
+	EPD_2in13_V4_SendData(0xc7);	// fast:0x0c, quality:0x0f, 0xcf
+	EPD_2in13_V4_SendCommand(0x20); // Activate Display Update Sequence
+	EPD_2in13_V4_ReadBusy();
+}
+
+static void EPD_2in13_V4_TurnOnDisplay_Partial(void)
+{
+	EPD_2in13_V4_SendCommand(0x22); // Display Update Control
+	EPD_2in13_V4_SendData(0xff);	// fast:0x0c, quality:0x0f, 0xcf
+	EPD_2in13_V4_SendCommand(0x20); // Activate Display Update Sequence
+	EPD_2in13_V4_ReadBusy();
+}
+
+/******************************************************************************
+function :	Initialize the e-Paper register
+parameter:
+******************************************************************************/
+void EPD_2in13_V4_Init(void)
+{
+	EPD_2in13_V4_Reset();
+
+	EPD_2in13_V4_ReadBusy();
+	EPD_2in13_V4_SendCommand(0x12);  //SWRESET
+	EPD_2in13_V4_ReadBusy();
+
+	EPD_2in13_V4_SendCommand(0x01); //Driver output control
+	EPD_2in13_V4_SendData(0xF9);
+	EPD_2in13_V4_SendData(0x00);
+	EPD_2in13_V4_SendData(0x00);
+
+	EPD_2in13_V4_SendCommand(0x11); //data entry mode
+	EPD_2in13_V4_SendData(0x03);
+
+	EPD_2in13_V4_SetWindows(0, 0, EPD_2in13_V4_WIDTH-1, EPD_2in13_V4_HEIGHT-1);
+	EPD_2in13_V4_SetCursor(0, 0);
+
+	EPD_2in13_V4_SendCommand(0x3C); //BorderWavefrom
+	EPD_2in13_V4_SendData(0x05);
+
+	EPD_2in13_V4_SendCommand(0x21); //  Display update control
+	EPD_2in13_V4_SendData(0x00);
+	EPD_2in13_V4_SendData(0x80);
+
+	EPD_2in13_V4_SendCommand(0x18); //Read built-in temperature sensor
+	EPD_2in13_V4_SendData(0x80);
+	EPD_2in13_V4_ReadBusy();
+}
+
+void EPD_2in13_V4_Init_Fast(void)
+{
+	EPD_2in13_V4_Reset();
+
+	EPD_2in13_V4_SendCommand(0x12);  //SWRESET
+	EPD_2in13_V4_ReadBusy();
+
+	EPD_2in13_V4_SendCommand(0x18); //Read built-in temperature sensor
+	EPD_2in13_V4_SendData(0x80);
+
+	EPD_2in13_V4_SendCommand(0x11); //data entry mode
+	EPD_2in13_V4_SendData(0x03);
+
+	EPD_2in13_V4_SetWindows(0, 0, EPD_2in13_V4_WIDTH-1, EPD_2in13_V4_HEIGHT-1);
+	EPD_2in13_V4_SetCursor(0, 0);
+
+	EPD_2in13_V4_SendCommand(0x22); // Load temperature value
+	EPD_2in13_V4_SendData(0xB1);
+	EPD_2in13_V4_SendCommand(0x20);
+	EPD_2in13_V4_ReadBusy();
+
+	EPD_2in13_V4_SendCommand(0x1A); // Write to temperature register
+	EPD_2in13_V4_SendData(0x64);
+	EPD_2in13_V4_SendData(0x00);
+
+	EPD_2in13_V4_SendCommand(0x22); // Load temperature value
+	EPD_2in13_V4_SendData(0x91);
+	EPD_2in13_V4_SendCommand(0x20);
+	EPD_2in13_V4_ReadBusy();
+}
+
+/******************************************************************************
+function :	Clear screen
+parameter:
+******************************************************************************/
+void EPD_2in13_V4_Clear(void)
+{
+	UWORD Width, Height;
+    Width = (EPD_2in13_V4_WIDTH % 8 == 0)? (EPD_2in13_V4_WIDTH / 8 ): (EPD_2in13_V4_WIDTH / 8 + 1);
+    Height = EPD_2in13_V4_HEIGHT;
+
+    EPD_2in13_V4_SendCommand(0x24);
+    for (UWORD j = 0; j < Height; j++) {
+        for (UWORD i = 0; i < Width; i++) {
+            EPD_2in13_V4_SendData(0XFF);
+        }
+    }
+
+	EPD_2in13_V4_TurnOnDisplay();
+}
+
+void EPD_2in13_V4_Clear_Black(void)
+{
+	UWORD Width, Height;
+    Width = (EPD_2in13_V4_WIDTH % 8 == 0)? (EPD_2in13_V4_WIDTH / 8 ): (EPD_2in13_V4_WIDTH / 8 + 1);
+    Height = EPD_2in13_V4_HEIGHT;
+
+    EPD_2in13_V4_SendCommand(0x24);
+    for (UWORD j = 0; j < Height; j++) {
+        for (UWORD i = 0; i < Width; i++) {
+            EPD_2in13_V4_SendData(0X00);
+        }
+    }
+
+	EPD_2in13_V4_TurnOnDisplay();
+}
+
+/******************************************************************************
+function :	Sends the image buffer in RAM to e-Paper and displays
+parameter:
+	Image : Image data
+******************************************************************************/
+void EPD_2in13_V4_Display(UBYTE *Image)
+{
+	UWORD Width, Height;
+    Width = (EPD_2in13_V4_WIDTH % 8 == 0)? (EPD_2in13_V4_WIDTH / 8 ): (EPD_2in13_V4_WIDTH / 8 + 1);
+    Height = EPD_2in13_V4_HEIGHT;
+
+    EPD_2in13_V4_SendCommand(0x24);
+    for (UWORD j = 0; j < Height; j++) {
+        for (UWORD i = 0; i < Width; i++) {
+            EPD_2in13_V4_SendData(Image[i + j * Width]);
+        }
+    }
+
+	EPD_2in13_V4_TurnOnDisplay();
+}
+
+void EPD_2in13_V4_Display_Fast(UBYTE *Image)
+{
+	UWORD Width, Height;
+    Width = (EPD_2in13_V4_WIDTH % 8 == 0)? (EPD_2in13_V4_WIDTH / 8 ): (EPD_2in13_V4_WIDTH / 8 + 1);
+    Height = EPD_2in13_V4_HEIGHT;
+
+    EPD_2in13_V4_SendCommand(0x24);
+    for (UWORD j = 0; j < Height; j++) {
+        for (UWORD i = 0; i < Width; i++) {
+            EPD_2in13_V4_SendData(Image[i + j * Width]);
+        }
+    }
+
+	EPD_2in13_V4_TurnOnDisplay_Fast();
+}
+
+
+/******************************************************************************
+function :	Refresh a base image
+parameter:
+	Image : Image data
+******************************************************************************/
+void EPD_2in13_V4_Display_Base(UBYTE *Image)
+{
+	UWORD Width, Height;
+    Width = (EPD_2in13_V4_WIDTH % 8 == 0)? (EPD_2in13_V4_WIDTH / 8 ): (EPD_2in13_V4_WIDTH / 8 + 1);
+    Height = EPD_2in13_V4_HEIGHT;
+
+	EPD_2in13_V4_SendCommand(0x24);   //Write Black and White image to RAM
+    for (UWORD j = 0; j < Height; j++) {
+        for (UWORD i = 0; i < Width; i++) {
+			EPD_2in13_V4_SendData(Image[i + j * Width]);
+		}
+	}
+	EPD_2in13_V4_SendCommand(0x26);   //Write Black and White image to RAM
+    for (UWORD j = 0; j < Height; j++) {
+        for (UWORD i = 0; i < Width; i++) {
+			EPD_2in13_V4_SendData(Image[i + j * Width]);
+		}
+	}
+	EPD_2in13_V4_TurnOnDisplay();
+}
+
+/******************************************************************************
+function :	Sends the image buffer in RAM to e-Paper and partial refresh
+parameter:
+	Image : Image data
+******************************************************************************/
+void EPD_2in13_V4_Display_Partial(UBYTE *Image)
+{
+	UWORD Width, Height;
+    Width = (EPD_2in13_V4_WIDTH % 8 == 0)? (EPD_2in13_V4_WIDTH / 8 ): (EPD_2in13_V4_WIDTH / 8 + 1);
+    Height = EPD_2in13_V4_HEIGHT;
+
+	//Reset
+    DEV_Digital_Write(EPD_RST_PIN, 0);
+    DEV_Delay_ms(1);
+    DEV_Digital_Write(EPD_RST_PIN, 1);
+
+	EPD_2in13_V4_SendCommand(0x3C); //BorderWavefrom
+	EPD_2in13_V4_SendData(0x80);
+
+	EPD_2in13_V4_SendCommand(0x01); //Driver output control
+	EPD_2in13_V4_SendData(0xF9);
+	EPD_2in13_V4_SendData(0x00);
+	EPD_2in13_V4_SendData(0x00);
+
+	EPD_2in13_V4_SendCommand(0x11); //data entry mode
+	EPD_2in13_V4_SendData(0x03);
+
+	EPD_2in13_V4_SetWindows(0, 0, EPD_2in13_V4_WIDTH-1, EPD_2in13_V4_HEIGHT-1);
+	EPD_2in13_V4_SetCursor(0, 0);
+
+	EPD_2in13_V4_SendCommand(0x24);   //Write Black and White image to RAM
+    for (UWORD j = 0; j < Height; j++) {
+        for (UWORD i = 0; i < Width; i++) {
+			EPD_2in13_V4_SendData(Image[i + j * Width]);
+		}
+	}
+	EPD_2in13_V4_TurnOnDisplay_Partial();
+}
+
+/******************************************************************************
+function :	Enter sleep mode
+parameter:
+******************************************************************************/
+void EPD_2in13_V4_Sleep(void)
+{
+	EPD_2in13_V4_SendCommand(0x10); //enter deep sleep
+	EPD_2in13_V4_SendData(0x01);
+	DEV_Delay_ms(100);
+}

+ 149 - 0
Core/Src/epd_config.c

@@ -0,0 +1,149 @@
+/*****************************************************************************
+* | File      	:   DEV_Config.c
+* | Author      :   Waveshare team
+* | Function    :   Hardware underlying interface
+* | Info        :
+*                Used to shield the underlying layers of each master
+*                and enhance portability
+*----------------
+* |	This version:   V2.0
+* | Date        :   2018-10-30
+* | Info        :
+# ******************************************************************************
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documnetation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to  whom the Software is
+# furished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+******************************************************************************/
+#include "epd_config.h"
+#include "stm32f1xx_hal_spi.h"
+
+extern SPI_HandleTypeDef hspi1;
+void DEV_SPI_WriteByte(UBYTE value)
+{
+    HAL_SPI_Transmit(&hspi1, &value, 1, 1000);
+}
+
+void DEV_SPI_Write_nByte(UBYTE *value, UDOUBLE len)
+{
+    HAL_SPI_Transmit(&hspi1, value, len, 1000);
+}
+
+void DEV_GPIO_Mode(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, UWORD Mode)
+{
+
+    GPIO_InitTypeDef GPIO_InitStruct = {0};
+    if(Mode == 0) {
+        GPIO_InitStruct.Pin = GPIO_Pin;
+        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+        GPIO_InitStruct.Pull = GPIO_PULLUP;
+        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+	} else {
+		GPIO_InitStruct.Pin = GPIO_Pin;
+        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+		// Debug (" %d OUT \r\n",Pin);
+	}
+}
+
+void DEV_GPIO_Init()
+{
+    HAL_SPI_MspDeInit(&hspi1);
+
+    //HAL_SPI_DeInit(&hspi1);
+//    __HAL_RCC_SPI1_CLK_DISABLE();
+//    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_7);
+}
+
+void DEV_SPI_Init()
+{
+    HAL_SPI_MspInit(&hspi1);
+    //HAL_SPI_DeInit(&hspi1);
+//    __HAL_RCC_SPI1_CLK_DISABLE();
+//    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_7);
+}
+
+
+void DEV_SPI_SendData(UBYTE Reg)
+{
+	UBYTE i,j=Reg;
+	DEV_GPIO_Mode(EPD_MOSI_PIN, 1);
+    DEV_GPIO_Mode(EPD_SCLK_PIN, 1);
+	DEV_Digital_Write(EPD_CS_PIN, 0);
+	for(i = 0; i<8; i++)
+    {
+        DEV_Digital_Write(EPD_SCLK_PIN, 0);
+        if (j & 0x80)
+        {
+            DEV_Digital_Write(EPD_MOSI_PIN, 1);
+        }
+        else
+        {
+            DEV_Digital_Write(EPD_MOSI_PIN, 0);
+        }
+
+        DEV_Digital_Write(EPD_SCLK_PIN, 1);
+        j = j << 1;
+    }
+	DEV_Digital_Write(EPD_SCLK_PIN, 0);
+	DEV_Digital_Write(EPD_CS_PIN, 1);
+}
+
+UBYTE DEV_SPI_ReadData()
+{
+	UBYTE i,j=0xff;
+	DEV_GPIO_Mode(EPD_MOSI_PIN, 0);
+    DEV_GPIO_Mode(EPD_SCLK_PIN, 1);
+	DEV_Digital_Write(EPD_CS_PIN, 0);
+	for(i = 0; i<8; i++)
+	{
+		DEV_Digital_Write(EPD_SCLK_PIN, 0);
+		j = j << 1;
+		if (DEV_Digital_Read(EPD_MOSI_PIN))
+		{
+            j = j | 0x01;
+		}
+		else
+		{
+            j= j & 0xfe;
+		}
+		DEV_Digital_Write(EPD_SCLK_PIN, 1);
+	}
+	DEV_Digital_Write(EPD_SCLK_PIN, 0);
+	DEV_Digital_Write(EPD_CS_PIN, 1);
+	return j;
+}
+
+int DEV_Module_Init(void)
+{
+    DEV_Digital_Write(EPD_DC_PIN, 0);
+    DEV_Digital_Write(EPD_CS_PIN, 0);
+	//DEV_Digital_Write(EPD_PWR_PIN, 1);
+    DEV_Digital_Write(EPD_RST_PIN, 1);
+    return 0;
+}
+
+void DEV_Module_Exit(void)
+{
+    DEV_Digital_Write(EPD_DC_PIN, 0);
+    DEV_Digital_Write(EPD_CS_PIN, 0);
+
+    //close 5V
+	//DEV_Digital_Write(EPD_PWR_PIN, 0);
+    DEV_Digital_Write(EPD_RST_PIN, 0);
+}

+ 151 - 0
Core/Src/epd_test.c

@@ -0,0 +1,151 @@
+/*****************************************************************************
+* | File      	:   EPD_2in13_V4_test.c
+* | Author      :   Waveshare team
+* | Function    :   2.13inch e-paper V4 test demo
+* | Info        :
+*----------------
+* |	This version:   V1.0
+* | Date        :   2023-6-25
+* | Info        :
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documnetation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to  whom the Software is
+# furished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+******************************************************************************/
+#include "EPD_Test.h"
+#include "epd.h"
+#include <time.h>
+
+int EPD_test(void)
+{
+
+    Debug("EPD_2in13_V4_test Demo\r\n");
+    if(DEV_Module_Init()!=0){
+        return -1;
+    }
+
+    Debug("e-Paper Init and Clear...\r\n");
+	EPD_2in13_V4_Init();
+
+    EPD_2in13_V4_Clear();
+
+    //Create a new image cache
+    UBYTE *BlackImage;
+    UWORD Imagesize = ((EPD_2in13_V4_WIDTH % 8 == 0)? (EPD_2in13_V4_WIDTH / 8 ): (EPD_2in13_V4_WIDTH / 8 + 1)) * EPD_2in13_V4_HEIGHT;
+    if((BlackImage = (UBYTE *)malloc(Imagesize)) == NULL) {
+        Debug("Failed to apply for black memory...\r\n");
+        return -1;
+    }
+    Debug("Paint_NewImage\r\n");
+    Paint_NewImage(BlackImage, EPD_2in13_V4_WIDTH, EPD_2in13_V4_HEIGHT, 90, WHITE);
+	Paint_Clear(WHITE);
+
+
+#if 0   //show image for array
+    Debug("The e-paper quickly refreshes the display image\r\n");
+    EPD_2in13_V4_Init_Fast();
+    Paint_SelectImage(BlackImage);
+    Paint_Clear(WHITE);
+    //Paint_DrawBitMap(gImage_2in13);
+
+    EPD_2in13_V4_Display_Fast(BlackImage);
+    DEV_Delay_ms(2000);
+#endif
+
+#if 1  // Drawing on the image
+	Paint_NewImage(BlackImage, EPD_2in13_V4_WIDTH, EPD_2in13_V4_HEIGHT, 90, WHITE);
+    Debug("Drawing\r\n");
+    //1.Select Image
+    EPD_2in13_V4_Init();
+    Paint_SelectImage(BlackImage);
+    Paint_Clear(WHITE);
+
+    // 2.Drawing on the image
+    Paint_DrawPoint(5, 10, BLACK, DOT_PIXEL_1X1, DOT_STYLE_DFT);
+    Paint_DrawPoint(5, 25, BLACK, DOT_PIXEL_2X2, DOT_STYLE_DFT);
+    Paint_DrawPoint(5, 40, BLACK, DOT_PIXEL_3X3, DOT_STYLE_DFT);
+    Paint_DrawPoint(5, 55, BLACK, DOT_PIXEL_4X4, DOT_STYLE_DFT);
+
+    Paint_DrawLine(20, 10, 70, 60, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);
+    Paint_DrawLine(70, 10, 20, 60, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);
+    Paint_DrawRectangle(20, 10, 70, 60, BLACK, DOT_PIXEL_1X1, DRAW_FILL_EMPTY);
+    Paint_DrawRectangle(85, 10, 135, 60, BLACK, DOT_PIXEL_1X1, DRAW_FILL_FULL);
+
+    Paint_DrawLine(45, 15, 45, 55, BLACK, DOT_PIXEL_1X1, LINE_STYLE_DOTTED);
+    Paint_DrawLine(25, 35, 70, 35, BLACK, DOT_PIXEL_1X1, LINE_STYLE_DOTTED);
+    Paint_DrawCircle(45, 35, 20, BLACK, DOT_PIXEL_1X1, DRAW_FILL_EMPTY);
+    Paint_DrawCircle(110, 35, 20, WHITE, DOT_PIXEL_1X1, DRAW_FILL_FULL);
+
+    Paint_DrawString_EN(140, 15, "waveshare", &Font16, BLACK, WHITE);
+    Paint_DrawNum(140, 40, 123456789, &Font16, BLACK, WHITE);
+
+    EPD_2in13_V4_Display_Base(BlackImage);
+    DEV_Delay_ms(3000);
+#endif
+
+#if 1   //Partial refresh, example shows time
+	Paint_NewImage(BlackImage, EPD_2in13_V4_WIDTH, EPD_2in13_V4_HEIGHT, 90, WHITE);
+    Debug("Partial refresh\r\n");
+    Paint_SelectImage(BlackImage);
+
+    PAINT_TIME sPaint_time;
+    sPaint_time.Hour = 12;
+    sPaint_time.Min = 34;
+    sPaint_time.Sec = 56;
+    UBYTE num = 10;
+    for (;;) {
+        sPaint_time.Sec = sPaint_time.Sec + 1;
+        if (sPaint_time.Sec == 60) {
+            sPaint_time.Min = sPaint_time.Min + 1;
+            sPaint_time.Sec = 0;
+            if (sPaint_time.Min == 60) {
+                sPaint_time.Hour =  sPaint_time.Hour + 1;
+                sPaint_time.Min = 0;
+                if (sPaint_time.Hour == 24) {
+                    sPaint_time.Hour = 0;
+                    sPaint_time.Min = 0;
+                    sPaint_time.Sec = 0;
+                }
+            }
+        }
+        Paint_ClearWindows(150, 80, 150 + Font16.Width * 7, 80 + Font16.Height, WHITE);
+        Paint_DrawTime(150, 80, &sPaint_time, &Font16, WHITE, BLACK);
+
+        num = num - 1;
+        if(num == 0) {
+            break;
+        }
+		EPD_2in13_V4_Display_Partial(BlackImage);
+        DEV_Delay_ms(500);//Analog clock 1s
+    }
+#endif
+
+	Debug("Clear...\r\n");
+	EPD_2in13_V4_Init();
+    //EPD_2in13_V4_Clear();
+
+    Debug("Goto Sleep...\r\n");
+    EPD_2in13_V4_Sleep();
+    free(BlackImage);
+    BlackImage = NULL;
+    DEV_Delay_ms(2000);//important, at least 2s
+    // close 5V
+    Debug("close 5V, Module enters 0 power consumption ...\r\n");
+    DEV_Module_Exit();
+    return 0;
+}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1764 - 0
Core/Src/font16.c


+ 965 - 0
Core/Src/gui_paint.c

@@ -0,0 +1,965 @@
+/******************************************************************************
+* | File      	:   GUI_Paint.c
+* | Author      :   Waveshare electronics
+* | Function    :	Achieve drawing: draw points, lines, boxes, circles and
+*                   their size, solid dotted line, solid rectangle hollow
+*                   rectangle, solid circle hollow circle.
+* | Info        :
+*   Achieve display characters: Display a single character, string, number
+*   Achieve time display: adaptive size display time minutes and seconds
+*----------------
+* |	This version:   V3.1
+* | Date        :   2020-07-08
+* | Info        :
+* -----------------------------------------------------------------------------
+* V3.1(2020-07-08):
+* 1.Change: Paint_SetScale(UBYTE scale)
+*		 Add scale 7 for 5.65f e-Parper
+* 2.Change: Paint_SetPixel(UWORD Xpoint, UWORD Ypoint, UWORD Color)
+*		 Add the branch for scale 7
+* 3.Change: Paint_Clear(UWORD Color)
+*		 Add the branch for scale 7
+*
+* -----------------------------------------------------------------------------
+* V3.0(2019-04-18):
+* 1.Change:
+*    Paint_DrawPoint(..., DOT_STYLE DOT_STYLE)
+* => Paint_DrawPoint(..., DOT_STYLE Dot_Style)
+*    Paint_DrawLine(..., LINE_STYLE Line_Style, DOT_PIXEL Dot_Pixel)
+* => Paint_DrawLine(..., DOT_PIXEL Line_width, LINE_STYLE Line_Style)
+*    Paint_DrawRectangle(..., DRAW_FILL Filled, DOT_PIXEL Dot_Pixel)
+* => Paint_DrawRectangle(..., DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
+*    Paint_DrawCircle(..., DRAW_FILL Draw_Fill, DOT_PIXEL Dot_Pixel)
+* => Paint_DrawCircle(..., DOT_PIXEL Line_width, DRAW_FILL Draw_Filll)
+*
+* -----------------------------------------------------------------------------
+* V2.0(2018-11-15):
+* 1.add: Paint_NewImage()
+*    Create an image's properties
+* 2.add: Paint_SelectImage()
+*    Select the picture to be drawn
+* 3.add: Paint_SetRotate()
+*    Set the direction of the cache
+* 4.add: Paint_RotateImage()
+*    Can flip the picture, Support 0-360 degrees,
+*    but only 90.180.270 rotation is better
+* 4.add: Paint_SetMirroring()
+*    Can Mirroring the picture, horizontal, vertical, origin
+* 5.add: Paint_DrawString_CN()
+*    Can display Chinese(GB1312)
+*
+* -----------------------------------------------------------------------------
+* V1.0(2018-07-17):
+*   Create library
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documnetation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to  whom the Software is
+* furished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*
+******************************************************************************/
+#include "GUI_Paint.h"
+#include "epd_config.h"
+#include "Debug.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h> //memset()
+#include <math.h>
+
+PAINT Paint;
+
+/******************************************************************************
+function: Create Image
+parameter:
+    image   :   Pointer to the image cache
+    width   :   The width of the picture
+    Height  :   The height of the picture
+    Color   :   Whether the picture is inverted
+******************************************************************************/
+void Paint_NewImage(UBYTE *image, UWORD Width, UWORD Height, UWORD Rotate, UWORD Color)
+{
+    Paint.Image = NULL;
+    Paint.Image = image;
+
+    Paint.WidthMemory = Width;
+    Paint.HeightMemory = Height;
+    Paint.Color = Color;
+	Paint.Scale = 2;
+
+    Paint.WidthByte = (Width % 8 == 0)? (Width / 8 ): (Width / 8 + 1);
+    Paint.HeightByte = Height;
+//    printf("WidthByte = %d, HeightByte = %d\r\n", Paint.WidthByte, Paint.HeightByte);
+//    printf(" EPD_WIDTH / 8 = %d\r\n",  122 / 8);
+
+    Paint.Rotate = Rotate;
+    Paint.Mirror = MIRROR_NONE;
+
+    if(Rotate == ROTATE_0 || Rotate == ROTATE_180) {
+        Paint.Width = Width;
+        Paint.Height = Height;
+    } else {
+        Paint.Width = Height;
+        Paint.Height = Width;
+    }
+}
+
+/******************************************************************************
+function: Select Image
+parameter:
+    image : Pointer to the image cache
+******************************************************************************/
+void Paint_SelectImage(UBYTE *image)
+{
+    Paint.Image = image;
+}
+
+/******************************************************************************
+function: Select Image Rotate
+parameter:
+    Rotate : 0,90,180,270
+******************************************************************************/
+void Paint_SetRotate(UWORD Rotate)
+{
+    if(Rotate == ROTATE_0 || Rotate == ROTATE_90 || Rotate == ROTATE_180 || Rotate == ROTATE_270) {
+        Debug("Set image Rotate %d\r\n", Rotate);
+        Paint.Rotate = Rotate;
+    } else {
+        Debug("rotate = 0, 90, 180, 270\r\n");
+    }
+}
+
+void Paint_SetScale(UBYTE scale)
+{
+    if(scale == 2){
+        Paint.Scale = scale;
+        Paint.WidthByte = (Paint.WidthMemory % 8 == 0)? (Paint.WidthMemory / 8 ): (Paint.WidthMemory / 8 + 1);
+    }else if(scale == 4){
+        Paint.Scale = scale;
+        Paint.WidthByte = (Paint.WidthMemory % 4 == 0)? (Paint.WidthMemory / 4 ): (Paint.WidthMemory / 4 + 1);
+    }else if(scale == 6 || scale == 7){//Only applicable with 5in65 e-Paper
+				Paint.Scale = scale;
+				Paint.WidthByte = (Paint.WidthMemory % 2 == 0)? (Paint.WidthMemory / 2 ): (Paint.WidthMemory / 2 + 1);;
+		}else{
+        Debug("Set Scale Input parameter error\r\n");
+        Debug("Scale Only support: 2 4 7\r\n");
+    }
+}
+/******************************************************************************
+function:	Select Image mirror
+parameter:
+    mirror   :Not mirror,Horizontal mirror,Vertical mirror,Origin mirror
+******************************************************************************/
+void Paint_SetMirroring(UBYTE mirror)
+{
+    if(mirror == MIRROR_NONE || mirror == MIRROR_HORIZONTAL ||
+        mirror == MIRROR_VERTICAL || mirror == MIRROR_ORIGIN) {
+        Debug("mirror image x:%s, y:%s\r\n",(mirror & 0x01)? "mirror":"none", ((mirror >> 1) & 0x01)? "mirror":"none");
+        Paint.Mirror = mirror;
+    } else {
+        Debug("mirror should be MIRROR_NONE, MIRROR_HORIZONTAL, \
+        MIRROR_VERTICAL or MIRROR_ORIGIN\r\n");
+    }
+}
+
+/******************************************************************************
+function: Draw Pixels
+parameter:
+    Xpoint : At point X
+    Ypoint : At point Y
+    Color  : Painted colors
+******************************************************************************/
+void Paint_SetPixel(UWORD Xpoint, UWORD Ypoint, UWORD Color)
+{
+    if(Xpoint > Paint.Width || Ypoint > Paint.Height){
+        Debug("Exceeding display boundaries\r\n");
+        return;
+    }
+    UWORD X, Y;
+
+    switch(Paint.Rotate) {
+    case 0:
+        X = Xpoint;
+        Y = Ypoint;
+        break;
+    case 90:
+        X = Paint.WidthMemory - Ypoint - 1;
+        Y = Xpoint;
+        break;
+    case 180:
+        X = Paint.WidthMemory - Xpoint - 1;
+        Y = Paint.HeightMemory - Ypoint - 1;
+        break;
+    case 270:
+        X = Ypoint;
+        Y = Paint.HeightMemory - Xpoint - 1;
+        break;
+    default:
+        return;
+    }
+
+    switch(Paint.Mirror) {
+    case MIRROR_NONE:
+        break;
+    case MIRROR_HORIZONTAL:
+        X = Paint.WidthMemory - X - 1;
+        break;
+    case MIRROR_VERTICAL:
+        Y = Paint.HeightMemory - Y - 1;
+        break;
+    case MIRROR_ORIGIN:
+        X = Paint.WidthMemory - X - 1;
+        Y = Paint.HeightMemory - Y - 1;
+        break;
+    default:
+        return;
+    }
+
+    if(X > Paint.WidthMemory || Y > Paint.HeightMemory){
+        Debug("Exceeding display boundaries\r\n");
+        return;
+    }
+
+    if(Paint.Scale == 2){
+        UDOUBLE Addr = X / 8 + Y * Paint.WidthByte;
+        UBYTE Rdata = Paint.Image[Addr];
+        if(Color == BLACK)
+            Paint.Image[Addr] = Rdata & ~(0x80 >> (X % 8));
+        else
+            Paint.Image[Addr] = Rdata | (0x80 >> (X % 8));
+    }else if(Paint.Scale == 4){
+        UDOUBLE Addr = X / 4 + Y * Paint.WidthByte;
+        Color = Color % 4;//Guaranteed color scale is 4  --- 0~3
+        UBYTE Rdata = Paint.Image[Addr];
+
+        Rdata = Rdata & (~(0xC0 >> ((X % 4)*2)));
+        Paint.Image[Addr] = Rdata | ((Color << 6) >> ((X % 4)*2));
+    }else if(Paint.Scale == 6 || Paint.Scale == 7){
+		UDOUBLE Addr = X / 2  + Y * Paint.WidthByte;
+		UBYTE Rdata = Paint.Image[Addr];
+		Rdata = Rdata & (~(0xF0 >> ((X % 2)*4)));//Clear first, then set value
+		Paint.Image[Addr] = Rdata | ((Color << 4) >> ((X % 2)*4));
+		//printf("Add =  %d ,data = %d\r\n",Addr,Rdata);
+		}
+}
+
+/******************************************************************************
+function: Clear the color of the picture
+parameter:
+    Color : Painted colors
+******************************************************************************/
+void Paint_Clear(UWORD Color)
+{
+	if(Paint.Scale == 2) {
+		for (UWORD Y = 0; Y < Paint.HeightByte; Y++) {
+			for (UWORD X = 0; X < Paint.WidthByte; X++ ) {//8 pixel =  1 byte
+				UDOUBLE Addr = X + Y*Paint.WidthByte;
+				Paint.Image[Addr] = Color;
+			}
+		}
+    }else if(Paint.Scale == 4) {
+        for (UWORD Y = 0; Y < Paint.HeightByte; Y++) {
+			for (UWORD X = 0; X < Paint.WidthByte; X++ ) {
+				UDOUBLE Addr = X + Y*Paint.WidthByte;
+				Paint.Image[Addr] = (Color<<6)|(Color<<4)|(Color<<2)|Color;
+			}
+		}
+	}else if(Paint.Scale == 6 || Paint.Scale == 7) {
+		for (UWORD Y = 0; Y < Paint.HeightByte; Y++) {
+			for (UWORD X = 0; X < Paint.WidthByte; X++ ) {
+				UDOUBLE Addr = X + Y*Paint.WidthByte;
+				Paint.Image[Addr] = (Color<<4)|Color;
+			}
+		}
+	}
+}
+
+/******************************************************************************
+function: Clear the color of a window
+parameter:
+    Xstart : x starting point
+    Ystart : Y starting point
+    Xend   : x end point
+    Yend   : y end point
+    Color  : Painted colors
+******************************************************************************/
+void Paint_ClearWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color)
+{
+    UWORD X, Y;
+    for (Y = Ystart; Y < Yend; Y++) {
+        for (X = Xstart; X < Xend; X++) {//8 pixel =  1 byte
+            Paint_SetPixel(X, Y, Color);
+        }
+    }
+}
+
+/******************************************************************************
+function: Draw Point(Xpoint, Ypoint) Fill the color
+parameter:
+    Xpoint		: The Xpoint coordinate of the point
+    Ypoint		: The Ypoint coordinate of the point
+    Color		: Painted color
+    Dot_Pixel	: point size
+    Dot_Style	: point Style
+******************************************************************************/
+void Paint_DrawPoint(UWORD Xpoint, UWORD Ypoint, UWORD Color,
+                     DOT_PIXEL Dot_Pixel, DOT_STYLE Dot_Style)
+{
+    if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
+        Debug("Paint_DrawPoint Input exceeds the normal display range\r\n");
+				printf("Xpoint = %d , Paint.Width = %d  \r\n ",Xpoint,Paint.Width);
+				printf("Ypoint = %d , Paint.Height = %d  \r\n ",Ypoint,Paint.Height);
+        return;
+    }
+
+    int16_t XDir_Num , YDir_Num;
+    if (Dot_Style == DOT_FILL_AROUND) {
+        for (XDir_Num = 0; XDir_Num < 2 * Dot_Pixel - 1; XDir_Num++) {
+            for (YDir_Num = 0; YDir_Num < 2 * Dot_Pixel - 1; YDir_Num++) {
+                if(Xpoint + XDir_Num - Dot_Pixel < 0 || Ypoint + YDir_Num - Dot_Pixel < 0)
+                    break;
+                // printf("x = %d, y = %d\r\n", Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel);
+                Paint_SetPixel(Xpoint + XDir_Num - Dot_Pixel, Ypoint + YDir_Num - Dot_Pixel, Color);
+            }
+        }
+    } else {
+        for (XDir_Num = 0; XDir_Num <  Dot_Pixel; XDir_Num++) {
+            for (YDir_Num = 0; YDir_Num <  Dot_Pixel; YDir_Num++) {
+                Paint_SetPixel(Xpoint + XDir_Num - 1, Ypoint + YDir_Num - 1, Color);
+            }
+        }
+    }
+}
+
+/******************************************************************************
+function: Draw a line of arbitrary slope
+parameter:
+    Xstart :Starting Xpoint point coordinates
+    Ystart :Starting Xpoint point coordinates
+    Xend   :End point Xpoint coordinate
+    Yend   :End point Ypoint coordinate
+    Color  :The color of the line segment
+    Line_width : Line width
+    Line_Style: Solid and dotted lines
+******************************************************************************/
+void Paint_DrawLine(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend,
+                    UWORD Color, DOT_PIXEL Line_width, LINE_STYLE Line_Style)
+{
+    if (Xstart > Paint.Width || Ystart > Paint.Height ||
+        Xend > Paint.Width || Yend > Paint.Height) {
+        Debug("Paint_DrawLine Input exceeds the normal display range\r\n");
+        return;
+    }
+
+    UWORD Xpoint = Xstart;
+    UWORD Ypoint = Ystart;
+    int dx = (int)Xend - (int)Xstart >= 0 ? Xend - Xstart : Xstart - Xend;
+    int dy = (int)Yend - (int)Ystart <= 0 ? Yend - Ystart : Ystart - Yend;
+
+    // Increment direction, 1 is positive, -1 is counter;
+    int XAddway = Xstart < Xend ? 1 : -1;
+    int YAddway = Ystart < Yend ? 1 : -1;
+
+    //Cumulative error
+    int Esp = dx + dy;
+    char Dotted_Len = 0;
+
+    for (;;) {
+        Dotted_Len++;
+        //Painted dotted line, 2 point is really virtual
+        if (Line_Style == LINE_STYLE_DOTTED && Dotted_Len % 3 == 0) {
+            //Debug("LINE_DOTTED\r\n");
+            Paint_DrawPoint(Xpoint, Ypoint, IMAGE_BACKGROUND, Line_width, DOT_STYLE_DFT);
+            Dotted_Len = 0;
+        } else {
+            Paint_DrawPoint(Xpoint, Ypoint, Color, Line_width, DOT_STYLE_DFT);
+        }
+        if (2 * Esp >= dy) {
+            if (Xpoint == Xend)
+                break;
+            Esp += dy;
+            Xpoint += XAddway;
+        }
+        if (2 * Esp <= dx) {
+            if (Ypoint == Yend)
+                break;
+            Esp += dx;
+            Ypoint += YAddway;
+        }
+    }
+}
+
+/******************************************************************************
+function: Draw a rectangle
+parameter:
+    Xstart :Rectangular  Starting Xpoint point coordinates
+    Ystart :Rectangular  Starting Xpoint point coordinates
+    Xend   :Rectangular  End point Xpoint coordinate
+    Yend   :Rectangular  End point Ypoint coordinate
+    Color  :The color of the Rectangular segment
+    Line_width: Line width
+    Draw_Fill : Whether to fill the inside of the rectangle
+******************************************************************************/
+void Paint_DrawRectangle(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend,
+                         UWORD Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
+{
+    if (Xstart > Paint.Width || Ystart > Paint.Height ||
+        Xend > Paint.Width || Yend > Paint.Height) {
+        Debug("Input exceeds the normal display range\r\n");
+        return;
+    }
+
+    if (Draw_Fill) {
+        UWORD Ypoint;
+        for(Ypoint = Ystart; Ypoint < Yend; Ypoint++) {
+            Paint_DrawLine(Xstart, Ypoint, Xend, Ypoint, Color , Line_width, LINE_STYLE_SOLID);
+        }
+    } else {
+        Paint_DrawLine(Xstart, Ystart, Xend, Ystart, Color, Line_width, LINE_STYLE_SOLID);
+        Paint_DrawLine(Xstart, Ystart, Xstart, Yend, Color, Line_width, LINE_STYLE_SOLID);
+        Paint_DrawLine(Xend, Yend, Xend, Ystart, Color, Line_width, LINE_STYLE_SOLID);
+        Paint_DrawLine(Xend, Yend, Xstart, Yend, Color, Line_width, LINE_STYLE_SOLID);
+    }
+}
+
+/******************************************************************************
+function: Use the 8-point method to draw a circle of the
+            specified size at the specified position->
+parameter:
+    X_Center  :Center X coordinate
+    Y_Center  :Center Y coordinate
+    Radius    :circle Radius
+    Color     :The color of the :circle segment
+    Line_width: Line width
+    Draw_Fill : Whether to fill the inside of the Circle
+******************************************************************************/
+void Paint_DrawCircle(UWORD X_Center, UWORD Y_Center, UWORD Radius,
+                      UWORD Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
+{
+    if (X_Center > Paint.Width || Y_Center >= Paint.Height) {
+        Debug("Paint_DrawCircle Input exceeds the normal display range\r\n");
+        return;
+    }
+
+    //Draw a circle from(0, R) as a starting point
+    int16_t XCurrent, YCurrent;
+    XCurrent = 0;
+    YCurrent = Radius;
+
+    //Cumulative error,judge the next point of the logo
+    int16_t Esp = 3 - (Radius << 1 );
+
+    int16_t sCountY;
+    if (Draw_Fill == DRAW_FILL_FULL) {
+        while (XCurrent <= YCurrent ) { //Realistic circles
+            for (sCountY = XCurrent; sCountY <= YCurrent; sCountY ++ ) {
+                Paint_DrawPoint(X_Center + XCurrent, Y_Center + sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//1
+                Paint_DrawPoint(X_Center - XCurrent, Y_Center + sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//2
+                Paint_DrawPoint(X_Center - sCountY, Y_Center + XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//3
+                Paint_DrawPoint(X_Center - sCountY, Y_Center - XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//4
+                Paint_DrawPoint(X_Center - XCurrent, Y_Center - sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//5
+                Paint_DrawPoint(X_Center + XCurrent, Y_Center - sCountY, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//6
+                Paint_DrawPoint(X_Center + sCountY, Y_Center - XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);//7
+                Paint_DrawPoint(X_Center + sCountY, Y_Center + XCurrent, Color, DOT_PIXEL_DFT, DOT_STYLE_DFT);
+            }
+            if (Esp < 0 )
+                Esp += 4 * XCurrent + 6;
+            else {
+                Esp += 10 + 4 * (XCurrent - YCurrent );
+                YCurrent --;
+            }
+            XCurrent ++;
+        }
+    } else { //Draw a hollow circle
+        while (XCurrent <= YCurrent ) {
+            Paint_DrawPoint(X_Center + XCurrent, Y_Center + YCurrent, Color, Line_width, DOT_STYLE_DFT);//1
+            Paint_DrawPoint(X_Center - XCurrent, Y_Center + YCurrent, Color, Line_width, DOT_STYLE_DFT);//2
+            Paint_DrawPoint(X_Center - YCurrent, Y_Center + XCurrent, Color, Line_width, DOT_STYLE_DFT);//3
+            Paint_DrawPoint(X_Center - YCurrent, Y_Center - XCurrent, Color, Line_width, DOT_STYLE_DFT);//4
+            Paint_DrawPoint(X_Center - XCurrent, Y_Center - YCurrent, Color, Line_width, DOT_STYLE_DFT);//5
+            Paint_DrawPoint(X_Center + XCurrent, Y_Center - YCurrent, Color, Line_width, DOT_STYLE_DFT);//6
+            Paint_DrawPoint(X_Center + YCurrent, Y_Center - XCurrent, Color, Line_width, DOT_STYLE_DFT);//7
+            Paint_DrawPoint(X_Center + YCurrent, Y_Center + XCurrent, Color, Line_width, DOT_STYLE_DFT);//0
+
+            if (Esp < 0 )
+                Esp += 4 * XCurrent + 6;
+            else {
+                Esp += 10 + 4 * (XCurrent - YCurrent );
+                YCurrent --;
+            }
+            XCurrent ++;
+        }
+    }
+}
+
+/******************************************************************************
+function: Show English characters
+parameter:
+    Xpoint           :X coordinate
+    Ypoint           :Y coordinate
+    Acsii_Char       :To display the English characters
+    Font             :A structure pointer that displays a character size
+    Color_Foreground : Select the foreground color
+    Color_Background : Select the background color
+******************************************************************************/
+void Paint_DrawChar(UWORD Xpoint, UWORD Ypoint, const char Acsii_Char,
+                    sFONT* Font, UWORD Color_Foreground, UWORD Color_Background)
+{
+    UWORD Page, Column;
+
+    if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
+        Debug("Paint_DrawChar Input exceeds the normal display range\r\n");
+        return;
+    }
+
+    uint32_t Char_Offset = (Acsii_Char - ' ') * Font->Height * (Font->Width / 8 + (Font->Width % 8 ? 1 : 0));
+    const unsigned char *ptr = &Font->table[Char_Offset];
+
+    for (Page = 0; Page < Font->Height; Page ++ ) {
+        for (Column = 0; Column < Font->Width; Column ++ ) {
+
+            //To determine whether the font background color and screen background color is consistent
+            if (FONT_BACKGROUND == Color_Background) { //this process is to speed up the scan
+                if (*ptr & (0x80 >> (Column % 8)))
+                    Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Foreground);
+                    // Paint_DrawPoint(Xpoint + Column, Ypoint + Page, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
+            } else {
+                if (*ptr & (0x80 >> (Column % 8))) {
+                    Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Foreground);
+                    // Paint_DrawPoint(Xpoint + Column, Ypoint + Page, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
+                } else {
+                    Paint_SetPixel(Xpoint + Column, Ypoint + Page, Color_Background);
+                    // Paint_DrawPoint(Xpoint + Column, Ypoint + Page, Color_Background, DOT_PIXEL_DFT, DOT_STYLE_DFT);
+                }
+            }
+            //One pixel is 8 bits
+            if (Column % 8 == 7)
+                ptr++;
+        }// Write a line
+        if (Font->Width % 8 != 0)
+            ptr++;
+    }// Write all
+}
+
+/******************************************************************************
+function:	Display the string
+parameter:
+    Xstart           :X coordinate
+    Ystart           :Y coordinate
+    pString          :The first address of the English string to be displayed
+    Font             :A structure pointer that displays a character size
+    Color_Foreground : Select the foreground color
+    Color_Background : Select the background color
+******************************************************************************/
+void Paint_DrawString_EN(UWORD Xstart, UWORD Ystart, const char * pString,
+                         sFONT* Font, UWORD Color_Foreground, UWORD Color_Background)
+{
+    UWORD Xpoint = Xstart;
+    UWORD Ypoint = Ystart;
+
+    if (Xstart > Paint.Width || Ystart > Paint.Height) {
+        Debug("Paint_DrawString_EN Input exceeds the normal display range\r\n");
+        return;
+    }
+
+    while (* pString != '\0') {
+        //if X direction filled , reposition to(Xstart,Ypoint),Ypoint is Y direction plus the Height of the character
+        if ((Xpoint + Font->Width ) > Paint.Width ) {
+            Xpoint = Xstart;
+            Ypoint += Font->Height;
+        }
+
+        // If the Y direction is full, reposition to(Xstart, Ystart)
+        if ((Ypoint  + Font->Height ) > Paint.Height ) {
+            Xpoint = Xstart;
+            Ypoint = Ystart;
+        }
+        Paint_DrawChar(Xpoint, Ypoint, * pString, Font, Color_Background, Color_Foreground);
+
+        //The next character of the address
+        pString ++;
+
+        //The next word of the abscissa increases the font of the broadband
+        Xpoint += Font->Width;
+    }
+}
+
+
+/******************************************************************************
+function: Display the string
+parameter:
+    Xstart  :X coordinate
+    Ystart  :Y coordinate
+    pString :The first address of the Chinese string and English
+              string to be displayed
+    Font    :A structure pointer that displays a character size
+    Color_Foreground : Select the foreground color
+    Color_Background : Select the background color
+******************************************************************************/
+void Paint_DrawString_CN(UWORD Xstart, UWORD Ystart, const char * pString, cFONT* font,
+                        UWORD Color_Foreground, UWORD Color_Background)
+{
+    const char* p_text = pString;
+    int x = Xstart, y = Ystart;
+    int i, j,Num;
+
+    /* Send the string character by character on EPD */
+    while (*p_text != 0) {
+        if(*p_text <= 0x7F) {  //ASCII < 126
+            for(Num = 0; Num < font->size; Num++) {
+                if(*p_text== font->table[Num].index[0]) {
+                    const char* ptr = &font->table[Num].matrix[0];
+
+                    for (j = 0; j < font->Height; j++) {
+                        for (i = 0; i < font->Width; i++) {
+                            if (FONT_BACKGROUND == Color_Background) { //this process is to speed up the scan
+                                if (*ptr & (0x80 >> (i % 8))) {
+                                    Paint_SetPixel(x + i, y + j, Color_Foreground);
+                                    // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
+                                }
+                            } else {
+                                if (*ptr & (0x80 >> (i % 8))) {
+                                    Paint_SetPixel(x + i, y + j, Color_Foreground);
+                                    // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
+                                } else {
+                                    Paint_SetPixel(x + i, y + j, Color_Background);
+                                    // Paint_DrawPoint(x + i, y + j, Color_Background, DOT_PIXEL_DFT, DOT_STYLE_DFT);
+                                }
+                            }
+                            if (i % 8 == 7) {
+                                ptr++;
+                            }
+                        }
+                        if (font->Width % 8 != 0) {
+                            ptr++;
+                        }
+                    }
+                    break;
+                }
+            }
+            /* Point on the next character */
+            p_text += 1;
+            /* Decrement the column position by 16 */
+            x += font->ASCII_Width;
+        } else {        //Chinese
+            for(Num = 0; Num < font->size; Num++) {
+                if((*p_text== font->table[Num].index[0]) && (*(p_text+1) == font->table[Num].index[1])) {
+                    const char* ptr = &font->table[Num].matrix[0];
+
+                    for (j = 0; j < font->Height; j++) {
+                        for (i = 0; i < font->Width; i++) {
+                            if (FONT_BACKGROUND == Color_Background) { //this process is to speed up the scan
+                                if (*ptr & (0x80 >> (i % 8))) {
+                                    Paint_SetPixel(x + i, y + j, Color_Foreground);
+                                    // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
+                                }
+                            } else {
+                                if (*ptr & (0x80 >> (i % 8))) {
+                                    Paint_SetPixel(x + i, y + j, Color_Foreground);
+                                    // Paint_DrawPoint(x + i, y + j, Color_Foreground, DOT_PIXEL_DFT, DOT_STYLE_DFT);
+                                } else {
+                                    Paint_SetPixel(x + i, y + j, Color_Background);
+                                    // Paint_DrawPoint(x + i, y + j, Color_Background, DOT_PIXEL_DFT, DOT_STYLE_DFT);
+                                }
+                            }
+                            if (i % 8 == 7) {
+                                ptr++;
+                            }
+                        }
+                        if (font->Width % 8 != 0) {
+                            ptr++;
+                        }
+                    }
+                    break;
+                }
+            }
+            /* Point on the next character */
+            p_text += 2;
+            /* Decrement the column position by 16 */
+            x += font->Width;
+        }
+    }
+}
+
+/******************************************************************************
+function:	Display nummber
+parameter:
+    Xstart           :X coordinate
+    Ystart           : Y coordinate
+    Nummber          : The number displayed
+    Font             :A structure pointer that displays a character size
+    Color_Foreground : Select the foreground color
+    Color_Background : Select the background color
+******************************************************************************/
+#define  ARRAY_LEN 255
+void Paint_DrawNum(UWORD Xpoint, UWORD Ypoint, int32_t Nummber,
+                   sFONT* Font, UWORD Color_Foreground, UWORD Color_Background)
+{
+
+    int16_t Num_Bit = 0, Str_Bit = 0;
+    uint8_t Str_Array[ARRAY_LEN] = {0}, Num_Array[ARRAY_LEN] = {0};
+    uint8_t *pStr = Str_Array;
+
+    if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
+        Debug("Paint_DisNum Input exceeds the normal display range\r\n");
+        return;
+    }
+
+    //Converts a number to a string
+    do {
+        Num_Array[Num_Bit] = Nummber % 10 + '0';
+        Num_Bit++;
+        Nummber /= 10;
+    } while(Nummber);
+
+
+    //The string is inverted
+    while (Num_Bit > 0) {
+        Str_Array[Str_Bit] = Num_Array[Num_Bit - 1];
+        Str_Bit ++;
+        Num_Bit --;
+    }
+
+    //show
+    Paint_DrawString_EN(Xpoint, Ypoint, (const char*)pStr, Font, Color_Background, Color_Foreground);
+}
+
+/******************************************************************************
+function:	Display nummber (Able to display decimals)
+parameter:
+    Xstart           :X coordinate
+    Ystart           : Y coordinate
+    Nummber          : The number displayed
+    Font             :A structure pointer that displays a character size
+    Digit            : Fractional width
+    Color_Foreground : Select the foreground color
+    Color_Background : Select the background color
+******************************************************************************/
+void Paint_DrawNumDecimals(UWORD Xpoint, UWORD Ypoint, double Nummber,
+                    sFONT* Font, UWORD Digit, UWORD Color_Foreground, UWORD Color_Background)
+{
+    int16_t Num_Bit = 0, Str_Bit = 0;
+    uint8_t Str_Array[ARRAY_LEN] = {0}, Num_Array[ARRAY_LEN] = {0};
+    uint8_t *pStr = Str_Array;
+	int temp = Nummber;
+	float decimals;
+	uint8_t i;
+    if (Xpoint > Paint.Width || Ypoint > Paint.Height) {
+        Debug("Paint_DisNum Input exceeds the normal display range\r\n");
+        return;
+    }
+
+	if(Digit > 0) {
+		decimals = Nummber - temp;
+		for(i=Digit; i > 0; i--) {
+			decimals*=10;
+		}
+		temp = decimals;
+		//Converts a number to a string
+		for(i=Digit; i>0; i--) {
+			Num_Array[Num_Bit] = temp % 10 + '0';
+			Num_Bit++;
+			temp /= 10;
+		}
+		Num_Array[Num_Bit] = '.';
+		Num_Bit++;
+	}
+
+	temp = Nummber;
+    //Converts a number to a string
+    do {
+        Num_Array[Num_Bit] = temp % 10 + '0';
+        Num_Bit++;
+        temp /= 10;
+    } while(temp);
+
+    //The string is inverted
+    while (Num_Bit > 0) {
+        Str_Array[Str_Bit] = Num_Array[Num_Bit - 1];
+        Str_Bit ++;
+        Num_Bit --;
+    }
+
+    //show
+    Paint_DrawString_EN(Xpoint, Ypoint, (const char*)pStr, Font, Color_Background, Color_Foreground);
+}
+
+/******************************************************************************
+function:	Display time
+parameter:
+    Xstart           :X coordinate
+    Ystart           : Y coordinate
+    pTime            : Time-related structures
+    Font             :A structure pointer that displays a character size
+    Color_Foreground : Select the foreground color
+    Color_Background : Select the background color
+******************************************************************************/
+void Paint_DrawTime(UWORD Xstart, UWORD Ystart, PAINT_TIME *pTime, sFONT* Font,
+                    UWORD Color_Foreground, UWORD Color_Background)
+{
+    uint8_t value[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+
+    UWORD Dx = Font->Width;
+
+    //Write data into the cache
+    Paint_DrawChar(Xstart                           , Ystart, value[pTime->Hour / 10], Font, Color_Background, Color_Foreground);
+    Paint_DrawChar(Xstart + Dx                      , Ystart, value[pTime->Hour % 10], Font, Color_Background, Color_Foreground);
+    Paint_DrawChar(Xstart + Dx  + Dx / 4 + Dx / 2   , Ystart, ':'                    , Font, Color_Background, Color_Foreground);
+    Paint_DrawChar(Xstart + Dx * 2 + Dx / 2         , Ystart, value[pTime->Min / 10] , Font, Color_Background, Color_Foreground);
+    Paint_DrawChar(Xstart + Dx * 3 + Dx / 2         , Ystart, value[pTime->Min % 10] , Font, Color_Background, Color_Foreground);
+    Paint_DrawChar(Xstart + Dx * 4 + Dx / 2 - Dx / 4, Ystart, ':'                    , Font, Color_Background, Color_Foreground);
+    Paint_DrawChar(Xstart + Dx * 5                  , Ystart, value[pTime->Sec / 10] , Font, Color_Background, Color_Foreground);
+    Paint_DrawChar(Xstart + Dx * 6                  , Ystart, value[pTime->Sec % 10] , Font, Color_Background, Color_Foreground);
+}
+
+/******************************************************************************
+function:	Display monochrome bitmap
+parameter:
+    image_buffer :A picture data converted to a bitmap
+info:
+    Use a computer to convert the image into a corresponding array,
+    and then embed the array directly into Imagedata.cpp as a .c file.
+******************************************************************************/
+void Paint_DrawBitMap(const unsigned char* image_buffer)
+{
+    UWORD x, y;
+    UDOUBLE Addr = 0;
+
+    for (y = 0; y < Paint.HeightByte; y++) {
+        for (x = 0; x < Paint.WidthByte; x++) {//8 pixel =  1 byte
+            Addr = x + y * Paint.WidthByte;
+            Paint.Image[Addr] = (unsigned char)image_buffer[Addr];
+        }
+    }
+}
+
+/******************************************************************************
+function:	paste monochrome bitmap to a frame buff
+parameter:
+    image_buffer :A picture data converted to a bitmap
+    xStart: The starting x coordinate
+    yStart: The starting y coordinate
+    imageWidth: Original image width
+    imageHeight: Original image height
+    flipColor: Whether the color is reversed
+info:
+    Use this function to paste image data into a buffer
+******************************************************************************/
+void Paint_DrawBitMap_Paste(const unsigned char* image_buffer, UWORD xStart, UWORD yStart, UWORD imageWidth, UWORD imageHeight, UBYTE flipColor)
+{
+    UBYTE color, srcImage;
+    UWORD x, y;
+    UWORD width = (imageWidth%8==0 ? imageWidth/8 : imageWidth/8+1);
+
+    for (y = 0; y < imageHeight; y++) {
+        for (x = 0; x < imageWidth; x++) {
+            srcImage = image_buffer[y*width + x/8];
+            if(flipColor)
+                color = (((srcImage<<(x%8) & 0x80) == 0) ? 1 : 0);
+            else
+                color = (((srcImage<<(x%8) & 0x80) == 0) ? 0 : 1);
+            Paint_SetPixel(x+xStart, y+yStart, color);
+        }
+    }
+}
+
+///******************************************************************************
+//function:	SDisplay half of monochrome bitmap
+//parameter:
+//	Region : 1 Upper half
+//					 2 Lower half
+//info:
+//******************************************************************************/
+//void Paint_DrawBitMap_Half(const unsigned char* image_buffer, UBYTE Region)
+//{
+//    UWORD x, y;
+//    UDOUBLE Addr = 0;
+//
+//		if(Region == 1){
+//			for (y = 0; y < Paint.HeightByte; y++) {
+//					for (x = 0; x < Paint.WidthByte; x++) {//8 pixel =  1 byte
+//							Addr = x + y * Paint.WidthByte;
+//							Paint.Image[Addr] = (unsigned char)image_buffer[Addr];
+//					}
+//			}
+//		}else{
+//			for (y = 0; y < Paint.HeightByte; y++) {
+//					for (x = 0; x < Paint.WidthByte; x++) {//8 pixel =  1 byte
+//							Addr = x + y * Paint.WidthByte ;
+//							Paint.Image[Addr] = \
+//							(unsigned char)image_buffer[Addr+ (Paint.HeightByte)*Paint.WidthByte];
+//					}
+//			}
+//		}
+//}
+
+///******************************************************************************
+//function:	SDisplay half of monochrome bitmap
+//parameter:
+//	Region : 1 Upper half
+//					 2 Lower half
+//info:
+//******************************************************************************/
+//void Paint_DrawBitMap_OneQuarter(const unsigned char* image_buffer, UBYTE Region)
+//{
+//    UWORD x, y;
+//    UDOUBLE Addr = 0;
+//
+//		if(Region == 1){
+//			for (y = 0; y < Paint.HeightByte; y++) {
+//					for (x = 0; x < Paint.WidthByte; x++) {//8 pixel =  1 byte
+//							Addr = x + y * Paint.WidthByte;
+//							Paint.Image[Addr] = (unsigned char)image_buffer[Addr];
+//					}
+//			}
+//		}else if(Region == 2){
+//			for (y = 0; y < Paint.HeightByte; y++) {
+//					for (x = 0; x < Paint.WidthByte; x++) {//8 pixel =  1 byte
+//							Addr = x + y * Paint.WidthByte ;
+//							Paint.Image[Addr] = \
+//							(unsigned char)image_buffer[Addr+ (Paint.HeightByte)*Paint.WidthByte];
+//					}
+//			}
+//		}else if(Region == 3){
+//			for (y = 0; y < Paint.HeightByte; y++) {
+//					for (x = 0; x < Paint.WidthByte; x++) {//8 pixel =  1 byte
+//							Addr = x + y * Paint.WidthByte ;
+//							Paint.Image[Addr] = \
+//							(unsigned char)image_buffer[Addr+ (Paint.HeightByte)*Paint.WidthByte*2];
+//					}
+//			}
+//		}else if(Region == 4){
+//			for (y = 0; y < Paint.HeightByte; y++) {
+//					for (x = 0; x < Paint.WidthByte; x++) {//8 pixel =  1 byte
+//							Addr = x + y * Paint.WidthByte ;
+//							Paint.Image[Addr] = \
+//							(unsigned char)image_buffer[Addr+ (Paint.HeightByte)*Paint.WidthByte*3];
+//					}
+//			}
+//		}
+//}
+
+void Paint_DrawBitMap_Block(const unsigned char* image_buffer, UBYTE Region)
+{
+    UWORD x, y;
+    UDOUBLE Addr = 0;
+		for (y = 0; y < Paint.HeightByte; y++) {
+				for (x = 0; x < Paint.WidthByte; x++) {//8 pixel =  1 byte
+						Addr = x + y * Paint.WidthByte ;
+						Paint.Image[Addr] = \
+						(unsigned char)image_buffer[Addr+ (Paint.HeightByte)*Paint.WidthByte*(Region - 1)];
+				}
+		}
+}

+ 309 - 0
Core/Src/main.c

@@ -0,0 +1,309 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : main.c
+  * @brief          : Main program body
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2025 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* Private includes ----------------------------------------------------------*/
+/* USER CODE BEGIN Includes */
+#include "epd_test.h"
+
+/* USER CODE END Includes */
+
+/* Private typedef -----------------------------------------------------------*/
+/* USER CODE BEGIN PTD */
+
+/* USER CODE END PTD */
+
+/* Private define ------------------------------------------------------------*/
+/* USER CODE BEGIN PD */
+
+/* USER CODE END PD */
+
+/* Private macro -------------------------------------------------------------*/
+/* USER CODE BEGIN PM */
+
+/* USER CODE END PM */
+
+/* Private variables ---------------------------------------------------------*/
+SPI_HandleTypeDef hspi1;
+
+UART_HandleTypeDef huart1;
+
+/* USER CODE BEGIN PV */
+
+/* USER CODE END PV */
+
+/* Private function prototypes -----------------------------------------------*/
+void SystemClock_Config(void);
+static void MX_GPIO_Init(void);
+static void MX_SPI1_Init(void);
+static void MX_USART1_UART_Init(void);
+/* USER CODE BEGIN PFP */
+
+/* USER CODE END PFP */
+
+/* Private user code ---------------------------------------------------------*/
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/**
+  * @brief  The application entry point.
+  * @retval int
+  */
+int main(void)
+{
+
+  /* USER CODE BEGIN 1 */
+
+  /* USER CODE END 1 */
+
+  /* MCU Configuration--------------------------------------------------------*/
+
+  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
+  HAL_Init();
+
+  /* USER CODE BEGIN Init */
+
+  /* USER CODE END Init */
+
+  /* Configure the system clock */
+  SystemClock_Config();
+
+  /* USER CODE BEGIN SysInit */
+
+  /* USER CODE END SysInit */
+
+  /* Initialize all configured peripherals */
+  MX_GPIO_Init();
+  MX_SPI1_Init();
+  MX_USART1_UART_Init();
+  /* USER CODE BEGIN 2 */
+
+  EPD_test();
+
+  /* USER CODE END 2 */
+
+  /* Infinite loop */
+  /* USER CODE BEGIN WHILE */
+  while (1)
+  {
+    /* USER CODE END WHILE */
+
+    /* USER CODE BEGIN 3 */
+	  HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
+
+	  HAL_Delay(1000);
+  }
+  /* USER CODE END 3 */
+}
+
+/**
+  * @brief System Clock Configuration
+  * @retval None
+  */
+void SystemClock_Config(void)
+{
+  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+
+  /** Initializes the RCC Oscillators according to the specified parameters
+  * in the RCC_OscInitTypeDef structure.
+  */
+  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
+  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
+  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
+  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+  /** Initializes the CPU, AHB and APB buses clocks
+  */
+  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
+                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
+  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
+  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
+
+  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+}
+
+/**
+  * @brief SPI1 Initialization Function
+  * @param None
+  * @retval None
+  */
+static void MX_SPI1_Init(void)
+{
+
+  /* USER CODE BEGIN SPI1_Init 0 */
+
+  /* USER CODE END SPI1_Init 0 */
+
+  /* USER CODE BEGIN SPI1_Init 1 */
+
+  /* USER CODE END SPI1_Init 1 */
+  /* SPI1 parameter configuration*/
+  hspi1.Instance = SPI1;
+  hspi1.Init.Mode = SPI_MODE_MASTER;
+  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
+  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
+  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
+  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
+  hspi1.Init.NSS = SPI_NSS_SOFT;
+  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
+  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
+  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
+  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
+  hspi1.Init.CRCPolynomial = 10;
+  if (HAL_SPI_Init(&hspi1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  /* USER CODE BEGIN SPI1_Init 2 */
+
+  /* USER CODE END SPI1_Init 2 */
+
+}
+
+/**
+  * @brief USART1 Initialization Function
+  * @param None
+  * @retval None
+  */
+static void MX_USART1_UART_Init(void)
+{
+
+  /* USER CODE BEGIN USART1_Init 0 */
+
+  /* USER CODE END USART1_Init 0 */
+
+  /* USER CODE BEGIN USART1_Init 1 */
+
+  /* USER CODE END USART1_Init 1 */
+  huart1.Instance = USART1;
+  huart1.Init.BaudRate = 9600;
+  huart1.Init.WordLength = UART_WORDLENGTH_8B;
+  huart1.Init.StopBits = UART_STOPBITS_1;
+  huart1.Init.Parity = UART_PARITY_NONE;
+  huart1.Init.Mode = UART_MODE_TX_RX;
+  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
+  if (HAL_UART_Init(&huart1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  /* USER CODE BEGIN USART1_Init 2 */
+
+  /* USER CODE END USART1_Init 2 */
+
+}
+
+/**
+  * @brief GPIO Initialization Function
+  * @param None
+  * @retval None
+  */
+static void MX_GPIO_Init(void)
+{
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  /* USER CODE BEGIN MX_GPIO_Init_1 */
+
+  /* USER CODE END MX_GPIO_Init_1 */
+
+  /* GPIO Ports Clock Enable */
+  __HAL_RCC_GPIOC_CLK_ENABLE();
+  __HAL_RCC_GPIOD_CLK_ENABLE();
+  __HAL_RCC_GPIOA_CLK_ENABLE();
+  __HAL_RCC_GPIOB_CLK_ENABLE();
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(GPIOA, RST_Pin|DC_Pin|CS_Pin, GPIO_PIN_SET);
+
+  /*Configure GPIO pin : LED_Pin */
+  GPIO_InitStruct.Pin = LED_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);
+
+  /*Configure GPIO pins : RST_Pin DC_Pin CS_Pin */
+  GPIO_InitStruct.Pin = RST_Pin|DC_Pin|CS_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+  /*Configure GPIO pin : BUSY_Pin */
+  GPIO_InitStruct.Pin = BUSY_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  HAL_GPIO_Init(BUSY_GPIO_Port, &GPIO_InitStruct);
+
+  /* USER CODE BEGIN MX_GPIO_Init_2 */
+
+  /* USER CODE END MX_GPIO_Init_2 */
+}
+
+/* USER CODE BEGIN 4 */
+
+/* USER CODE END 4 */
+
+/**
+  * @brief  This function is executed in case of error occurrence.
+  * @retval None
+  */
+void Error_Handler(void)
+{
+  /* USER CODE BEGIN Error_Handler_Debug */
+  /* User can add his own implementation to report the HAL error return state */
+  __disable_irq();
+  while (1)
+  {
+  }
+  /* USER CODE END Error_Handler_Debug */
+}
+#ifdef USE_FULL_ASSERT
+/**
+  * @brief  Reports the name of the source file and the source line number
+  *         where the assert_param error has occurred.
+  * @param  file: pointer to the source file name
+  * @param  line: assert_param error line source number
+  * @retval None
+  */
+void assert_failed(uint8_t *file, uint32_t line)
+{
+  /* USER CODE BEGIN 6 */
+  /* User can add his own implementation to report the file name and line number,
+     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
+  /* USER CODE END 6 */
+}
+#endif /* USE_FULL_ASSERT */

+ 219 - 0
Core/Src/stm32f1xx_hal_msp.c

@@ -0,0 +1,219 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file         stm32f1xx_hal_msp.c
+  * @brief        This file provides code for the MSP Initialization
+  *               and de-Initialization codes.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2025 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* Private typedef -----------------------------------------------------------*/
+/* USER CODE BEGIN TD */
+
+/* USER CODE END TD */
+
+/* Private define ------------------------------------------------------------*/
+/* USER CODE BEGIN Define */
+
+/* USER CODE END Define */
+
+/* Private macro -------------------------------------------------------------*/
+/* USER CODE BEGIN Macro */
+
+/* USER CODE END Macro */
+
+/* Private variables ---------------------------------------------------------*/
+/* USER CODE BEGIN PV */
+
+/* USER CODE END PV */
+
+/* Private function prototypes -----------------------------------------------*/
+/* USER CODE BEGIN PFP */
+
+/* USER CODE END PFP */
+
+/* External functions --------------------------------------------------------*/
+/* USER CODE BEGIN ExternalFunctions */
+
+/* USER CODE END ExternalFunctions */
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+/**
+  * Initializes the Global MSP.
+  */
+void HAL_MspInit(void)
+{
+
+  /* USER CODE BEGIN MspInit 0 */
+
+  /* USER CODE END MspInit 0 */
+
+  __HAL_RCC_AFIO_CLK_ENABLE();
+  __HAL_RCC_PWR_CLK_ENABLE();
+
+  /* System interrupt init*/
+
+  /** NOJTAG: JTAG-DP Disabled and SW-DP Enabled
+  */
+  __HAL_AFIO_REMAP_SWJ_NOJTAG();
+
+  /* USER CODE BEGIN MspInit 1 */
+
+  /* USER CODE END MspInit 1 */
+}
+
+/**
+  * @brief SPI MSP Initialization
+  * This function configures the hardware resources used in this example
+  * @param hspi: SPI handle pointer
+  * @retval None
+  */
+void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
+{
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(hspi->Instance==SPI1)
+  {
+    /* USER CODE BEGIN SPI1_MspInit 0 */
+
+    /* USER CODE END SPI1_MspInit 0 */
+    /* Peripheral clock enable */
+    __HAL_RCC_SPI1_CLK_ENABLE();
+
+    __HAL_RCC_GPIOA_CLK_ENABLE();
+    /**SPI1 GPIO Configuration
+    PA5     ------> SPI1_SCK
+    PA7     ------> SPI1_MOSI
+    */
+    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_7;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+    /* USER CODE BEGIN SPI1_MspInit 1 */
+
+    /* USER CODE END SPI1_MspInit 1 */
+
+  }
+
+}
+
+/**
+  * @brief SPI MSP De-Initialization
+  * This function freeze the hardware resources used in this example
+  * @param hspi: SPI handle pointer
+  * @retval None
+  */
+void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
+{
+  if(hspi->Instance==SPI1)
+  {
+    /* USER CODE BEGIN SPI1_MspDeInit 0 */
+
+    /* USER CODE END SPI1_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_SPI1_CLK_DISABLE();
+
+    /**SPI1 GPIO Configuration
+    PA5     ------> SPI1_SCK
+    PA7     ------> SPI1_MOSI
+    */
+    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_7);
+
+    /* USER CODE BEGIN SPI1_MspDeInit 1 */
+
+    /* USER CODE END SPI1_MspDeInit 1 */
+  }
+
+}
+
+/**
+  * @brief UART MSP Initialization
+  * This function configures the hardware resources used in this example
+  * @param huart: UART handle pointer
+  * @retval None
+  */
+void HAL_UART_MspInit(UART_HandleTypeDef* huart)
+{
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(huart->Instance==USART1)
+  {
+    /* USER CODE BEGIN USART1_MspInit 0 */
+
+    /* USER CODE END USART1_MspInit 0 */
+    /* Peripheral clock enable */
+    __HAL_RCC_USART1_CLK_ENABLE();
+
+    __HAL_RCC_GPIOA_CLK_ENABLE();
+    /**USART1 GPIO Configuration
+    PA9     ------> USART1_TX
+    PA10     ------> USART1_RX
+    */
+    GPIO_InitStruct.Pin = GPIO_PIN_9;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+    GPIO_InitStruct.Pin = GPIO_PIN_10;
+    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+    /* USER CODE BEGIN USART1_MspInit 1 */
+
+    /* USER CODE END USART1_MspInit 1 */
+
+  }
+
+}
+
+/**
+  * @brief UART MSP De-Initialization
+  * This function freeze the hardware resources used in this example
+  * @param huart: UART handle pointer
+  * @retval None
+  */
+void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
+{
+  if(huart->Instance==USART1)
+  {
+    /* USER CODE BEGIN USART1_MspDeInit 0 */
+
+    /* USER CODE END USART1_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_USART1_CLK_DISABLE();
+
+    /**USART1 GPIO Configuration
+    PA9     ------> USART1_TX
+    PA10     ------> USART1_RX
+    */
+    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
+
+    /* USER CODE BEGIN USART1_MspDeInit 1 */
+
+    /* USER CODE END USART1_MspDeInit 1 */
+  }
+
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */

+ 89 - 0
Core/Src/stm32f1xx_it.c

@@ -0,0 +1,89 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file    stm32f1xx_it.c
+  * @brief   Interrupt Service Routines.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2025 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+#include "stm32f1xx_it.h"
+/* Private includes ----------------------------------------------------------*/
+/* USER CODE BEGIN Includes */
+/* USER CODE END Includes */
+
+/* Private typedef -----------------------------------------------------------*/
+/* USER CODE BEGIN TD */
+
+/* USER CODE END TD */
+
+/* Private define ------------------------------------------------------------*/
+/* USER CODE BEGIN PD */
+
+/* USER CODE END PD */
+
+/* Private macro -------------------------------------------------------------*/
+/* USER CODE BEGIN PM */
+
+/* USER CODE END PM */
+
+/* Private variables ---------------------------------------------------------*/
+/* USER CODE BEGIN PV */
+
+/* USER CODE END PV */
+
+/* Private function prototypes -----------------------------------------------*/
+/* USER CODE BEGIN PFP */
+
+/* USER CODE END PFP */
+
+/* Private user code ---------------------------------------------------------*/
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/* External variables --------------------------------------------------------*/
+
+/* USER CODE BEGIN EV */
+
+/* USER CODE END EV */
+
+/******************************************************************************/
+/*           Cortex-M3 Processor Interruption and Exception Handlers          */
+/******************************************************************************/
+/**
+  * @brief This function handles System tick timer.
+  */
+void SysTick_Handler(void)
+{
+  /* USER CODE BEGIN SysTick_IRQn 0 */
+
+  /* USER CODE END SysTick_IRQn 0 */
+  HAL_IncTick();
+  /* USER CODE BEGIN SysTick_IRQn 1 */
+
+  /* USER CODE END SysTick_IRQn 1 */
+}
+
+/******************************************************************************/
+/* STM32F1xx Peripheral Interrupt Handlers                                    */
+/* Add here the Interrupt Handlers for the used peripherals.                  */
+/* For the available peripheral interrupt handler names,                      */
+/* please refer to the startup file (startup_stm32f1xx.s).                    */
+/******************************************************************************/
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */

+ 176 - 0
Core/Src/syscalls.c

@@ -0,0 +1,176 @@
+/**
+ ******************************************************************************
+ * @file      syscalls.c
+ * @author    Auto-generated by STM32CubeIDE
+ * @brief     STM32CubeIDE Minimal System calls file
+ *
+ *            For more information about which c-functions
+ *            need which of these lowlevel functions
+ *            please consult the Newlib libc-manual
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2020-2025 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Includes */
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+
+
+/* Variables */
+extern int __io_putchar(int ch) __attribute__((weak));
+extern int __io_getchar(void) __attribute__((weak));
+
+
+char *__env[1] = { 0 };
+char **environ = __env;
+
+
+/* Functions */
+void initialise_monitor_handles()
+{
+}
+
+int _getpid(void)
+{
+  return 1;
+}
+
+int _kill(int pid, int sig)
+{
+  (void)pid;
+  (void)sig;
+  errno = EINVAL;
+  return -1;
+}
+
+void _exit (int status)
+{
+  _kill(status, -1);
+  while (1) {}    /* Make sure we hang here */
+}
+
+__attribute__((weak)) int _read(int file, char *ptr, int len)
+{
+  (void)file;
+  int DataIdx;
+
+  for (DataIdx = 0; DataIdx < len; DataIdx++)
+  {
+    *ptr++ = __io_getchar();
+  }
+
+  return len;
+}
+
+__attribute__((weak)) int _write(int file, char *ptr, int len)
+{
+  (void)file;
+  int DataIdx;
+
+  for (DataIdx = 0; DataIdx < len; DataIdx++)
+  {
+    __io_putchar(*ptr++);
+  }
+  return len;
+}
+
+int _close(int file)
+{
+  (void)file;
+  return -1;
+}
+
+
+int _fstat(int file, struct stat *st)
+{
+  (void)file;
+  st->st_mode = S_IFCHR;
+  return 0;
+}
+
+int _isatty(int file)
+{
+  (void)file;
+  return 1;
+}
+
+int _lseek(int file, int ptr, int dir)
+{
+  (void)file;
+  (void)ptr;
+  (void)dir;
+  return 0;
+}
+
+int _open(char *path, int flags, ...)
+{
+  (void)path;
+  (void)flags;
+  /* Pretend like we always fail */
+  return -1;
+}
+
+int _wait(int *status)
+{
+  (void)status;
+  errno = ECHILD;
+  return -1;
+}
+
+int _unlink(char *name)
+{
+  (void)name;
+  errno = ENOENT;
+  return -1;
+}
+
+int _times(struct tms *buf)
+{
+  (void)buf;
+  return -1;
+}
+
+int _stat(char *file, struct stat *st)
+{
+  (void)file;
+  st->st_mode = S_IFCHR;
+  return 0;
+}
+
+int _link(char *old, char *new)
+{
+  (void)old;
+  (void)new;
+  errno = EMLINK;
+  return -1;
+}
+
+int _fork(void)
+{
+  errno = EAGAIN;
+  return -1;
+}
+
+int _execve(char *name, char **argv, char **env)
+{
+  (void)name;
+  (void)argv;
+  (void)env;
+  errno = ENOMEM;
+  return -1;
+}

+ 79 - 0
Core/Src/sysmem.c

@@ -0,0 +1,79 @@
+/**
+ ******************************************************************************
+ * @file      sysmem.c
+ * @author    Generated by STM32CubeIDE
+ * @brief     STM32CubeIDE System Memory calls file
+ *
+ *            For more information about which C functions
+ *            need which of these lowlevel functions
+ *            please consult the newlib libc manual
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2025 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Includes */
+#include <errno.h>
+#include <stdint.h>
+
+/**
+ * Pointer to the current high watermark of the heap usage
+ */
+static uint8_t *__sbrk_heap_end = NULL;
+
+/**
+ * @brief _sbrk() allocates memory to the newlib heap and is used by malloc
+ *        and others from the C library
+ *
+ * @verbatim
+ * ############################################################################
+ * #  .data  #  .bss  #       newlib heap       #          MSP stack          #
+ * #         #        #                         # Reserved by _Min_Stack_Size #
+ * ############################################################################
+ * ^-- RAM start      ^-- _end                             _estack, RAM end --^
+ * @endverbatim
+ *
+ * This implementation starts allocating at the '_end' linker symbol
+ * The '_Min_Stack_Size' linker symbol reserves a memory for the MSP stack
+ * The implementation considers '_estack' linker symbol to be RAM end
+ * NOTE: If the MSP stack, at any point during execution, grows larger than the
+ * reserved size, please increase the '_Min_Stack_Size'.
+ *
+ * @param incr Memory size
+ * @return Pointer to allocated memory
+ */
+void *_sbrk(ptrdiff_t incr)
+{
+  extern uint8_t _end; /* Symbol defined in the linker script */
+  extern uint8_t _estack; /* Symbol defined in the linker script */
+  extern uint32_t _Min_Stack_Size; /* Symbol defined in the linker script */
+  const uint32_t stack_limit = (uint32_t)&_estack - (uint32_t)&_Min_Stack_Size;
+  const uint8_t *max_heap = (uint8_t *)stack_limit;
+  uint8_t *prev_heap_end;
+
+  /* Initialize heap end at first call */
+  if (NULL == __sbrk_heap_end)
+  {
+    __sbrk_heap_end = &_end;
+  }
+
+  /* Protect heap from growing into the reserved MSP stack */
+  if (__sbrk_heap_end + incr > max_heap)
+  {
+    errno = ENOMEM;
+    return (void *)-1;
+  }
+
+  prev_heap_end = __sbrk_heap_end;
+  __sbrk_heap_end += incr;
+
+  return (void *)prev_heap_end;
+}

+ 406 - 0
Core/Src/system_stm32f1xx.c

@@ -0,0 +1,406 @@
+/**
+  ******************************************************************************
+  * @file    system_stm32f1xx.c
+  * @author  MCD Application Team
+  * @brief   CMSIS Cortex-M3 Device Peripheral Access Layer System Source File.
+  * 
+  * 1.  This file provides two functions and one global variable to be called from 
+  *     user application:
+  *      - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
+  *                      factors, AHB/APBx prescalers and Flash settings). 
+  *                      This function is called at startup just after reset and 
+  *                      before branch to main program. This call is made inside
+  *                      the "startup_stm32f1xx_xx.s" file.
+  *
+  *      - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+  *                                  by the user application to setup the SysTick 
+  *                                  timer or configure other parameters.
+  *                                     
+  *      - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+  *                                 be called whenever the core clock is changed
+  *                                 during program execution.
+  *
+  * 2. After each device reset the HSI (8 MHz) is used as system clock source.
+  *    Then SystemInit() function is called, in "startup_stm32f1xx_xx.s" file, to
+  *    configure the system clock before to branch to main program.
+  *
+  * 4. The default value of HSE crystal is set to 8 MHz (or 25 MHz, depending on
+  *    the product used), refer to "HSE_VALUE". 
+  *    When HSE is used as system clock source, directly or through PLL, and you
+  *    are using different crystal you have to adapt the HSE value to your own
+  *    configuration.
+  *        
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2017-2021 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/** @addtogroup CMSIS
+  * @{
+  */
+
+/** @addtogroup stm32f1xx_system
+  * @{
+  */  
+  
+/** @addtogroup STM32F1xx_System_Private_Includes
+  * @{
+  */
+
+#include "stm32f1xx.h"
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F1xx_System_Private_TypesDefinitions
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F1xx_System_Private_Defines
+  * @{
+  */
+
+#if !defined  (HSE_VALUE) 
+  #define HSE_VALUE               8000000U /*!< Default value of the External oscillator in Hz.
+                                                This value can be provided and adapted by the user application. */
+#endif /* HSE_VALUE */
+
+#if !defined  (HSI_VALUE)
+  #define HSI_VALUE               8000000U /*!< Default value of the Internal oscillator in Hz.
+                                                This value can be provided and adapted by the user application. */
+#endif /* HSI_VALUE */
+
+/*!< Uncomment the following line if you need to use external SRAM  */ 
+#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
+/* #define DATA_IN_ExtSRAM */
+#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */
+
+/* Note: Following vector table addresses must be defined in line with linker
+         configuration. */
+/*!< Uncomment the following line if you need to relocate the vector table
+     anywhere in Flash or Sram, else the vector table is kept at the automatic
+     remap of boot address selected */
+/* #define USER_VECT_TAB_ADDRESS */
+
+#if defined(USER_VECT_TAB_ADDRESS)
+/*!< Uncomment the following line if you need to relocate your vector Table
+     in Sram else user remap will be done in Flash. */
+/* #define VECT_TAB_SRAM */
+#if defined(VECT_TAB_SRAM)
+#define VECT_TAB_BASE_ADDRESS   SRAM_BASE       /*!< Vector Table base address field.
+                                                     This value must be a multiple of 0x200. */
+#define VECT_TAB_OFFSET         0x00000000U     /*!< Vector Table base offset field.
+                                                     This value must be a multiple of 0x200. */
+#else
+#define VECT_TAB_BASE_ADDRESS   FLASH_BASE      /*!< Vector Table base address field.
+                                                     This value must be a multiple of 0x200. */
+#define VECT_TAB_OFFSET         0x00000000U     /*!< Vector Table base offset field.
+                                                     This value must be a multiple of 0x200. */
+#endif /* VECT_TAB_SRAM */
+#endif /* USER_VECT_TAB_ADDRESS */
+
+/******************************************************************************/
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F1xx_System_Private_Macros
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F1xx_System_Private_Variables
+  * @{
+  */
+
+  /* This variable is updated in three ways:
+      1) by calling CMSIS function SystemCoreClockUpdate()
+      2) by calling HAL API function HAL_RCC_GetHCLKFreq()
+      3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency 
+         Note: If you use this function to configure the system clock; then there
+               is no need to call the 2 first functions listed above, since SystemCoreClock
+               variable is updated automatically.
+  */
+uint32_t SystemCoreClock = 8000000;
+const uint8_t AHBPrescTable[16U] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+const uint8_t APBPrescTable[8U] =  {0, 0, 0, 0, 1, 2, 3, 4};
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F1xx_System_Private_FunctionPrototypes
+  * @{
+  */
+
+#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
+#ifdef DATA_IN_ExtSRAM
+  static void SystemInit_ExtMemCtl(void); 
+#endif /* DATA_IN_ExtSRAM */
+#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32F1xx_System_Private_Functions
+  * @{
+  */
+
+/**
+  * @brief  Setup the microcontroller system
+  *         Initialize the Embedded Flash Interface, the PLL and update the 
+  *         SystemCoreClock variable.
+  * @note   This function should be used only after reset.
+  * @param  None
+  * @retval None
+  */
+void SystemInit (void)
+{
+#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
+  #ifdef DATA_IN_ExtSRAM
+    SystemInit_ExtMemCtl(); 
+  #endif /* DATA_IN_ExtSRAM */
+#endif 
+
+  /* Configure the Vector Table location -------------------------------------*/
+#if defined(USER_VECT_TAB_ADDRESS)
+  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
+#endif /* USER_VECT_TAB_ADDRESS */
+}
+
+/**
+  * @brief  Update SystemCoreClock variable according to Clock Register Values.
+  *         The SystemCoreClock variable contains the core clock (HCLK), it can
+  *         be used by the user application to setup the SysTick timer or configure
+  *         other parameters.
+  *           
+  * @note   Each time the core clock (HCLK) changes, this function must be called
+  *         to update SystemCoreClock variable value. Otherwise, any configuration
+  *         based on this variable will be incorrect.         
+  *     
+  * @note   - The system frequency computed by this function is not the real 
+  *           frequency in the chip. It is calculated based on the predefined 
+  *           constant and the selected clock source:
+  *             
+  *           - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+  *                                              
+  *           - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+  *                          
+  *           - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) 
+  *             or HSI_VALUE(*) multiplied by the PLL factors.
+  *         
+  *         (*) HSI_VALUE is a constant defined in stm32f1xx.h file (default value
+  *             8 MHz) but the real value may vary depending on the variations
+  *             in voltage and temperature.   
+  *    
+  *         (**) HSE_VALUE is a constant defined in stm32f1xx.h file (default value
+  *              8 MHz or 25 MHz, depending on the product used), user has to ensure
+  *              that HSE_VALUE is same as the real frequency of the crystal used.
+  *              Otherwise, this function may have wrong result.
+  *                
+  *         - The result of this function could be not correct when using fractional
+  *           value for HSE crystal.
+  * @param  None
+  * @retval None
+  */
+void SystemCoreClockUpdate (void)
+{
+  uint32_t tmp = 0U, pllmull = 0U, pllsource = 0U;
+
+#if defined(STM32F105xC) || defined(STM32F107xC)
+  uint32_t prediv1source = 0U, prediv1factor = 0U, prediv2factor = 0U, pll2mull = 0U;
+#endif /* STM32F105xC */
+
+#if defined(STM32F100xB) || defined(STM32F100xE)
+  uint32_t prediv1factor = 0U;
+#endif /* STM32F100xB or STM32F100xE */
+    
+  /* Get SYSCLK source -------------------------------------------------------*/
+  tmp = RCC->CFGR & RCC_CFGR_SWS;
+  
+  switch (tmp)
+  {
+    case 0x00U:  /* HSI used as system clock */
+      SystemCoreClock = HSI_VALUE;
+      break;
+    case 0x04U:  /* HSE used as system clock */
+      SystemCoreClock = HSE_VALUE;
+      break;
+    case 0x08U:  /* PLL used as system clock */
+
+      /* Get PLL clock source and multiplication factor ----------------------*/
+      pllmull = RCC->CFGR & RCC_CFGR_PLLMULL;
+      pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
+      
+#if !defined(STM32F105xC) && !defined(STM32F107xC)      
+      pllmull = ( pllmull >> 18U) + 2U;
+      
+      if (pllsource == 0x00U)
+      {
+        /* HSI oscillator clock divided by 2 selected as PLL clock entry */
+        SystemCoreClock = (HSI_VALUE >> 1U) * pllmull;
+      }
+      else
+      {
+ #if defined(STM32F100xB) || defined(STM32F100xE)
+       prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1U;
+       /* HSE oscillator clock selected as PREDIV1 clock entry */
+       SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; 
+ #else
+        /* HSE selected as PLL clock entry */
+        if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET)
+        {/* HSE oscillator clock divided by 2 */
+          SystemCoreClock = (HSE_VALUE >> 1U) * pllmull;
+        }
+        else
+        {
+          SystemCoreClock = HSE_VALUE * pllmull;
+        }
+ #endif
+      }
+#else
+      pllmull = pllmull >> 18U;
+      
+      if (pllmull != 0x0DU)
+      {
+         pllmull += 2U;
+      }
+      else
+      { /* PLL multiplication factor = PLL input clock * 6.5 */
+        pllmull = 13U / 2U; 
+      }
+            
+      if (pllsource == 0x00U)
+      {
+        /* HSI oscillator clock divided by 2 selected as PLL clock entry */
+        SystemCoreClock = (HSI_VALUE >> 1U) * pllmull;
+      }
+      else
+      {/* PREDIV1 selected as PLL clock entry */
+        
+        /* Get PREDIV1 clock source and division factor */
+        prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC;
+        prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1U;
+        
+        if (prediv1source == 0U)
+        { 
+          /* HSE oscillator clock selected as PREDIV1 clock entry */
+          SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;          
+        }
+        else
+        {/* PLL2 clock selected as PREDIV1 clock entry */
+          
+          /* Get PREDIV2 division factor and PLL2 multiplication factor */
+          prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4U) + 1U;
+          pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8U) + 2U; 
+          SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull;                         
+        }
+      }
+#endif /* STM32F105xC */ 
+      break;
+
+    default:
+      SystemCoreClock = HSI_VALUE;
+      break;
+  }
+  
+  /* Compute HCLK clock frequency ----------------*/
+  /* Get HCLK prescaler */
+  tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4U)];
+  /* HCLK clock frequency */
+  SystemCoreClock >>= tmp;  
+}
+
+#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
+/**
+  * @brief  Setup the external memory controller. Called in startup_stm32f1xx.s 
+  *          before jump to __main
+  * @param  None
+  * @retval None
+  */ 
+#ifdef DATA_IN_ExtSRAM
+/**
+  * @brief  Setup the external memory controller. 
+  *         Called in startup_stm32f1xx_xx.s/.c before jump to main.
+  *         This function configures the external SRAM mounted on STM3210E-EVAL
+  *         board (STM32 High density devices). This SRAM will be used as program
+  *         data memory (including heap and stack).
+  * @param  None
+  * @retval None
+  */ 
+void SystemInit_ExtMemCtl(void) 
+{
+  __IO uint32_t tmpreg;
+  /*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is 
+    required, then adjust the Register Addresses */
+
+  /* Enable FSMC clock */
+  RCC->AHBENR = 0x00000114U;
+
+  /* Delay after an RCC peripheral clock enabling */
+  tmpreg = READ_BIT(RCC->AHBENR, RCC_AHBENR_FSMCEN);
+  
+  /* Enable GPIOD, GPIOE, GPIOF and GPIOG clocks */
+  RCC->APB2ENR = 0x000001E0U;
+  
+  /* Delay after an RCC peripheral clock enabling */
+  tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPDEN);
+
+  (void)(tmpreg);
+  
+/* ---------------  SRAM Data lines, NOE and NWE configuration ---------------*/
+/*----------------  SRAM Address lines configuration -------------------------*/
+/*----------------  NOE and NWE configuration --------------------------------*/  
+/*----------------  NE3 configuration ----------------------------------------*/
+/*----------------  NBL0, NBL1 configuration ---------------------------------*/
+  
+  GPIOD->CRL = 0x44BB44BBU;  
+  GPIOD->CRH = 0xBBBBBBBBU;
+
+  GPIOE->CRL = 0xB44444BBU;  
+  GPIOE->CRH = 0xBBBBBBBBU;
+
+  GPIOF->CRL = 0x44BBBBBBU;  
+  GPIOF->CRH = 0xBBBB4444U;
+
+  GPIOG->CRL = 0x44BBBBBBU;  
+  GPIOG->CRH = 0x444B4B44U;
+   
+/*----------------  FSMC Configuration ---------------------------------------*/  
+/*----------------  Enable FSMC Bank1_SRAM Bank ------------------------------*/
+  
+  FSMC_Bank1->BTCR[4U] = 0x00001091U;
+  FSMC_Bank1->BTCR[5U] = 0x00110212U;
+}
+#endif /* DATA_IN_ExtSRAM */
+#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+  
+/**
+  * @}
+  */

+ 364 - 0
Core/Startup/startup_stm32f103c8tx.s

@@ -0,0 +1,364 @@
+/**
+  *************** (C) COPYRIGHT 2017 STMicroelectronics ************************
+  * @file      startup_stm32f103xb.s
+  * @author    MCD Application Team
+  * @brief     STM32F103xB Devices vector table for Atollic toolchain.
+  *            This module performs:
+  *                - Set the initial SP
+  *                - Set the initial PC == Reset_Handler,
+  *                - Set the vector table entries with the exceptions ISR address
+  *                - Configure the clock system   
+  *                - Branches to main in the C library (which eventually
+  *                  calls main()).
+  *            After Reset the Cortex-M3 processor is in Thread mode,
+  *            priority is Privileged, and the Stack is set to Main.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2017-2021 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+  .syntax unified
+  .cpu cortex-m3
+  .fpu softvfp
+  .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+
+.equ  BootRAM, 0xF108F85F
+/**
+ * @brief  This is the code that gets called when the processor first
+ *          starts execution following a reset event. Only the absolutely
+ *          necessary set is performed, after which the application
+ *          supplied main() routine is called.
+ * @param  None
+ * @retval : None
+*/
+
+  .section .text.Reset_Handler
+  .weak Reset_Handler
+  .type Reset_Handler, %function
+Reset_Handler:
+
+/* Call the clock system initialization function.*/
+    bl  SystemInit
+
+/* Copy the data segment initializers from flash to SRAM */
+  ldr r0, =_sdata
+  ldr r1, =_edata
+  ldr r2, =_sidata
+  movs r3, #0
+  b LoopCopyDataInit
+
+CopyDataInit:
+  ldr r4, [r2, r3]
+  str r4, [r0, r3]
+  adds r3, r3, #4
+
+LoopCopyDataInit:
+  adds r4, r0, r3
+  cmp r4, r1
+  bcc CopyDataInit
+  
+/* Zero fill the bss segment. */
+  ldr r2, =_sbss
+  ldr r4, =_ebss
+  movs r3, #0
+  b LoopFillZerobss
+
+FillZerobss:
+  str  r3, [r2]
+  adds r2, r2, #4
+
+LoopFillZerobss:
+  cmp r2, r4
+  bcc FillZerobss
+
+/* Call static constructors */
+    bl __libc_init_array
+/* Call the application's entry point.*/
+  bl main
+  bx lr
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief  This is the code that gets called when the processor receives an
+ *         unexpected interrupt.  This simply enters an infinite loop, preserving
+ *         the system state for examination by a debugger.
+ *
+ * @param  None
+ * @retval : None
+*/
+    .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+  b Infinite_Loop
+  .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M3.  Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+******************************************************************************/
+  .section .isr_vector,"a",%progbits
+  .type g_pfnVectors, %object
+  .size g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+
+  .word _estack
+  .word Reset_Handler
+  .word NMI_Handler
+  .word HardFault_Handler
+  .word MemManage_Handler
+  .word BusFault_Handler
+  .word UsageFault_Handler
+  .word 0
+  .word 0
+  .word 0
+  .word 0
+  .word SVC_Handler
+  .word DebugMon_Handler
+  .word 0
+  .word PendSV_Handler
+  .word SysTick_Handler
+  .word WWDG_IRQHandler
+  .word PVD_IRQHandler
+  .word TAMPER_IRQHandler
+  .word RTC_IRQHandler
+  .word FLASH_IRQHandler
+  .word RCC_IRQHandler
+  .word EXTI0_IRQHandler
+  .word EXTI1_IRQHandler
+  .word EXTI2_IRQHandler
+  .word EXTI3_IRQHandler
+  .word EXTI4_IRQHandler
+  .word DMA1_Channel1_IRQHandler
+  .word DMA1_Channel2_IRQHandler
+  .word DMA1_Channel3_IRQHandler
+  .word DMA1_Channel4_IRQHandler
+  .word DMA1_Channel5_IRQHandler
+  .word DMA1_Channel6_IRQHandler
+  .word DMA1_Channel7_IRQHandler
+  .word ADC1_2_IRQHandler
+  .word USB_HP_CAN1_TX_IRQHandler
+  .word USB_LP_CAN1_RX0_IRQHandler
+  .word CAN1_RX1_IRQHandler
+  .word CAN1_SCE_IRQHandler
+  .word EXTI9_5_IRQHandler
+  .word TIM1_BRK_IRQHandler
+  .word TIM1_UP_IRQHandler
+  .word TIM1_TRG_COM_IRQHandler
+  .word TIM1_CC_IRQHandler
+  .word TIM2_IRQHandler
+  .word TIM3_IRQHandler
+  .word TIM4_IRQHandler
+  .word I2C1_EV_IRQHandler
+  .word I2C1_ER_IRQHandler
+  .word I2C2_EV_IRQHandler
+  .word I2C2_ER_IRQHandler
+  .word SPI1_IRQHandler
+  .word SPI2_IRQHandler
+  .word USART1_IRQHandler
+  .word USART2_IRQHandler
+  .word USART3_IRQHandler
+  .word EXTI15_10_IRQHandler
+  .word RTC_Alarm_IRQHandler
+  .word USBWakeUp_IRQHandler
+  .word 0
+  .word 0
+  .word 0
+  .word 0
+  .word 0
+  .word 0
+  .word 0
+  .word BootRAM          /* @0x108. This is for boot in RAM mode for
+                            STM32F10x Medium Density devices. */
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+
+  .weak NMI_Handler
+  .thumb_set NMI_Handler,Default_Handler
+
+  .weak HardFault_Handler
+  .thumb_set HardFault_Handler,Default_Handler
+
+  .weak MemManage_Handler
+  .thumb_set MemManage_Handler,Default_Handler
+
+  .weak BusFault_Handler
+  .thumb_set BusFault_Handler,Default_Handler
+
+  .weak UsageFault_Handler
+  .thumb_set UsageFault_Handler,Default_Handler
+
+  .weak SVC_Handler
+  .thumb_set SVC_Handler,Default_Handler
+
+  .weak DebugMon_Handler
+  .thumb_set DebugMon_Handler,Default_Handler
+
+  .weak PendSV_Handler
+  .thumb_set PendSV_Handler,Default_Handler
+
+  .weak SysTick_Handler
+  .thumb_set SysTick_Handler,Default_Handler
+
+  .weak WWDG_IRQHandler
+  .thumb_set WWDG_IRQHandler,Default_Handler
+
+  .weak PVD_IRQHandler
+  .thumb_set PVD_IRQHandler,Default_Handler
+
+  .weak TAMPER_IRQHandler
+  .thumb_set TAMPER_IRQHandler,Default_Handler
+
+  .weak RTC_IRQHandler
+  .thumb_set RTC_IRQHandler,Default_Handler
+
+  .weak FLASH_IRQHandler
+  .thumb_set FLASH_IRQHandler,Default_Handler
+
+  .weak RCC_IRQHandler
+  .thumb_set RCC_IRQHandler,Default_Handler
+
+  .weak EXTI0_IRQHandler
+  .thumb_set EXTI0_IRQHandler,Default_Handler
+
+  .weak EXTI1_IRQHandler
+  .thumb_set EXTI1_IRQHandler,Default_Handler
+
+  .weak EXTI2_IRQHandler
+  .thumb_set EXTI2_IRQHandler,Default_Handler
+
+  .weak EXTI3_IRQHandler
+  .thumb_set EXTI3_IRQHandler,Default_Handler
+
+  .weak EXTI4_IRQHandler
+  .thumb_set EXTI4_IRQHandler,Default_Handler
+
+  .weak DMA1_Channel1_IRQHandler
+  .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
+
+  .weak DMA1_Channel2_IRQHandler
+  .thumb_set DMA1_Channel2_IRQHandler,Default_Handler
+
+  .weak DMA1_Channel3_IRQHandler
+  .thumb_set DMA1_Channel3_IRQHandler,Default_Handler
+
+  .weak DMA1_Channel4_IRQHandler
+  .thumb_set DMA1_Channel4_IRQHandler,Default_Handler
+
+  .weak DMA1_Channel5_IRQHandler
+  .thumb_set DMA1_Channel5_IRQHandler,Default_Handler
+
+  .weak DMA1_Channel6_IRQHandler
+  .thumb_set DMA1_Channel6_IRQHandler,Default_Handler
+
+  .weak DMA1_Channel7_IRQHandler
+  .thumb_set DMA1_Channel7_IRQHandler,Default_Handler
+
+  .weak ADC1_2_IRQHandler
+  .thumb_set ADC1_2_IRQHandler,Default_Handler
+
+  .weak USB_HP_CAN1_TX_IRQHandler
+  .thumb_set USB_HP_CAN1_TX_IRQHandler,Default_Handler
+
+  .weak USB_LP_CAN1_RX0_IRQHandler
+  .thumb_set USB_LP_CAN1_RX0_IRQHandler,Default_Handler
+
+  .weak CAN1_RX1_IRQHandler
+  .thumb_set CAN1_RX1_IRQHandler,Default_Handler
+
+  .weak CAN1_SCE_IRQHandler
+  .thumb_set CAN1_SCE_IRQHandler,Default_Handler
+
+  .weak EXTI9_5_IRQHandler
+  .thumb_set EXTI9_5_IRQHandler,Default_Handler
+
+  .weak TIM1_BRK_IRQHandler
+  .thumb_set TIM1_BRK_IRQHandler,Default_Handler
+
+  .weak TIM1_UP_IRQHandler
+  .thumb_set TIM1_UP_IRQHandler,Default_Handler
+
+  .weak TIM1_TRG_COM_IRQHandler
+  .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
+
+  .weak TIM1_CC_IRQHandler
+  .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+  .weak TIM2_IRQHandler
+  .thumb_set TIM2_IRQHandler,Default_Handler
+
+  .weak TIM3_IRQHandler
+  .thumb_set TIM3_IRQHandler,Default_Handler
+
+  .weak TIM4_IRQHandler
+  .thumb_set TIM4_IRQHandler,Default_Handler
+
+  .weak I2C1_EV_IRQHandler
+  .thumb_set I2C1_EV_IRQHandler,Default_Handler
+
+  .weak I2C1_ER_IRQHandler
+  .thumb_set I2C1_ER_IRQHandler,Default_Handler
+
+  .weak I2C2_EV_IRQHandler
+  .thumb_set I2C2_EV_IRQHandler,Default_Handler
+
+  .weak I2C2_ER_IRQHandler
+  .thumb_set I2C2_ER_IRQHandler,Default_Handler
+
+  .weak SPI1_IRQHandler
+  .thumb_set SPI1_IRQHandler,Default_Handler
+
+  .weak SPI2_IRQHandler
+  .thumb_set SPI2_IRQHandler,Default_Handler
+
+  .weak USART1_IRQHandler
+  .thumb_set USART1_IRQHandler,Default_Handler
+
+  .weak USART2_IRQHandler
+  .thumb_set USART2_IRQHandler,Default_Handler
+
+  .weak USART3_IRQHandler
+  .thumb_set USART3_IRQHandler,Default_Handler
+
+  .weak EXTI15_10_IRQHandler
+  .thumb_set EXTI15_10_IRQHandler,Default_Handler
+
+  .weak RTC_Alarm_IRQHandler
+  .thumb_set RTC_Alarm_IRQHandler,Default_Handler
+
+  .weak USBWakeUp_IRQHandler
+  .thumb_set USBWakeUp_IRQHandler,Default_Handler
+
+

+ 188 - 0
STM32F103C8TX_FLASH.ld

@@ -0,0 +1,188 @@
+/*
+******************************************************************************
+**
+** @file        : LinkerScript.ld
+**
+** @author      : Auto-generated by STM32CubeIDE
+**
+** @brief       : Linker script for STM32F103C8Tx Device from STM32F1 series
+**                      64KBytes FLASH
+**                      20KBytes RAM
+**
+**                Set heap size, stack size and stack location according
+**                to application requirements.
+**
+**                Set memory bank area and size if external memory is used
+**
+**  Target      : STMicroelectronics STM32
+**
+**  Distribution: The file is distributed as is, without any warranty
+**                of any kind.
+**
+******************************************************************************
+** @attention
+**
+** Copyright (c) 2025 STMicroelectronics.
+** All rights reserved.
+**
+** This software is licensed under terms that can be found in the LICENSE file
+** in the root directory of this software component.
+** If no LICENSE file comes with this software, it is provided AS-IS.
+**
+******************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
+
+_Min_Heap_Size = 0x200; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Memories definition */
+MEMORY
+{
+  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 20K
+  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 64K
+}
+
+/* Sections */
+SECTIONS
+{
+
+  /* The startup code into "FLASH" Rom type memory */
+  .isr_vector :
+  {
+    . = ALIGN(4);
+    KEEP(*(.isr_vector)) /* Startup code */
+    . = ALIGN(4);
+  } >FLASH
+
+  /* The program code and other data into "FLASH" Rom type memory */
+  .text :
+  {
+    . = ALIGN(4);
+    *(.text)           /* .text sections (code) */
+    *(.text*)          /* .text* sections (code) */
+    *(.glue_7)         /* glue arm to thumb code */
+    *(.glue_7t)        /* glue thumb to arm code */
+    *(.eh_frame)
+
+    KEEP (*(.init))
+    KEEP (*(.fini))
+
+    . = ALIGN(4);
+    _etext = .;        /* define a global symbols at end of code */
+  } >FLASH
+
+  /* Constant data into "FLASH" Rom type memory */
+  .rodata :
+  {
+    . = ALIGN(4);
+    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
+    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
+    . = ALIGN(4);
+  } >FLASH
+
+  .ARM.extab (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+  {
+    . = ALIGN(4);
+    *(.ARM.extab* .gnu.linkonce.armextab.*)
+    . = ALIGN(4);
+  } >FLASH
+
+  .ARM (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+  {
+    . = ALIGN(4);
+    __exidx_start = .;
+    *(.ARM.exidx*)
+    __exidx_end = .;
+    . = ALIGN(4);
+  } >FLASH
+
+  .preinit_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+  {
+    . = ALIGN(4);
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array*))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+    . = ALIGN(4);
+  } >FLASH
+
+  .init_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+  {
+    . = ALIGN(4);
+    PROVIDE_HIDDEN (__init_array_start = .);
+    KEEP (*(SORT(.init_array.*)))
+    KEEP (*(.init_array*))
+    PROVIDE_HIDDEN (__init_array_end = .);
+    . = ALIGN(4);
+  } >FLASH
+
+  .fini_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+  {
+    . = ALIGN(4);
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(SORT(.fini_array.*)))
+    KEEP (*(.fini_array*))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+    . = ALIGN(4);
+  } >FLASH
+
+  /* Used by the startup to initialize data */
+  _sidata = LOADADDR(.data);
+
+  /* Initialized data sections into "RAM" Ram type memory */
+  .data :
+  {
+    . = ALIGN(4);
+    _sdata = .;        /* create a global symbol at data start */
+    *(.data)           /* .data sections */
+    *(.data*)          /* .data* sections */
+    *(.RamFunc)        /* .RamFunc sections */
+    *(.RamFunc*)       /* .RamFunc* sections */
+
+    . = ALIGN(4);
+    _edata = .;        /* define a global symbol at data end */
+
+  } >RAM AT> FLASH
+
+  /* Uninitialized data section into "RAM" Ram type memory */
+  . = ALIGN(4);
+  .bss :
+  {
+    /* This is used by the startup in order to initialize the .bss section */
+    _sbss = .;         /* define a global symbol at bss start */
+    __bss_start__ = _sbss;
+    *(.bss)
+    *(.bss*)
+    *(COMMON)
+
+    . = ALIGN(4);
+    _ebss = .;         /* define a global symbol at bss end */
+    __bss_end__ = _ebss;
+  } >RAM
+
+  /* User_heap_stack section, used to check that there is enough "RAM" Ram  type memory left */
+  ._user_heap_stack :
+  {
+    . = ALIGN(8);
+    PROVIDE ( end = . );
+    PROVIDE ( _end = . );
+    . = . + _Min_Heap_Size;
+    . = . + _Min_Stack_Size;
+    . = ALIGN(8);
+  } >RAM
+
+  /* Remove information from the compiler libraries */
+  /DISCARD/ :
+  {
+    libc.a ( * )
+    libm.a ( * )
+    libgcc.a ( * )
+  }
+
+  .ARM.attributes 0 : { *(.ARM.attributes) }
+}