1
0

fin SETR2

This commit is contained in:
Jose
2025-12-19 17:13:32 +01:00
parent b9c332427d
commit ec45536183
740 changed files with 465505 additions and 284 deletions

View File

@@ -0,0 +1,90 @@
/**
******************************************************************************
* File Name : app_touchgfx.c
******************************************************************************
* This file was created by TouchGFX Generator 4.26.0. This file is only
* generated once! Delete this file from your project and re-generate code
* using STM32CubeMX or change this file manually to update it.
******************************************************************************
* @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 "app_touchgfx.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* 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 -----------------------------------------------*/
void touchgfx_init(void);
void touchgfx_components_init(void);
void touchgfx_taskEntry(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/**
* PreOS Initialization function
*/
void MX_TouchGFX_PreOSInit(void)
{
}
/**
* Initialize TouchGFX application
*/
void MX_TouchGFX_Init(void)
{
// Calling forward to touchgfx_init in C++ domain
touchgfx_components_init();
touchgfx_init();
}
/**
* TouchGFX application entry function
*/
void MX_TouchGFX_Process(void)
{
// Calling forward to touchgfx_taskEntry in C++ domain
touchgfx_taskEntry();
}
/**
* TouchGFX application thread
*/
void TouchGFX_Task(void* argument)
{
// Calling forward to touchgfx_taskEntry in C++ domain
touchgfx_taskEntry();
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,60 @@
/**
******************************************************************************
* File Name : app_touchgfx.h
******************************************************************************
* This file was created by TouchGFX Generator 4.26.0. This file is only
* generated once! Delete this file from your project and re-generate code
* using STM32CubeMX or change this file manually to update it.
******************************************************************************
* @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.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef APP_TOUCHGFX_H
#define APP_TOUCHGFX_H
#ifdef __cplusplus
extern "C" {
#endif
/* 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 MX_TouchGFX_PreOSInit(void);
void MX_TouchGFX_Init(void);
void MX_TouchGFX_Process(void);
void TouchGFX_Task(void* argument);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
#ifdef __cplusplus
}
#endif
#endif /* APP_TOUCHGFX_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,33 @@
{
"Application": {
"Name": "STM32F746G_DISCO",
"TouchGfxPath": "../Middlewares/ST/touchgfx",
"AvailableColorDepths": [ 16 ],
"AvailableLCDs":
{
"16": "LCD16bpp"
},
"AvailableResolutions": [
{
"Width": 480,
"Height": 272
}
],
"PostGenerateTargetCommand": "touchgfx update_project",
"Family": "STM32F7",
"SubFamily": "STM32F7x6",
"Platform": "m7",
"Toolchain": "STM32CubeIDE",
"ProjectFile": "../STM32F746G_DISCO.ioc",
"OptionalComponentsRoot": "../Middlewares/ST/touchgfx_components",
"OptionalComponents": [
],
"AdditionalFeatures": [
"CWRVector",
"VectorFonts",
"Video"
]
},
"Version": "4.26.0"
}

View File

@@ -0,0 +1,104 @@
{
"Application": {
"Screens": [
{
"Name": "MainScreen",
"Components": [
{
"Type": "Image",
"Name": "background",
"X": -73,
"Y": -177,
"Width": 626,
"Height": 626,
"RelativeFilename": "fondo.png"
},
{
"Type": "ToggleButton",
"Name": "led_button",
"X": 185,
"Y": 111,
"Width": 170,
"Height": 60,
"Pressed": "__generated\\glass_theme_images_widgets_togglebutton_large_round_text_on_active.png",
"Released": "__generated\\glass_theme_images_widgets_togglebutton_large_round_text_off_normal.png"
}
],
"Interactions": [
{
"InteractionName": "on_click",
"Trigger": {
"Type": "TriggerClicked",
"TriggerComponent": "led_button"
},
"Action": {
"Type": "ActionCustom",
"FunctionName": "led_toggle"
}
}
]
}
],
"CustomContainerDefinitions": [],
"Name": "P7_SETR2_TGFX",
"Resolution": {
"Width": 480,
"Height": 272
},
"SelectedColorDepth": 16,
"StartupScreenName": "MainScreen",
"SelectedStartupLanguage": "GB",
"TouchGfxPath": "../Middlewares/ST/touchgfx",
"UIPath": ".",
"AvailableColorDepths": [
16
],
"AvailableLCDs": {
"16": "LCD16bpp"
},
"AvailableSections": [
"ExtFlashSection",
"IntFlashSection"
],
"AvailableResolutions": [
{
"Width": 480,
"Height": 272
}
],
"PhysicalButtons": [],
"FrameworkFeatures": {
"LCD16bpp": {
"Id": "LCD16bpp",
"IsEnabled": true
}
},
"GenerateAssetsCommand": "make -f simulator/gcc/Makefile assets -j8",
"PostGenerateCommand": "touchgfx update_project --project-file=simulator/msvs/Application.vcxproj",
"PostGenerateTargetCommand": "touchgfx update_project",
"CompileSimulatorCommand": "make -f simulator/gcc/Makefile -j8",
"RunSimulatorCommand": "build\\bin\\simulator.exe",
"CompileTargetCommand": "make -f ../gcc/Makefile -j8",
"FlashTargetCommand": "make -f ../gcc/Makefile flash -j8",
"FlashTargetIntCommandOverride": "make -f ../gcc/Makefile intflash -j8",
"LandscapeSkinX": 0,
"LandscapeSkinY": 0,
"PortraitSkinX": 0,
"PortraitSkinY": 0,
"DisplayOrientation": "Landscape",
"Family": "STM32F7",
"SubFamily": "STM32F7x6",
"Toolchain": "STM32CubeIDE",
"Platform": "m7",
"ProjectFile": "../STM32F746G_DISCO.ioc",
"OptionalComponentsRoot": "../Middlewares/ST/touchgfx_components",
"OptionalComponents": [],
"AdditionalFeatures": [
"CWRVector",
"VectorFonts",
"Video"
]
},
"Version": "4.26.0",
"CreatedBy": "4.26.0"
}

View File

@@ -0,0 +1,24 @@
{
"image_configuration": {
"dither_algorithm": "2",
"alpha_dither": "yes",
"layout_rotation": "0",
"opaque_image_format": "RGB565",
"nonopaque_image_format": "ARGB8888",
"l8_compression": "no",
"rgb_compression": "no",
"section": "ExtFlashSection",
"extra_section": "ExtFlashSection",
"images": {}
},
"text_configuration": {
"remap": "yes",
"a4": "yes",
"binary_translations": "no",
"binary_fonts": "no",
"framebuffer_bpp": "16",
"font_format": "0",
"cache_size": 4096,
"copy_translations_to_ram": "no"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<TextDatabase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="texts.xsd" Version="4.26.0">
<Languages>
<Language Id="GB" />
</Languages>
<Texts>
<TextGroup Id="Group1" />
<TextGroup Id="Unsorted" />
</Texts>
<Typographies>
<Typography Id="Default" Font="verdana.ttf" Size="20" Bpp="4" IsVector="no" Direction="LTR" FallbackCharacter="?" />
<Typography Id="Large" Font="verdana.ttf" Size="40" Bpp="4" IsVector="no" Direction="LTR" FallbackCharacter="?" />
<Typography Id="Small" Font="verdana.ttf" Size="10" Bpp="4" IsVector="no" Direction="LTR" FallbackCharacter="?" />
</Typographies>
</TextDatabase>

View File

@@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!--Types-->
<xs:simpleType name="direction" final="restriction" >
<xs:restriction base="xs:string">
<xs:enumeration value="LTR" />
<xs:enumeration value="RTL" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="alignment" final="restriction" >
<xs:restriction base="xs:string">
<xs:enumeration value="Left" />
<xs:enumeration value="LEFT" />
<xs:enumeration value="left" />
<xs:enumeration value="Center" />
<xs:enumeration value="CENTER" />
<xs:enumeration value="center" />
<xs:enumeration value="Right" />
<xs:enumeration value="RIGHT" />
<xs:enumeration value="right" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="bpp" final="restriction" >
<xs:restriction base="xs:string">
<xs:enumeration value="1" />
<xs:enumeration value="2" />
<xs:enumeration value="4" />
<xs:enumeration value="8" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="fallbackCharacter" final="restriction" >
<xs:restriction base="xs:string">
<xs:pattern value="|.|skip|(0[xX][0-9a-fA-F]{1,4})" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ellipsisCharacter" final="restriction" >
<xs:restriction base="xs:string">
<xs:pattern value="|.|(0[xX][0-9a-fA-F]{1,4})" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="wildcardCharacterRanges" final="restriction" >
<xs:restriction base="xs:string">
<xs:pattern value="|(.-.|(0[xX][0-9a-fA-F]{1,4}|[0-9]{1,5})(-(0[xX][0-9a-fA-F]{1,4}|[0-9]{1,5}))?)(,(.-.|(0[xX][0-9a-fA-F]{1,4}|[0-9]{1,5})(-(0[xX][0-9a-fA-F]{1,4}|[0-9]{1,5}))?))*" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="validCppIdentifier" final="restriction" >
<xs:restriction base="xs:string">
<xs:pattern value="[a-zA-Z_][a-zA-Z0-9_]*" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="validIdentifier" final="restriction" >
<xs:restriction base="xs:string">
<xs:pattern value="[a-zA-Z0-9_]+" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="fontSize" final="restriction">
<xs:restriction base="xs:unsignedInt">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="1000"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="isVector" final="restriction" >
<xs:restriction base="xs:string">
<xs:enumeration value="yes" />
<xs:enumeration value="no" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="isCompressed" final="restriction" >
<xs:restriction base="xs:string">
<xs:enumeration value="yes" />
<xs:enumeration value="no" />
</xs:restriction>
</xs:simpleType>
<!--TextDatabase specification-->
<xs:element name="TextDatabase">
<xs:complexType>
<xs:sequence>
<xs:element name="Languages">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Language">
<xs:complexType>
<xs:attribute name="Id" type="validCppIdentifier" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:sequence>
<xs:element name="Texts">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="TextGroup">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Text">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="unbounded" name="Translation">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="Language" type="validCppIdentifier" use="required" />
<xs:attribute name="Alignment" type="alignment" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="Id" type="validIdentifier" use="required" />
<xs:attribute name="Alignment" type="alignment" use="required" />
<xs:attribute name="TypographyId" type="validCppIdentifier" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="Id" type="validIdentifier" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:element name="Typographies">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Typography">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="LanguageSetting">
<xs:complexType>
<xs:attribute name="Language" type="validCppIdentifier" use="required" />
<xs:attribute name="Font" type="xs:string" use="required" />
<xs:attribute name="Size" type="fontSize" use="required" />
<xs:attribute name="Bpp" type="bpp" use="required" />
<xs:attribute name="IsVector" type="isVector" use="required" />
<xs:attribute name="Direction" type="direction" use="required" />
<xs:attribute name="IsCompressed" type="isCompressed" use="optional" />
<xs:attribute name="FallbackCharacter" type="fallbackCharacter" use="optional" />
<xs:attribute name="WildcardCharacters" type="xs:string" use="optional" />
<xs:attribute name="WidgetWildcardCharacters" type="xs:string" use="optional" />
<xs:attribute name="WildcardCharacterRanges" type="wildcardCharacterRanges" use="optional" />
<xs:attribute name="EllipsisCharacter" type="ellipsisCharacter" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="Id" type="validCppIdentifier" use="required" />
<xs:attribute name="Font" type="xs:string" use="required" />
<xs:attribute name="Size" type="fontSize" use="required" />
<xs:attribute name="Bpp" type="bpp" use="required" />
<xs:attribute name="IsVector" type="isVector" use="required" />
<xs:attribute name="Direction" type="direction" use="required" />
<xs:attribute name="IsCompressed" type="isCompressed" use="optional" />
<xs:attribute name="FallbackCharacter" type="fallbackCharacter" use="optional" />
<xs:attribute name="WildcardCharacters" type="xs:string" use="optional" />
<xs:attribute name="WidgetWildcardCharacters" type="xs:string" use="optional" />
<xs:attribute name="WildcardCharacterRanges" type="wildcardCharacterRanges" use="optional" />
<xs:attribute name="EllipsisCharacter" type="ellipsisCharacter" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="Version" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,24 @@
#ifndef FRONTENDAPPLICATION_HPP
#define FRONTENDAPPLICATION_HPP
#include <gui_generated/common/FrontendApplicationBase.hpp>
class FrontendHeap;
using namespace touchgfx;
class FrontendApplication : public FrontendApplicationBase
{
public:
FrontendApplication(Model& m, FrontendHeap& heap);
virtual ~FrontendApplication() { }
virtual void handleTickEvent()
{
model.tick();
FrontendApplicationBase::handleTickEvent();
}
private:
};
#endif // FRONTENDAPPLICATION_HPP

View File

@@ -0,0 +1,74 @@
#ifndef FRONTENDHEAP_HPP
#define FRONTENDHEAP_HPP
#include <gui_generated/common/FrontendHeapBase.hpp>
class FrontendHeap : public FrontendHeapBase
{
public:
/* List any user-defined view types here*/
typedef touchgfx::meta::TypeList< touchgfx::meta::Nil, //Replace this with first user-defined type
touchgfx::meta::Nil //List must always end with meta::Nil !
> UserDefinedViewTypes;
/* List any user-defined presenter types here*/
typedef touchgfx::meta::TypeList< touchgfx::meta::Nil, //Replace this with first user-defined type
touchgfx::meta::Nil //List must always end with meta::Nil !
> UserDefinedPresenterTypes;
/* List any user-defined transition types here*/
typedef touchgfx::meta::TypeList< touchgfx::meta::Nil, //Replace this with first user-defined type
touchgfx::meta::Nil //List must always end with meta::Nil !
> UserDefinedTransitionTypes;
/* Calculate largest view, both from generated and user-defined typelists */
typedef touchgfx::meta::select_type_maxsize< UserDefinedViewTypes >::type MaxUserViewType;
typedef touchgfx::meta::TypeList< MaxGeneratedViewType,
touchgfx::meta::TypeList< MaxUserViewType,
touchgfx::meta::Nil
> > CombinedViewTypes;
typedef touchgfx::meta::select_type_maxsize< CombinedViewTypes >::type MaxViewType;
/* Calculate largest presenter, both from generated and user-defined typelists */
typedef touchgfx::meta::select_type_maxsize< UserDefinedPresenterTypes >::type MaxUserPresenterType;
typedef touchgfx::meta::TypeList< MaxGeneratedPresenterType,
touchgfx::meta::TypeList< MaxUserPresenterType,
touchgfx::meta::Nil
> > CombinedPresenterTypes;
typedef touchgfx::meta::select_type_maxsize< CombinedPresenterTypes >::type MaxPresenterType;
/* Calculate largest transition, both from generated and user-defined typelists */
typedef touchgfx::meta::select_type_maxsize< UserDefinedTransitionTypes >::type MaxUserTransitionType;
typedef touchgfx::meta::TypeList< MaxGeneratedTransitionType,
touchgfx::meta::TypeList< MaxUserTransitionType,
touchgfx::meta::Nil
> > CombinedTransitionTypes;
typedef touchgfx::meta::select_type_maxsize< CombinedTransitionTypes >::type MaxTransitionType;
static FrontendHeap& getInstance()
{
static FrontendHeap instance;
return instance;
}
touchgfx::Partition< CombinedPresenterTypes, 1 > presenters;
touchgfx::Partition< CombinedViewTypes, 1 > views;
touchgfx::Partition< CombinedTransitionTypes, 1 > transitions;
Model model;
FrontendApplication app;
private:
FrontendHeap() : FrontendHeapBase(presenters, views, transitions, app),
app(model, *this)
{
gotoStartScreen(app);
}
};
#endif // FRONTENDHEAP_HPP

View File

@@ -0,0 +1,36 @@
#ifndef MAINSCREENPRESENTER_HPP
#define MAINSCREENPRESENTER_HPP
#include <gui/model/ModelListener.hpp>
#include <mvp/Presenter.hpp>
using namespace touchgfx;
class MainScreenView;
class MainScreenPresenter : public touchgfx::Presenter, public ModelListener
{
public:
MainScreenPresenter(MainScreenView& v);
/**
* The activate function is called automatically when this screen is "switched in"
* (ie. made active). Initialization logic can be placed here.
*/
virtual void activate();
/**
* The deactivate function is called automatically when this screen is "switched out"
* (ie. made inactive). Teardown functionality can be placed here.
*/
virtual void deactivate();
virtual ~MainScreenPresenter() {}
private:
MainScreenPresenter();
MainScreenView& view;
};
#endif // MAINSCREENPRESENTER_HPP

View File

@@ -0,0 +1,18 @@
#ifndef MAINSCREENVIEW_HPP
#define MAINSCREENVIEW_HPP
#include <gui_generated/mainscreen_screen/MainScreenViewBase.hpp>
#include <gui/mainscreen_screen/MainScreenPresenter.hpp>
class MainScreenView : public MainScreenViewBase
{
public:
MainScreenView();
virtual ~MainScreenView() {}
virtual void setupScreen();
virtual void tearDownScreen();
virtual void led_toggle();
protected:
};
#endif // MAINSCREENVIEW_HPP

View File

@@ -0,0 +1,21 @@
#ifndef MODEL_HPP
#define MODEL_HPP
class ModelListener;
class Model
{
public:
Model();
void bind(ModelListener* listener)
{
modelListener = listener;
}
void tick();
protected:
ModelListener* modelListener;
};
#endif // MODEL_HPP

View File

@@ -0,0 +1,21 @@
#ifndef MODELLISTENER_HPP
#define MODELLISTENER_HPP
#include <gui/model/Model.hpp>
class ModelListener
{
public:
ModelListener() : model(0) {}
virtual ~ModelListener() {}
void bind(Model* m)
{
model = m;
}
protected:
Model* model;
};
#endif // MODELLISTENER_HPP

View File

@@ -0,0 +1,7 @@
#include <gui/common/FrontendApplication.hpp>
FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap)
: FrontendApplicationBase(m, heap)
{
}

View File

@@ -0,0 +1,18 @@
#include <gui/mainscreen_screen/MainScreenView.hpp>
#include <gui/mainscreen_screen/MainScreenPresenter.hpp>
MainScreenPresenter::MainScreenPresenter(MainScreenView& v)
: view(v)
{
}
void MainScreenPresenter::activate()
{
}
void MainScreenPresenter::deactivate()
{
}

View File

@@ -0,0 +1,29 @@
#include <gui/mainscreen_screen/MainScreenView.hpp>
#include "stm32f7xx_hal.h"
MainScreenView::MainScreenView()
{
}
void MainScreenView::setupScreen()
{
MainScreenViewBase::setupScreen();
}
void MainScreenView::tearDownScreen()
{
MainScreenViewBase::tearDownScreen();
}
void MainScreenView::led_toggle()
{
if(led_button.getState())
{
HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET);
}
}

View File

@@ -0,0 +1,12 @@
#include <gui/model/Model.hpp>
#include <gui/model/ModelListener.hpp>
Model::Model() : modelListener(0)
{
}
void Model::tick()
{
}

View File

@@ -0,0 +1,48 @@
#include <CortexMMCUInstrumentation.hpp>
#include <touchgfx/hal/HAL.hpp>
namespace touchgfx
{
void CortexMMCUInstrumentation::init()
{
// See: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/CEGHJDCF.html
//
// [24] Read/write TRCENA This bit must be set to 1 to enable use of the trace and debug blocks:
// Data Watchpoint and Trace (DWT)
// Instrumentation Trace Macrocell (ITM)
// Embedded Trace Macrocell (ETM)
// Trace Port Interface Unit (TPIU).
// This enables control of power usage unless tracing is required. The application can enable this, for ITM use, or use by a debugger.
// Enable Debug Exception and Monitor Control Register
*((volatile unsigned int*)0xE000EDFC) |= 0x01000000;
// Enable Lock Access Register
*((volatile unsigned int*)0xE0001FB0) |= 0xC5ACCE55;
// Enable Data Watchpoint and Trace Control Register
*((volatile unsigned int*)0xE0001000) |= 1;
}
//Board specific clockfrequency
unsigned int CortexMMCUInstrumentation::getElapsedUS(unsigned int start, unsigned int now, unsigned int clockfrequency)
{
return ((now - start) + (clockfrequency / 2)) / clockfrequency;
}
unsigned int CortexMMCUInstrumentation::getCPUCycles()
{
return *((volatile unsigned int*)0xE0001004);
}
void CortexMMCUInstrumentation::setMCUActive(bool active)
{
if (active) //idle task sched out
{
uint32_t cc_temp = getCPUCycles() - cc_in;
cc_consumed += cc_temp;
}
else //idle task sched in
{
cc_in = getCPUCycles();
}
}
}

View File

@@ -0,0 +1,74 @@
#ifndef CORTEXMMCUINSTRUMENTATION_HPP
#define CORTEXMMCUINSTRUMENTATION_HPP
#include <platform/core/MCUInstrumentation.hpp>
#include <stdint.h>
namespace touchgfx
{
/**
* @class CortexMMCUInstrumentation CortexMMCUInstrumentation.hpp platform/core/arm/cortex-m/CortexMMCUInstrumentation.hpp
*
* @brief Interface for instrumenting Cortex-M processors to measure MCU load via measured CPU
* cycles.
*
* Interface for instrumenting Cortex-M processors to measure MCU load via measured CPU
* cycles.
*
* @sa MCUInstrumentation
*/
class CortexMMCUInstrumentation : public MCUInstrumentation
{
public:
/**
* @fn virtual void CortexMMCUInstrumentation::init();
*
* @brief Initialization.
*
* Initialization.
*/
virtual void init();
/**
* @fn virtual unsigned int CortexMMCUInstrumentation::getElapsedUS(unsigned int start, unsigned int now, unsigned int clockfrequency);
*
* @brief Gets elapsed microseconds basedon clockfrequency.
*
* Gets elapsed microseconds basedon clockfrequency.
*
* @param start Start time.
* @param now Current time.
* @param clockfrequency Clock frequency of the system.
*
* @return Elapsed microseconds start and now.
*/
virtual unsigned int getElapsedUS(unsigned int start, unsigned int now, unsigned int clockfrequency);
/**
* @fn virtual unsigned int CortexMMCUInstrumentation::getCPUCycles();
*
* @brief Gets CPU cycles from register.
*
* Gets CPU cycles from register.
*
* @return CPU cycles.
*/
virtual unsigned int getCPUCycles();
/**
* @fn virtual void CortexMMCUInstrumentation::setMCUActive(bool active);
*
* @brief Register if MCU is active by measuring cpu cycles.
*
* Register if MCU is active by measuring cpu cycles. If user wishes to track
* MCU load, this method should be called whenever the OS Idle task is scheduled
* in or out. This method makes calls to a concrete implementation of GPIO
* functionality and a concrete implementation of cpu cycles.
*
* @param active If true, MCU is registered as being active, inactive otherwise.
*/
virtual void setMCUActive(bool active);
};
} // namespace touchgfx
#endif // CORTEXMMCUINSTRUMENTATION_HPP

View File

@@ -0,0 +1,182 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : STM32TouchController.cpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.19.1.
******************************************************************************
* @attention
*
* Copyright (c) 2022 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 */
/* USER CODE BEGIN STM32TouchController */
#include <STM32TouchController.hpp>
#include <TouchGFXHAL.hpp>
#include <ft5336.h>
#include <stm32f7xx_hal.h>
#include <touchgfx/hal/OSWrappers.hpp>
static TS_DrvTypeDef* tsDriver;
extern I2C_HandleTypeDef hi2c3;
void STM32TouchController::init()
{
/* Initialize the TS driver structure */
tsDriver = &ft5336_ts_drv;
/* Initialize the TS driver */
tsDriver->Start(TS_I2C_ADDRESS);
}
bool STM32TouchController::sampleTouch(int32_t& x, int32_t& y)
{
/**
* By default sampleTouch returns false,
* return true if a touch has been detected, otherwise false.
*
* Coordinates are passed to the caller by reference by x and y.
*
* This function is called by the TouchGFX framework.
* By default sampleTouch is called every tick, this can be adjusted by HAL::setTouchSampleRate(int8_t);
*
*/
if (tsDriver)
{
if (tsDriver->DetectTouch(TS_I2C_ADDRESS))
{
/* Get each touch coordinates */
uint16_t _x, _y;
tsDriver->GetXY(TS_I2C_ADDRESS, &_y, &_x);
x = (int32_t)_x;
y = (int32_t)_y;
return true;
}
}
return false;
}
/**
* @brief Manages error callback by re-initializing I2C.
* @param i2c_handler : I2C handler
* @param Addr: I2C Address
* @retval None
*/
static void I2Cx_Error(I2C_HandleTypeDef* i2c_handler, uint8_t Addr)
{
/* De-initialize the I2C communication bus */
HAL_I2C_DeInit(i2c_handler);
/* Re-Initialize the I2C communication bus */
//I2Cx_Init(i2c_handler);
}
/**
* @brief Reads multiple data.
* @param i2c_handler : I2C handler
* @param Addr: I2C address
* @param Reg: Reg address
* @param MemAddress: Memory address
* @param Buffer: Pointer to data buffer
* @param Length: Length of the data
* @retval Number of read data
*/
static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef* i2c_handler,
uint8_t Addr,
uint16_t Reg,
uint16_t MemAddress,
uint8_t* Buffer,
uint16_t Length)
{
HAL_StatusTypeDef status = HAL_OK;
status = HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000);
/* Check the communication status */
if (status != HAL_OK)
{
/* I2C error occurred */
I2Cx_Error(i2c_handler, Addr);
}
return status;
}
/**
* @brief Writes a value in a register of the device through BUS in using DMA mode.
* @param i2c_handler : I2C handler
* @param Addr: Device address on BUS Bus.
* @param Reg: The target register address to write
* @param MemAddress: Memory address
* @param Buffer: The target register value to be written
* @param Length: buffer size to be written
* @retval HAL status
*/
static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef* i2c_handler,
uint8_t Addr,
uint16_t Reg,
uint16_t MemAddress,
uint8_t* Buffer,
uint16_t Length)
{
HAL_StatusTypeDef status = HAL_OK;
status = HAL_I2C_Mem_Write(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000);
/* Check the communication status */
if (status != HAL_OK)
{
/* Re-Initiaize the I2C Bus */
I2Cx_Error(i2c_handler, Addr);
}
return status;
}
/**
* @brief Writes a single data.
* @param Addr: I2C address
* @param Reg: Reg address
* @param Value: Data to be written
* @retval None
*/
void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value)
{
I2Cx_WriteMultiple(&hi2c3, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&Value, 1);
}
/**
* @brief Reads a single data.
* @param Addr: I2C address
* @param Reg: Reg address
* @retval Data to be read
*/
uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg)
{
uint8_t read_value = 0;
I2Cx_ReadMultiple(&hi2c3, Addr, Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&read_value, 1);
return read_value;
}
/**
* @brief TS delay
* @param Delay: Delay in ms
* @retval None
*/
void TS_IO_Delay(uint32_t Delay)
{
HAL_Delay(Delay);
}
/* USER CODE END STM32TouchController */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,73 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : STM32TouchController.hpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.19.1.
******************************************************************************
* @attention
*
* Copyright (c) 2022 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 */
/* USER CODE BEGIN STM32TouchController */
#ifndef STM32TOUCHCONTROLLER_HPP
#define STM32TOUCHCONTROLLER_HPP
#include <platform/driver/touch/TouchController.hpp>
/**
* @class STM32TouchController
*
* @brief This class specializes TouchController Interface.
*
* @sa touchgfx::TouchController
*/
class STM32TouchController : public touchgfx::TouchController
{
public:
STM32TouchController() {}
/**
* @fn virtual void STM32TouchController::init() = 0;
*
* @brief Initializes touch controller.
*
* Initializes touch controller.
*/
virtual void init();
/**
* @fn virtual bool STM32TouchController::sampleTouch(int32_t& x, int32_t& y) = 0;
*
* @brief Checks whether the touch screen is being touched, and if so, what coordinates.
*
* Checks whether the touch screen is being touched, and if so, what coordinates.
*
* @param [out] x The x position of the touch
* @param [out] y The y position of the touch
*
* @return True if a touch has been detected, otherwise false.
*/
virtual bool sampleTouch(int32_t& x, int32_t& y);
private:
static const uint16_t TS_I2C_ADDRESS = ((uint16_t)0x70);
};
#endif // STM32TOUCHCONTROLLER_HPP
/* USER CODE END STM32TouchController */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,196 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : TouchGFXGPIO.cpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.19.1.
******************************************************************************
* @attention
*
* Copyright (c) 2022 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 */
#include <touchgfx/hal/GPIO.hpp>
/**
* GPIO_ID Enum
* The signals represented by this enum are used by TouchGFX framework to signal internal events.
*
* VSYNC_FREQ, /// Pin is toggled at each VSYNC
* RENDER_TIME, /// Pin is high when frame rendering begins, low when finished
* FRAME_RATE, /// Pin is toggled when the frame buffers are swapped.
* MCU_ACTIVE /// Pin is high when framework is utilizing the MCU.
*
* Configure GPIO's with the same name as the GPIO_IDs above, as output, in CubeMX to export
* the signals for performance measuring. See support.touchgfx.com for further details.
*
*/
/* USER CODE BEGIN TouchGFXGPIO.cpp */
#include "stm32f7xx.h"
#include "main.h"
/* USER CODE BEGIN user includes */
// VSYNC_FREQ - Pin PB4(D3).
// RENDER_TIME - Pin PC6(D1)
// FRAME_RATE - Pin PC7(D0)
// MCU_ACTIVE - Pin PG6(D2)
/* USER CODE END user includes */
using namespace touchgfx;
static int GPIO_InvertedLevels[4];
#define M_GPIO_PIN_SET(id) (GPIO_InvertedLevels[id] ? GPIO_PIN_RESET : GPIO_PIN_SET)
#define M_GPIO_PIN_RESET(id) (GPIO_InvertedLevels[id] ? GPIO_PIN_SET : GPIO_PIN_RESET)
/*
* Perform configuration of IO pins.
*/
void GPIO::init()
{
for (int id = 0; id <= 4; id++)
{
if (GPIO::get(static_cast<GPIO_ID>(id)))
{
if (GPIO_InvertedLevels[id] != 1)
{
GPIO_InvertedLevels[id] = 1;
}
}
}
}
/*
* Sets a pin high.
*/
void GPIO::set(GPIO_ID id)
{
switch (id)
{
case GPIO::VSYNC_FREQ:
#if defined(VSYNC_FREQ_GPIO_Port) && defined(VSYNC_FREQ_Pin)
HAL_GPIO_WritePin(VSYNC_FREQ_GPIO_Port, VSYNC_FREQ_Pin, M_GPIO_PIN_SET(id));
#endif
break;
case GPIO::RENDER_TIME:
#if defined(RENDER_TIME_GPIO_Port) && defined(RENDER_TIME_Pin)
HAL_GPIO_WritePin(RENDER_TIME_GPIO_Port, RENDER_TIME_Pin, M_GPIO_PIN_SET(id));
#endif
break;
case GPIO::FRAME_RATE:
#if defined(FRAME_RATE_GPIO_Port) && defined(FRAME_RATE_Pin)
HAL_GPIO_WritePin(FRAME_RATE_GPIO_Port, FRAME_RATE_Pin, M_GPIO_PIN_SET(id));
#endif
break;
case GPIO::MCU_ACTIVE:
#if defined(MCU_ACTIVE_GPIO_Port) && defined(MCU_ACTIVE_Pin)
HAL_GPIO_WritePin(MCU_ACTIVE_GPIO_Port, MCU_ACTIVE_Pin, M_GPIO_PIN_SET(id));
#endif
break;
}
}
/*
* Sets a pin low.
*/
void GPIO::clear(GPIO_ID id)
{
switch (id)
{
case GPIO::VSYNC_FREQ:
#if defined(VSYNC_FREQ_GPIO_Port) && defined(VSYNC_FREQ_Pin)
HAL_GPIO_WritePin(VSYNC_FREQ_GPIO_Port, VSYNC_FREQ_Pin, M_GPIO_PIN_RESET(id));
#endif
break;
case GPIO::RENDER_TIME:
#if defined(RENDER_TIME_GPIO_Port) && defined(RENDER_TIME_Pin)
HAL_GPIO_WritePin(RENDER_TIME_GPIO_Port, RENDER_TIME_Pin, M_GPIO_PIN_RESET(id));
#endif
break;
case GPIO::FRAME_RATE:
#if defined(FRAME_RATE_GPIO_Port) && defined(FRAME_RATE_Pin)
HAL_GPIO_WritePin(FRAME_RATE_GPIO_Port, FRAME_RATE_Pin, M_GPIO_PIN_RESET(id));
#endif
break;
case GPIO::MCU_ACTIVE:
#if defined(MCU_ACTIVE_GPIO_Port) && defined(MCU_ACTIVE_Pin)
HAL_GPIO_WritePin(MCU_ACTIVE_GPIO_Port, MCU_ACTIVE_Pin, M_GPIO_PIN_RESET(id));
#endif
break;
}
}
/*
* Toggles a pin.
*/
void GPIO::toggle(GPIO_ID id)
{
switch (id)
{
case GPIO::VSYNC_FREQ:
#if defined(VSYNC_FREQ_GPIO_Port) && defined(VSYNC_FREQ_Pin)
HAL_GPIO_TogglePin(VSYNC_FREQ_GPIO_Port, VSYNC_FREQ_Pin);
#endif
break;
case GPIO::RENDER_TIME:
#if defined(RENDER_TIME_GPIO_Port) && defined(RENDER_TIME_Pin)
HAL_GPIO_TogglePin(RENDER_TIME_GPIO_Port, RENDER_TIME_Pin);
#endif
break;
case GPIO::FRAME_RATE:
#if defined(FRAME_RATE_GPIO_Port) && defined(FRAME_RATE_Pin)
HAL_GPIO_TogglePin(FRAME_RATE_GPIO_Port, FRAME_RATE_Pin);
#endif
break;
case GPIO::MCU_ACTIVE:
#if defined(MCU_ACTIVE_GPIO_Port) && defined(MCU_ACTIVE_Pin)
HAL_GPIO_TogglePin(MCU_ACTIVE_GPIO_Port, MCU_ACTIVE_Pin);
#endif
break;
}
}
/*
* Gets the state of a pin.
*/
bool GPIO::get(GPIO_ID id)
{
GPIO_PinState bitstatus = GPIO_PIN_RESET;
switch (id)
{
case GPIO::VSYNC_FREQ:
#if defined(VSYNC_FREQ_GPIO_Port) && defined(VSYNC_FREQ_Pin)
bitstatus = HAL_GPIO_ReadPin(VSYNC_FREQ_GPIO_Port, VSYNC_FREQ_Pin);
#endif
break;
case GPIO::RENDER_TIME:
#if defined(RENDER_TIME_GPIO_Port) && defined(RENDER_TIME_Pin)
bitstatus = HAL_GPIO_ReadPin(RENDER_TIME_GPIO_Port, RENDER_TIME_Pin);
#endif
break;
case GPIO::FRAME_RATE:
#if defined(FRAME_RATE_GPIO_Port) && defined(FRAME_RATE_Pin)
bitstatus = HAL_GPIO_ReadPin(FRAME_RATE_GPIO_Port, FRAME_RATE_Pin);
#endif
break;
case GPIO::MCU_ACTIVE:
#if defined(MCU_ACTIVE_GPIO_Port) && defined(MCU_ACTIVE_Pin)
bitstatus = HAL_GPIO_ReadPin(MCU_ACTIVE_GPIO_Port, MCU_ACTIVE_Pin);
#endif
break;
}
return (bitstatus == GPIO_PIN_SET);
}
/* USER CODE END TouchGFXGPIO.cpp */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,188 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : TouchGFXHAL.cpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.19.1.
******************************************************************************
* @attention
*
* Copyright (c) 2022 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 */
#include <TouchGFXHAL.hpp>
/* USER CODE BEGIN TouchGFXHAL.cpp */
#include "stm32f7xx.h"
#include <touchgfx/hal/OSWrappers.hpp>
#include <CortexMMCUInstrumentation.hpp>
#include "FreeRTOS.h"
#include "task.h"
using namespace touchgfx;
CortexMMCUInstrumentation instrumentation;
namespace
{
LOCATION_PRAGMA_NOLOAD("TouchGFX_Framebuffer")
uint32_t animationBuffer[(480 * 272 * 2 + 3) / 4] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Framebuffer");
}
void TouchGFXHAL::initialize()
{
// Calling parent implementation of initialize().
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
// Please note, HAL::initialize() must be called to initialize the framework.
TouchGFXGeneratedHAL::initialize();
setAnimationStorage((void*)animationBuffer); //enable the animation storage to allow slide animations
lockDMAToFrontPorch(false);
instrumentation.init();
setMCUInstrumentation(&instrumentation);
enableMCULoadCalculation(true);
}
/**
* Gets the frame buffer address used by the TFT controller.
*
* @return The address of the frame buffer currently being displayed on the TFT.
*/
uint16_t* TouchGFXHAL::getTFTFrameBuffer() const
{
// Calling parent implementation of getTFTFrameBuffer().
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
return TouchGFXGeneratedHAL::getTFTFrameBuffer();
}
/**
* Sets the frame buffer address used by the TFT controller.
*
* @param [in] address New frame buffer address.
*/
void TouchGFXHAL::setTFTFrameBuffer(uint16_t* address)
{
// Calling parent implementation of setTFTFrameBuffer(uint16_t* address).
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
TouchGFXGeneratedHAL::setTFTFrameBuffer(address);
}
/**
* This function is called whenever the framework has performed a partial draw.
*
* @param rect The area of the screen that has been drawn, expressed in absolute coordinates.
*
* @see flushFrameBuffer().
*/
void TouchGFXHAL::flushFrameBuffer(const touchgfx::Rect& rect)
{
// Calling parent implementation of flushFrameBuffer(const touchgfx::Rect& rect).
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
// Please note, HAL::flushFrameBuffer(const touchgfx::Rect& rect) must
// be called to notify the touchgfx framework that flush has been performed.
TouchGFXGeneratedHAL::flushFrameBuffer(rect);
// If the framebuffer is placed in Write Through cached memory (e.g. SRAM) then we need
// to flush the Dcache to make sure framebuffer is correct in RAM. That's done
// using SCB_CleanInvalidateDCache().
SCB_CleanInvalidateDCache();
}
bool TouchGFXHAL::blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes)
{
return TouchGFXGeneratedHAL::blockCopy(dest, src, numBytes);
}
/**
* Configures the interrupts relevant for TouchGFX. This primarily entails setting
* the interrupt priorities for the DMA and LCD interrupts.
*/
void TouchGFXHAL::configureInterrupts()
{
// Calling parent implementation of configureInterrupts().
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
TouchGFXGeneratedHAL::configureInterrupts();
}
/**
* Used for enabling interrupts set in configureInterrupts()
*/
void TouchGFXHAL::enableInterrupts()
{
// Calling parent implementation of enableInterrupts().
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
TouchGFXGeneratedHAL::enableInterrupts();
}
/**
* Used for disabling interrupts set in configureInterrupts()
*/
void TouchGFXHAL::disableInterrupts()
{
// Calling parent implementation of disableInterrupts().
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
TouchGFXGeneratedHAL::disableInterrupts();
}
/**
* Configure the LCD controller to fire interrupts at VSYNC. Called automatically
* once TouchGFX initialization has completed.
*/
void TouchGFXHAL::enableLCDControllerInterrupt()
{
// Calling parent implementation of enableLCDControllerInterrupt().
//
// To overwrite the generated implementation, omit call to parent function
// and implemented needed functionality here.
TouchGFXGeneratedHAL::enableLCDControllerInterrupt();
}
extern "C"
{
portBASE_TYPE IdleTaskHook(void* p)
{
if ((int)p) //idle task sched out
{
touchgfx::HAL::getInstance()->setMCUActive(true);
}
else //idle task sched in
{
touchgfx::HAL::getInstance()->setMCUActive(false);
}
return pdTRUE;
}
}
/* USER CODE END TouchGFXHAL.cpp */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,165 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : TouchGFXHAL.hpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.19.1.
******************************************************************************
* @attention
*
* Copyright (c) 2022 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 */
#ifndef TouchGFXHAL_HPP
#define TouchGFXHAL_HPP
/* USER CODE BEGIN TouchGFXHAL.hpp */
#include <TouchGFXGeneratedHAL.hpp>
/**
* @class TouchGFXHAL
*
* @brief HAL implementation for TouchGFX.
*
* @sa HAL
*/
class TouchGFXHAL : public TouchGFXGeneratedHAL
{
public:
/**
* @fn TouchGFXHAL::TouchGFXHAL(touchgfx::DMA_Interface& dma, touchgfx::LCD& display, touchgfx::TouchController& tc, uint16_t width, uint16_t height) : TouchGFXGeneratedHAL(dma, display, tc, width, height)
*
* @brief Constructor.
*
* Constructor. Initializes members.
*
* @param [in,out] dma Reference to DMA interface.
* @param [in,out] display Reference to LCD interface.
* @param [in,out] tc Reference to Touch Controller driver.
* @param width Width of the display.
* @param height Height of the display.
*/
TouchGFXHAL(touchgfx::DMA_Interface& dma, touchgfx::LCD& display, touchgfx::TouchController& tc, uint16_t width, uint16_t height) : TouchGFXGeneratedHAL(dma, display, tc, width, height)
{
}
virtual void initialize();
/**
* @fn virtual void TouchGFXHAL::disableInterrupts();
*
* @brief Disables the DMA and LCD interrupts.
*
* Disables the DMA and LCD interrupts.
*/
virtual void disableInterrupts();
/**
* @fn virtual void TouchGFXHAL::enableInterrupts();
*
* @brief Enables the DMA and LCD interrupts.
*
* Enables the DMA and LCD interrupts.
*/
virtual void enableInterrupts();
/**
* @fn virtual void TouchGFXHAL::configureInterrupts();
*
* @brief Sets the DMA and LCD interrupt priorities.
*
* Sets the DMA and LCD interrupt priorities.
*/
virtual void configureInterrupts();
/**
* @fn virtual void TouchGFXHAL::enableLCDControllerInterrupt();
*
* @brief Configure the LCD controller to fire interrupts at VSYNC.
*
* Configure the LCD controller to fire interrupts at VSYNC. Called automatically
* once TouchGFX initialization has completed.
*/
virtual void enableLCDControllerInterrupt();
/**
* @fn virtual void TouchGFXHAL::flushFrameBuffer();
*
* @brief This function is called whenever the framework has performed a complete draw.
*
* This specialization is only in place to keep compilers happy. Base impl. will call the
* Rect version.
* @see HAL::flushFrameBuffer
*/
virtual void flushFrameBuffer()
{
TouchGFXGeneratedHAL::flushFrameBuffer();
}
/**
* @fn virtual void TouchGFXHAL::flushFrameBuffer(const Rect& rect);
*
* @brief This function is called whenever the framework has performed a partial draw.
*
* This function is called whenever the framework has performed a partial draw.
* On the STM32F7, make sure to clean and invalidate the data cache. This is to
* ensure that LTDC sees correct data when transferring to the display.
*
* @param rect The area of the screen that has been drawn, expressed in absolute coordinates.
*
* @see flushFrameBuffer().
*/
virtual void flushFrameBuffer(const touchgfx::Rect& rect);
/**
* @fn virtual bool TouchGFXHAL::blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes);
*
* @brief This function performs a platform-specific memcpy.
*
* This function performs a platform-specific memcpy, if supported by the hardware.
*
* @param [out] dest Pointer to destination memory.
* @param [in] src Pointer to source memory.
* @param numBytes Number of bytes to copy.
*
* @return true if the copy succeeded, false if copy was not performed.
*/
virtual bool blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes);
protected:
/**
* @fn virtual uint16_t* TouchGFXHAL::getTFTFrameBuffer() const;
*
* @brief Gets the frame buffer address used by the TFT controller.
*
* Gets the frame buffer address used by the TFT controller.
*
* @return The address of the frame buffer currently being displayed on the TFT.
*/
virtual uint16_t* getTFTFrameBuffer() const;
/**
* @fn virtual void TouchGFXHAL::setTFTFrameBuffer(uint16_t* adr);
*
* @brief Sets the frame buffer address used by the TFT controller.
*
* Sets the frame buffer address used by the TFT controller.
*
* @param [in,out] adr New frame buffer address.
*/
virtual void setTFTFrameBuffer(uint16_t* adr);
};
/* USER CODE END TouchGFXHAL.hpp */
#endif // TouchGFXHAL_HPP
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,539 @@
/**
******************************************************************************
* File Name : DoubleBufferedVideoController.hpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.26.0. Please, do not edit!
******************************************************************************
* @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.
*
******************************************************************************
*/
#ifndef BUFFERPOOLVIDEOCONTROLLER_HPP
#define BUFFERPOOLVIDEOCONTROLLER_HPP
#include <touchgfx/widgets/VideoWidget.hpp>
#include <MJPEGDecoder.hpp>
#include <touchgfx/Utils.hpp>
#include <string.h>
#include "cmsis_os.h"
#if defined(osCMSIS) && (osCMSIS < 0x20000)
#define MUTEX_CREATE() osMutexCreate(0)
#define MUTEX_LOCK(m) osMutexWait(m, osWaitForever)
#define MUTEX_TYPE osMutexId
#define MUTEX_UNLOCK(m) osMutexRelease(m)
#define SEM_CREATE() osSemaphoreCreate(0, 1)
#define SEM_POST(s) osSemaphoreRelease(s)
#define SEM_TYPE osSemaphoreId
#define SEM_WAIT(s) osSemaphoreWait(s, osWaitForever)
#else
#define MUTEX_CREATE() osMutexNew(0)
#define MUTEX_LOCK(m) osMutexAcquire(m, osWaitForever)
#define MUTEX_TYPE osMutexId_t
#define MUTEX_UNLOCK(m) osMutexRelease(m)
#define SEM_CREATE() osSemaphoreNew(1, 0, 0)
#define SEM_POST(s) osSemaphoreRelease(s)
#define SEM_TYPE osSemaphoreId_t
#define SEM_WAIT(s) osSemaphoreAcquire(s, osWaitForever)
#endif
template <uint32_t no_streams, uint32_t width, uint32_t height, uint32_t stride, touchgfx::Bitmap::BitmapFormat output_format>
class DoubleBufferedVideoController : public touchgfx::VideoController
{
public:
DoubleBufferedVideoController()
: VideoController(),
bufferRGB(0), sizeBufferRGB(0), topBufferRGB(0), allowSkipFrames(true),
semDecode(0), mutexBuffers(0)
{
assert((no_streams > 0) && "Video: Number of streams zero!");
// Clear decoder array
memset(mjpegDecoders, 0, sizeof(mjpegDecoders));
// Initialize synchronization primitives
semDecode = SEM_CREATE(); // Binary semaphore
mutexBuffers = MUTEX_CREATE();
}
virtual Handle registerVideoWidget(touchgfx::VideoWidget& widget)
{
// Running in UI thread
// Find stream handle for Widget
Handle handle = getFreeHandle();
streams[handle].isActive = true;
// Set Widget buffer format and address
widget.setVideoBufferFormat(output_format, width, height);
widget.setVideoBuffer((uint8_t*)0);
streams[handle].frameNumberShown = 0;
// Todo, make buffer size depending on widget
const uint32_t sizeOfOneDecodeBuffer = height * stride;
// Allocate two buffers for this stream, if possible
if (topBufferRGB + 2 * sizeOfOneDecodeBuffer > (bufferRGB + sizeBufferRGB))
{
assert(0 && "registerVideoWidget: Unable to allocate two RGB buffers!");
return 0xFFFFFFFF;
}
streams[handle].bufferA = (uint8_t*)topBufferRGB;
topBufferRGB += sizeOfOneDecodeBuffer;
streams[handle].bufferB = (uint8_t*)topBufferRGB;
topBufferRGB += sizeOfOneDecodeBuffer;
return handle;
}
virtual void unregisterVideoWidget(const Handle handle)
{
// Running in UI thread
// Reset active for this handle
streams[handle].isActive = false;
// If all handles are free, reset top pointer
bool oneIsActive = false;
for (uint32_t i = 0; i < no_streams; i++)
{
oneIsActive |= streams[i].isActive;
}
if (oneIsActive == false)
{
// Reset memory usage
topBufferRGB = bufferRGB;
}
}
virtual uint32_t getCurrentFrameNumber(const Handle handle)
{
assert(handle < no_streams);
const Stream& stream = streams[handle];
return stream.frameNumberShown;
}
virtual void setFrameRate(const Handle handle, uint32_t ui_frames, uint32_t video_frames)
{
// Running in UI thread
assert(handle < no_streams);
Stream& stream = streams[handle];
// Reset counters
stream.tickCount = 0;
stream.frameCount = 0;
// Save requested frame rate ratio
stream.frame_rate_ticks = ui_frames;
stream.frame_rate_video = video_frames;
}
virtual void setVideoData(const Handle handle, const uint8_t* movie, const uint32_t length)
{
// Running in UI thread
mjpegDecoders[handle]->setVideoData(movie, length);
clearState(handle);
}
virtual void setVideoData(const Handle handle, VideoDataReader& reader)
{
// Running in UI thread
mjpegDecoders[handle]->setVideoData(reader);
clearState(handle);
}
virtual void setCommand(const Handle handle, Command cmd, uint32_t param)
{
// Running in UI thread
assert(handle < no_streams);
Stream& stream = streams[handle];
switch (cmd)
{
case PLAY:
// Cannot Play without movie
if (mjpegDecoders[handle]->hasVideo())
{
MUTEX_LOCK(mutexBuffers);
stream.isPlaying = true;
stream.cancelDecoding = false;
// Reset counters
stream.frameCount = 0;
stream.tickCount = 0;
// Seek to start of video if stopped
if (stream.isStopped)
{
stream.seek_to_frame = 1;
}
stream.isStopped = false;
// Kick decoder if next buffer is available
stream.skip_frames = 0;
if (stream.nextBuffer == 0)
{
stream.doDecodeNewFrame = true;
SEM_POST(semDecode);
}
MUTEX_UNLOCK(mutexBuffers);
}
break;
case PAUSE:
stream.isPlaying = false;
stream.isStopped = false;
break;
case SEEK:
stream.seek_to_frame = param;
// Reset counters
stream.frameCount = 0;
stream.tickCount = 0;
break;
case SHOW:
stream.seek_to_frame = param;
// Reset counters
stream.frameCount = 0;
stream.tickCount = 0;
stream.isStopped = false;
break;
case STOP:
stream.isPlaying = false;
stream.isStopped = true;
break;
case SET_REPEAT:
stream.repeat = (param > 0);
break;
}
}
/**
* Called by VideoWidget::handleTickEvent.
* Update frame counters.
* Decide if widget should be invalidated.
*/
virtual bool updateFrame(const Handle handle, touchgfx::VideoWidget& widget)
{
// Running in UI thread
assert(handle < no_streams);
Stream& stream = streams[handle];
// Increase tickCount if playing
if (stream.isPlaying)
{
stream.tickCount += HAL::getInstance()->getLCDRefreshCount();
}
// Assume more frames are available, flag is lowered once, when changing to the last frame
bool hasMoreFrames = true;
// See if we have a nextBuffer and if next frame of specific frame is to be decoded
if (stream.nextBuffer && (decodeForNextTick(stream) || stream.seek_to_frame > 0))
{
MUTEX_LOCK(mutexBuffers);
// Do nothing if seek to frame
if (stream.seek_to_frame > 0)
{
stream.nextBuffer = 0;
}
if (stream.nextBuffer != 0)
{
// Use nextBuffer as current
stream.currentBuffer = stream.nextBuffer;
stream.nextBuffer = 0;
// Copy frameNumber, increase count
stream.frameNumberShown = stream.frameNumberNext;
stream.frameCount++;
hasMoreFrames = stream.hasMoreFramesAfterNext;
// Update widget to show current buffer
widget.setVideoBuffer(stream.currentBuffer);
widget.invalidate();
if (!hasMoreFrames && !stream.repeat)
{
stream.isPlaying = false;
}
}
MUTEX_UNLOCK(mutexBuffers);
}
// Kick decoder if playing or seeking frame and next buffer is ready
if ((stream.isPlaying || stream.seek_to_frame > 0) && (stream.nextBuffer == 0))
{
stream.doDecodeNewFrame = true;
SEM_POST(semDecode);
}
return hasMoreFrames;
}
virtual void draw(const Handle handle, const touchgfx::Rect& invalidatedArea, const touchgfx::VideoWidget& widget)
{
// Running in UI thread
// Nothing in this decoder
}
void setRGBBuffer(uint8_t* buffer, size_t sizeOfBuffer)
{
// Running in UI thread / main
bufferRGB = buffer;
topBufferRGB = bufferRGB;
sizeBufferRGB = sizeOfBuffer;
}
void addDecoder(MJPEGDecoder& decoder, uint32_t index)
{
// Running in UI thread / main
assert(index < no_streams);
mjpegDecoders[index] = &decoder;
}
void endFrame()
{
// Running in UI thread
// Nothing to do
}
void decoderTaskEntry()
{
// Running in Decoder thread!!
while (1)
{
// Look for a stream to decode
uint32_t stream_index = getStreamIndexToDecode();
if (stream_index == NO_STREAM)
{
// All streams decoded, wait for synchronisation signal from UI thread
SEM_WAIT(semDecode);
// Try from the beginning
continue;
}
// Lock out UI by taking the mutex
MUTEX_LOCK(mutexBuffers);
// Now decode the stream
Stream& stream = streams[stream_index];
// Select the unused buffer for decoding
uint8_t* decodeBuffer = (stream.currentBuffer == stream.bufferA) ? stream.bufferB : stream.bufferA;
MJPEGDecoder* const decoder = mjpegDecoders[stream_index];
// Seek or increment video frame
if (stream.seek_to_frame > 0)
{
decoder->gotoFrame(stream.seek_to_frame);
stream.seek_to_frame = 0;
stream.cancelDecoding = false;
}
else
{
if (stream.skip_frames > 0)
{
decoder->gotoFrame(decoder->getCurrentFrameNumber() + stream.skip_frames);
stream.frameCount += stream.skip_frames;
stream.skip_frames = 0;
}
}
// Unlock mutex while decoding
MUTEX_UNLOCK(mutexBuffers);
// Decode frame
const bool hasMoreFrames = decoder->decodeNextFrame(decodeBuffer, width, height, stride);
MUTEX_LOCK(mutexBuffers);
// Save new frame in stream unless cancelled
if (stream.cancelDecoding)
{
stream.cancelDecoding = false;
}
else
{
stream.nextBuffer = decodeBuffer;
if (hasMoreFrames)
{
stream.frameNumberNext = decoder->getCurrentFrameNumber() - 1; // Points to frame after this
}
else
{
stream.frameNumberNext = 1;
}
stream.hasMoreFramesAfterNext = hasMoreFrames;
// Lower decode flag
stream.doDecodeNewFrame = false;
}
// Release the mutex
MUTEX_UNLOCK(mutexBuffers);
}
}
virtual void getVideoInformation(const Handle handle, touchgfx::VideoInformation* data)
{
assert(handle < no_streams);
mjpegDecoders[handle]->getVideoInfo(data);
}
virtual bool getIsPlaying(const Handle handle)
{
assert(handle < no_streams);
Stream& stream = streams[handle];
return stream.isPlaying;
}
virtual void setVideoFrameRateCompensation(bool allow)
{
allowSkipFrames = allow;
}
private:
class Stream
{
public:
Stream() : frameCount(0), frameNumberNext(0), frameNumberShown(0), tickCount(0),
frame_rate_video(0), frame_rate_ticks(0),
seek_to_frame(0), skip_frames(0),
currentBuffer(0), nextBuffer(0), bufferA(0), bufferB(0),
isActive(false), isPlaying(false),
doDecodeNewFrame(false), cancelDecoding(false),
hasMoreFramesAfterNext(false), repeat(true), isStopped(false)
{}
uint32_t frameCount; // Video frame count since play/speed change
uint32_t frameNumberNext; // Next Video frame number (if any)
uint32_t frameNumberShown; // Shown Video frame number
uint32_t tickCount; // UI frames since play
uint32_t frame_rate_video; // Ratio of frames wanted counter
uint32_t frame_rate_ticks; // Ratio of frames wanted divider
uint32_t seek_to_frame; // Requested next frame number
uint32_t skip_frames; // Number of frames to skip to keep frame rate
uint8_t* currentBuffer; // Current Video frame, used for drawing
uint8_t* nextBuffer; // Already decode next video frame, or zero
uint8_t* bufferA; // One buffer allocated for this stream
uint8_t* bufferB; // Another buffer allocated for this stream
bool isActive;
bool isPlaying;
bool doDecodeNewFrame;
bool cancelDecoding;
bool hasMoreFramesAfterNext;
bool repeat;
bool isStopped;
};
enum
{
NO_STREAM = 0xFFFF
};
MJPEGDecoder* mjpegDecoders[no_streams];
Stream streams[no_streams];
uint8_t* bufferRGB;
size_t sizeBufferRGB; // Size in Bytes
uint8_t* topBufferRGB; // Pointer to unused memory in buffer
bool allowSkipFrames;
SEM_TYPE semDecode; // Post by UI, wait by Decoder thread
MUTEX_TYPE mutexBuffers; // Mutual exclusion of the video buffers and stream data
/* return true, if new video frame should be decoded for the next tick (keep video decode framerate low) */
bool decodeForNextTick(Stream& stream)
{
// Running in UI thread
// Compare tickCount/frameCount to frame_rate_ticks/frame_rate_video
if ((stream.tickCount * stream.frame_rate_video) >= (stream.frame_rate_ticks * stream.frameCount))
{
if (allowSkipFrames)
{
stream.skip_frames = (stream.tickCount * stream.frame_rate_video - stream.frame_rate_ticks * stream.frameCount) / stream.frame_rate_ticks;
if (stream.skip_frames > 0)
{
stream.skip_frames--;
}
}
return true;
}
return false;
}
Handle getFreeHandle()
{
// Running in UI thread
for (uint32_t i = 0; i < no_streams; i++)
{
if (streams[i].isActive == false)
{
// Reset stream parameters
streams[i] = Stream();
return static_cast<VideoController::Handle>(i);
}
}
assert(0 && "Unable to find free video stream handle!");
return static_cast<VideoController::Handle>(0);
}
uint32_t getStreamIndexToDecode()
{
for (uint32_t i = 0; i < no_streams; i++)
{
Stream& stream = streams[i];
if (stream.doDecodeNewFrame) // Marked by UI for decoding
{
return i;
}
}
return NO_STREAM;
}
void clearState(const Handle handle)
{
// Stop playing, and clear next buffer if any, cancel ongoing decoding
setCommand(handle, STOP, 0);
MUTEX_LOCK(mutexBuffers);
Stream& stream = streams[handle];
if (stream.nextBuffer != 0)
{
// Ignore any decoded buffer
stream.nextBuffer = 0;
}
stream.cancelDecoding = true;
stream.isPlaying = false;
MUTEX_UNLOCK(mutexBuffers);
}
};
#endif // TOUCHGFX_BUFFERPOOLVIDEOCONTROLLER_HPP

View File

@@ -0,0 +1,89 @@
/**
******************************************************************************
* File Name : MJPEGDecoder.hpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.26.0. Please, do not edit!
******************************************************************************
* @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.
*
******************************************************************************
*/
#ifndef TOUCHGFX_MJPEGDECODER_HPP
#define TOUCHGFX_MJPEGDECODER_HPP
#include <touchgfx/hal/Types.hpp>
#include <touchgfx/hal/VideoController.hpp>
class MJPEGDecoder
{
public:
virtual ~MJPEGDecoder()
{
}
//Set video data for the decoder
virtual void setVideoData(const uint8_t* movie, const uint32_t length) = 0;
//Set video data for the decoder
virtual void setVideoData(touchgfx::VideoDataReader& reader) = 0;
/**
* Check if MJPEGDecoder has a video.
*
* @return Returns true if the MJPEGDecoder has a video.
*/
virtual bool hasVideo() = 0;
//Increment position to next frame and decode and convert to RGB
virtual bool decodeNextFrame(uint8_t* buffer, uint16_t width, uint16_t height, uint32_t stride) = 0;
//Increment position to next frame and decode. Used with decodeFrame.
virtual bool gotoNextFrame() = 0;
//Decode part of the current frame, framebuffer is locked, area is drawn relative to frameBuffer
virtual bool decodeFrame(const touchgfx::Rect& area, uint8_t* frameBuffer, uint32_t framebufferStride) = 0;
//Decode thumbnail, assumes buffer stride is width
virtual bool decodeThumbnail(uint32_t frameno, uint8_t* buffer, uint16_t width, uint16_t height) = 0;
//Set current frame number
virtual void gotoFrame(uint32_t frameno) = 0;
//Get current frame number
virtual uint32_t getCurrentFrameNumber() const = 0;
//Get number of frames in video
virtual uint32_t getNumberOfFrames() = 0;
//Read video information
virtual void getVideoInfo(touchgfx::VideoInformation* data) = 0;
enum AVIErrors
{
AVI_NO_ERROR,
AVI_NO_BUFFERS,
AVI_NO_FILE,
AVI_ERROR_NOT_RIFF,
AVI_ERROR_AVI_HEADER_NOT_FOUND,
AVI_ERROR_AVI_LIST_NOT_FOUND,
AVI_ERROR_AVI_HDRL_NOT_FOUND,
AVI_ERROR_AVI_AVIH_NOT_FOUND,
AVI_ERROR_AVI_HEADER_TO_SHORT, //not full header provided
AVI_ERROR_FILE_BUFFER_TO_SMALL,
AVI_ERROR_MOVI_NOT_FOUND,
AVI_ERROR_IDX1_NOT_FOUND,
AVI_ERROR_FRAMENO_TO_HIGH,
AVI_ERROR_EOF_REACHED
};
AVIErrors virtual getLastError() = 0;
};
#endif // TOUCHGFX_MJPEGDECODER_HPP

View File

@@ -0,0 +1,156 @@
/**
******************************************************************************
* File Name : OSWrappers.cpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.26.0. Please, do not edit!
******************************************************************************
* @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.
*
******************************************************************************
*/
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/hal/OSWrappers.hpp>
#include <cmsis_os2.h>
#include <cassert>
static osSemaphoreId_t frame_buffer_sem = NULL;
static osMessageQueueId_t vsync_queue = NULL;
// Just a dummy value to insert in the VSYNC queue.
static uint32_t dummy = 0x5a;
using namespace touchgfx;
/*
* Initialize frame buffer semaphore and queue/mutex for VSYNC signal.
*/
void OSWrappers::initialize()
{
// Create a queue of length 1
frame_buffer_sem = osSemaphoreNew(1, 1, NULL); // Binary semaphore
assert((frame_buffer_sem != NULL) && "Creation of framebuffer semaphore failed");
// Create a queue of length 1
vsync_queue = osMessageQueueNew(1, 4, NULL);
assert((vsync_queue != NULL) && "Creation of vsync message queue failed");
}
/*
* Take the frame buffer semaphore. Blocks until semaphore is available.
*/
void OSWrappers::takeFrameBufferSemaphore()
{
osSemaphoreAcquire(frame_buffer_sem, osWaitForever);
}
/*
* Release the frame buffer semaphore.
*/
void OSWrappers::giveFrameBufferSemaphore()
{
osSemaphoreRelease(frame_buffer_sem);
}
/*
* Attempt to obtain the frame buffer semaphore. If semaphore is not available, do
* nothing.
*
* Note must return immediately! This function does not care who has the taken the semaphore,
* it only serves to make sure that the semaphore is taken by someone.
*/
void OSWrappers::tryTakeFrameBufferSemaphore()
{
osSemaphoreAcquire(frame_buffer_sem, 0);
}
/*
* Release the frame buffer semaphore in a way that is safe in interrupt context. Called
* from ISR.
*
* Release the frame buffer semaphore in a way that is safe in interrupt context.
* Called from ISR.
*/
void OSWrappers::giveFrameBufferSemaphoreFromISR()
{
osSemaphoreRelease(frame_buffer_sem);
}
/*
* Signal that a VSYNC has occurred. Should make the vsync queue/mutex available.
*
* Note This function is called from an ISR, and should (depending on OS) trigger a
* scheduling.
*/
void OSWrappers::signalVSync()
{
osMessageQueuePut(vsync_queue, &dummy, 0, 0);
}
/*
* Signal that the rendering of the frame has completed. Used by
* some systems to avoid using any previous vsync.
*/
void OSWrappers::signalRenderingDone()
{
// Empty implementation for CMSIS V2
}
/*
* This function blocks until a VSYNC occurs.
*
* Note This function must first clear the mutex/queue and then wait for the next one to
* occur.
*/
void OSWrappers::waitForVSync()
{
uint32_t dummyGet;
// First make sure the queue is empty, by trying to remove an element with 0 timeout.
osMessageQueueGet(vsync_queue, &dummyGet, 0, 0);
// Then, wait for next VSYNC to occur.
osMessageQueueGet(vsync_queue, &dummyGet, 0, osWaitForever);
}
/*
* A function that causes executing task to sleep for a number of milliseconds.
*
* A function that causes executing task to sleep for a number of milliseconds.
* This function is OPTIONAL. It is only used by the TouchGFX in the case of
* a specific frame refresh strategy (REFRESH_STRATEGY_OPTIM_SINGLE_BUFFER_TFT_CTRL).
* Due to backwards compatibility, in order for this function to be useable by the HAL
* the function must be explicitly registered:
* hal.registerTaskDelayFunction(&OSWrappers::taskDelay)
*
* see HAL::setFrameRefreshStrategy(FrameRefreshStrategy s)
* see HAL::registerTaskDelayFunction(void (*delayF)(uint16_t))
*/
void OSWrappers::taskDelay(uint16_t ms)
{
osDelay(static_cast<uint32_t>(ms));
}
/**
* A function that causes the executing task to yield control to
* another thread. This function is used by the framework when it
* is necessary to wait a little before continuing (e.g. drawing).
*
* The implementation should typically request the operating
* system to change to another task of similar priority. When
* running without an operating system, the implementation can run
* a very short task and return.
*/
void OSWrappers::taskYield()
{
osThreadYield();
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,714 @@
/**
******************************************************************************
* File Name : STM32DMA.cpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.26.0. Please, do not edit!
******************************************************************************
* @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.
*
******************************************************************************
*/
#include "stm32f7xx_hal.h"
#include "stm32f7xx_hal_dma2d.h"
#include <STM32DMA.hpp>
#include <cassert>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/hal/Paint.hpp>
/* Makes touchgfx specific types and variables visible to this file */
using namespace touchgfx;
typedef struct
{
const uint16_t format;
const uint16_t size;
const uint32_t* const data;
} clutData_t;
extern "C" DMA2D_HandleTypeDef hdma2d;
extern "C" {
static void DMA2D_XferCpltCallback(DMA2D_HandleTypeDef* handle)
{
(void)handle; // Unused argument
HAL::getInstance()->signalDMAInterrupt();
}
static void DMA2D_XferErrorCallback(DMA2D_HandleTypeDef* handle)
{
(void)handle; // Unused argument
while (1)
{
}
}
}
STM32DMA::STM32DMA()
: DMA_Interface(dma_queue), dma_queue(queue_storage, sizeof(queue_storage) / sizeof(queue_storage[0]))
{
}
STM32DMA::~STM32DMA()
{
/* Disable DMA2D global Interrupt */
NVIC_DisableIRQ(DMA2D_IRQn);
}
void STM32DMA::initialize()
{
/* Ensure DMA2D Clock is enabled */
__HAL_RCC_DMA2D_CLK_ENABLE();
__HAL_RCC_DMA2D_FORCE_RESET();
__HAL_RCC_DMA2D_RELEASE_RESET();
/* Add transfer error callback function */
hdma2d.XferErrorCallback = DMA2D_XferErrorCallback;
/* Add transfer complete callback function */
hdma2d.XferCpltCallback = DMA2D_XferCpltCallback;
/* Enable DMA2D global Interrupt */
NVIC_EnableIRQ(DMA2D_IRQn);
}
inline uint32_t STM32DMA::getChromARTInputFormat(Bitmap::BitmapFormat format)
{
// Default color mode set to ARGB8888
uint32_t dma2dColorMode = DMA2D_INPUT_ARGB8888;
switch (format)
{
case Bitmap::ARGB8888: /* DMA2D input mode set to 32bit ARGB */
dma2dColorMode = DMA2D_INPUT_ARGB8888;
break;
case Bitmap::RGB888: /* DMA2D input mode set to 24bit RGB */
dma2dColorMode = DMA2D_INPUT_RGB888;
break;
case Bitmap::RGB565: /* DMA2D input mode set to 16bit RGB */
dma2dColorMode = DMA2D_INPUT_RGB565;
break;
case Bitmap::ARGB2222: /* Fall through */
case Bitmap::ABGR2222: /* Fall through */
case Bitmap::RGBA2222: /* Fall through */
case Bitmap::BGRA2222: /* Fall through */
case Bitmap::L8: /* DMA2D input mode set to 8bit Color Look up table*/
dma2dColorMode = DMA2D_INPUT_L8;
break;
case Bitmap::BW: /* Fall through */
case Bitmap::BW_RLE: /* Fall through */
case Bitmap::GRAY4: /* Fall through */
case Bitmap::GRAY2: /* Fall through */
default: /* Unsupported input format for DMA2D */
assert(0 && "Unsupported Format!");
break;
}
return dma2dColorMode;
}
inline uint32_t STM32DMA::getChromARTOutputFormat(Bitmap::BitmapFormat format)
{
// Default color mode set to ARGB8888
uint32_t dma2dColorMode = DMA2D_OUTPUT_ARGB8888;
switch (format)
{
case Bitmap::ARGB8888: /* DMA2D output mode set to 32bit ARGB */
dma2dColorMode = DMA2D_OUTPUT_ARGB8888;
break;
case Bitmap::RGB888: /* Fall through */
case Bitmap::ARGB2222: /* Fall through */
case Bitmap::ABGR2222: /* Fall through */
case Bitmap::RGBA2222: /* Fall through */
case Bitmap::BGRA2222: /* DMA2D output mode set to 24bit RGB */
dma2dColorMode = DMA2D_OUTPUT_RGB888;
break;
case Bitmap::RGB565: /* DMA2D output mode set to 16bit RGB */
dma2dColorMode = DMA2D_OUTPUT_RGB565;
break;
case Bitmap::L8: /* Fall through */
case Bitmap::BW: /* Fall through */
case Bitmap::BW_RLE: /* Fall through */
case Bitmap::GRAY4: /* Fall through */
case Bitmap::GRAY2: /* Fall through */
default: /* Unsupported output format for DMA2D */
assert(0 && "Unsupported Format!");
break;
}
return dma2dColorMode;
}
BlitOperations STM32DMA::getBlitCaps()
{
return static_cast<BlitOperations>(BLIT_OP_FILL
| BLIT_OP_FILL_WITH_ALPHA
| BLIT_OP_COPY
| BLIT_OP_COPY_L8
| BLIT_OP_COPY_WITH_ALPHA
| BLIT_OP_COPY_ARGB8888
| BLIT_OP_COPY_ARGB8888_WITH_ALPHA
| BLIT_OP_COPY_A4
| BLIT_OP_COPY_A8);
}
/*
* void STM32DMA::setupDataCopy(const BlitOp& blitOp) handles blit operation of
* BLIT_OP_COPY
* BLIT_OP_COPY_L8
* BLIT_OP_COPY_WITH_ALPHA
* BLIT_OP_COPY_ARGB8888
* BLIT_OP_COPY_ARGB8888_WITH_ALPHA
* BLIT_OP_COPY_A4
* BLIT_OP_COPY_A8
*/
void STM32DMA::setupDataCopy(const BlitOp& blitOp)
{
uint32_t dma2dForegroundColorMode = getChromARTInputFormat(static_cast<Bitmap::BitmapFormat>(blitOp.srcFormat));
uint32_t dma2dBackgroundColorMode = getChromARTInputFormat(static_cast<Bitmap::BitmapFormat>(blitOp.dstFormat));
uint32_t dma2dOutputColorMode = getChromARTOutputFormat(static_cast<Bitmap::BitmapFormat>(blitOp.dstFormat));
/* DMA2D OOR register configuration */
WRITE_REG(DMA2D->OOR, blitOp.dstLoopStride - blitOp.nSteps);
/* DMA2D BGOR register configuration */
WRITE_REG(DMA2D->BGOR, blitOp.dstLoopStride - blitOp.nSteps);
/* DMA2D FGOR register configuration */
WRITE_REG(DMA2D->FGOR, blitOp.srcLoopStride - blitOp.nSteps);
/* DMA2D OPFCCR register configuration */
WRITE_REG(DMA2D->OPFCCR, dma2dOutputColorMode);
/* Configure DMA2D data size */
WRITE_REG(DMA2D->NLR, (blitOp.nLoops | (blitOp.nSteps << DMA2D_NLR_PL_Pos)));
/* Configure DMA2D destination address */
WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(blitOp.pDst));
/* Configure DMA2D source address */
WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(blitOp.pSrc));
switch (blitOp.operation)
{
case BLIT_OP_COPY_A4:
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_A4 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));
/* set DMA2D foreground color */
WRITE_REG(DMA2D->FGCOLR, blitOp.color);
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, dma2dBackgroundColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));
/* Set DMA2D mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_IT_TC | DMA2D_CR_START | DMA2D_IT_CE | DMA2D_IT_TE);
break;
case BLIT_OP_COPY_A8:
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_A8 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));
/* set DMA2D foreground color */
WRITE_REG(DMA2D->FGCOLR, blitOp.color);
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, dma2dBackgroundColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));
/* Set DMA2D mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_IT_TC | DMA2D_CR_START | DMA2D_IT_CE | DMA2D_IT_TE);
break;
case BLIT_OP_COPY_WITH_ALPHA:
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, dma2dForegroundColorMode | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, dma2dBackgroundColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));
/* Set DMA2D mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_IT_TC | DMA2D_CR_START | DMA2D_IT_CE | DMA2D_IT_TE);
break;
case BLIT_OP_COPY_L8:
{
bool blend = true;
const clutData_t* const palette = reinterpret_cast<const clutData_t*>(blitOp.pClut);
/* Write foreground CLUT memory address */
WRITE_REG(DMA2D->FGCMAR, reinterpret_cast<uint32_t>(&palette->data));
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, dma2dForegroundColorMode | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, dma2dBackgroundColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));
/* Configure CLUT */
switch ((Bitmap::ClutFormat)palette->format)
{
case Bitmap::CLUT_FORMAT_L8_ARGB8888:
/* Write foreground CLUT size and CLUT color mode */
MODIFY_REG(DMA2D->FGPFCCR, (DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM), (((palette->size - 1) << DMA2D_FGPFCCR_CS_Pos) | (DMA2D_CCM_ARGB8888 << DMA2D_FGPFCCR_CCM_Pos)));
break;
case Bitmap::CLUT_FORMAT_L8_RGB888:
if (blitOp.alpha == 255)
{
blend = false;
}
MODIFY_REG(DMA2D->FGPFCCR, (DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM), (((palette->size - 1) << DMA2D_FGPFCCR_CS_Pos) | (DMA2D_CCM_RGB888 << DMA2D_FGPFCCR_CCM_Pos)));
break;
case Bitmap::CLUT_FORMAT_L8_RGB565:
default:
assert(0 && "Unsupported format");
break;
}
/* Enable the CLUT loading for the foreground */
SET_BIT(DMA2D->FGPFCCR, DMA2D_FGPFCCR_START);
while ((READ_REG(DMA2D->FGPFCCR) & DMA2D_FGPFCCR_START) != 0U)
{
}
DMA2D->IFCR = (DMA2D_FLAG_CTC);
/* Set DMA2D mode */
if (blend)
{
WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_IT_TC | DMA2D_CR_START | DMA2D_IT_CE | DMA2D_IT_TE);
}
else
{
WRITE_REG(DMA2D->CR, DMA2D_M2M_PFC | DMA2D_IT_TC | DMA2D_CR_START | DMA2D_IT_CE | DMA2D_IT_TE);
}
}
break;
case BLIT_OP_COPY_ARGB8888:
case BLIT_OP_COPY_ARGB8888_WITH_ALPHA:
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, dma2dForegroundColorMode | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, dma2dBackgroundColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));
/* Set DMA2D mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_IT_TC | DMA2D_CR_START | DMA2D_IT_CE | DMA2D_IT_TE);
break;
default: /* BLIT_OP_COPY */
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, dma2dForegroundColorMode | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));
/* Perform pixel-format-conversion (PFC) If Bitmap format is not same format as framebuffer format */
if (blitOp.srcFormat != blitOp.dstFormat)
{
/* Start DMA2D : PFC Mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M_PFC | DMA2D_IT_TC | DMA2D_CR_START | DMA2D_IT_CE | DMA2D_IT_TE);
}
else
{
/* Start DMA2D : M2M Mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M | DMA2D_IT_TC | DMA2D_CR_START | DMA2D_IT_CE | DMA2D_IT_TE);
}
break;
}
}
/*
* void STM32DMA::setupDataFill(const BlitOp& blitOp) handles blit operation of
* BLIT_OP_FILL
* BLIT_OP_FILL_WITH_ALPHA
*/
void STM32DMA::setupDataFill(const BlitOp& blitOp)
{
uint32_t dma2dOutputColorMode = getChromARTOutputFormat(static_cast<Bitmap::BitmapFormat>(blitOp.dstFormat));
/* DMA2D OPFCCR register configuration */
WRITE_REG(DMA2D->OPFCCR, dma2dOutputColorMode);
/* Configure DMA2D data size */
WRITE_REG(DMA2D->NLR, (blitOp.nLoops | (blitOp.nSteps << DMA2D_NLR_PL_Pos)));
/* Configure DMA2D destination address */
WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(blitOp.pDst));
/* DMA2D OOR register configuration */
WRITE_REG(DMA2D->OOR, blitOp.dstLoopStride - blitOp.nSteps);
if (blitOp.operation == BLIT_OP_FILL_WITH_ALPHA)
{
/* DMA2D BGOR register configuration */
WRITE_REG(DMA2D->BGOR, blitOp.dstLoopStride - blitOp.nSteps);
/* DMA2D FGOR register configuration */
WRITE_REG(DMA2D->FGOR, blitOp.dstLoopStride - blitOp.nSteps);
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, dma2dOutputColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Write DMA2D FGPFCCR register */
WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_A8 | (DMA2D_REPLACE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | ((blitOp.alpha << 24) & DMA2D_FGPFCCR_ALPHA));
/* DMA2D FGCOLR register configuration */
WRITE_REG(DMA2D->FGCOLR, blitOp.color);
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));
/* Configure DMA2D source address */
WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));
/* Enable the Peripheral and Enable the transfer complete interrupt */
WRITE_REG(DMA2D->CR, (DMA2D_IT_TC | DMA2D_CR_START | DMA2D_M2M_BLEND | DMA2D_IT_CE | DMA2D_IT_TE));
}
else
{
/* Write DMA2D FGPFCCR register */
WRITE_REG(DMA2D->FGPFCCR, dma2dOutputColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_FGPFCCR_AM_Pos));
/* DMA2D FGOR register configuration */
WRITE_REG(DMA2D->FGOR, 0);
/* Set color */
WRITE_REG(DMA2D->OCOLR, blitOp.color);
/* Enable the Peripheral and Enable the transfer complete interrupt */
WRITE_REG(DMA2D->CR, (DMA2D_IT_TC | DMA2D_CR_START | DMA2D_R2M | DMA2D_IT_CE | DMA2D_IT_TE));
}
}
namespace touchgfx
{
namespace paint
{
namespace
{
const clutData_t* L8CLUT = 0;
uint32_t L8ClutLoaded = 0;
} // namespace
void setL8Palette(const uint8_t* const data)
{
L8CLUT = reinterpret_cast<const clutData_t*>(data - offsetof(clutData_t, data));
L8ClutLoaded = 0;
}
/**
* @fn void tearDown();
*
* @brief Waits until previous DMA drawing operation has finished
*/
void tearDown()
{
/* Wait for DMA2D to finish last run */
while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);
/* Clear transfer flags */
WRITE_REG(DMA2D->IFCR, DMA2D_FLAG_TC | DMA2D_FLAG_CE | DMA2D_FLAG_TE);
}
/** Flushes a line of pixels in the data cache if used.
*
* @brief Flushes decoded RGB pixels when rendering compressed images
*/
void flushLine(uint32_t* addr, int sizebytes)
{
// This function is used when decompressing data to flush
// the currently decoded data in the cache to allow the DMA2D
// to blend the pixels correctly.
if (SCB->CCR & SCB_CCR_DC_Msk)
{
SCB_CleanDCache_by_Addr(addr, sizebytes);
}
}
/**
* @fn void invalidateTextureCache();
*
* @brief Flushes the data cache if used.
*/
void invalidateTextureCache()
{
}
namespace rgb565
{
/**
* @fn void lineFromColor();
*
* @brief Renders Canvas Widget chunks using DMA.
* This functions will not generate an interrupt, and will not affect the DMA queue.
*/
void lineFromColor(uint16_t* const ptr, const unsigned count, const uint32_t color, const uint8_t alpha, const uint32_t color565)
{
/* Wait for DMA2D to finish last run */
while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);
/* Clear transfer flags */
WRITE_REG(DMA2D->IFCR, DMA2D_FLAG_TC | DMA2D_FLAG_CE | DMA2D_FLAG_TE);
/* DMA2D OPFCCR register configuration */
WRITE_REG(DMA2D->OPFCCR, DMA2D_OUTPUT_RGB565);
/* Configure DMA2D data size */
WRITE_REG(DMA2D->NLR, (1 | (count << DMA2D_NLR_PL_Pos)));
/* Configure DMA2D destination address */
WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(ptr));
if (alpha < 0xFF)
{
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, DMA2D_OUTPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Write DMA2D FGPFCCR register */
WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_A8 | (DMA2D_REPLACE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (alpha << DMA2D_FGPFCCR_ALPHA_Pos));
/* DMA2D FGCOLR register configuration */
WRITE_REG(DMA2D->FGCOLR, color);
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, (uint32_t)ptr);
/* Configure DMA2D source address */
WRITE_REG(DMA2D->FGMAR, (uint32_t)ptr);
/* Enable the Peripheral and Enable the transfer complete interrupt */
WRITE_REG(DMA2D->CR, (DMA2D_CR_START | DMA2D_M2M_BLEND));
}
else
{
/* Write DMA2D FGPFCCR register */
WRITE_REG(DMA2D->FGPFCCR, DMA2D_OUTPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_FGPFCCR_AM_Pos));
/* Set color */
WRITE_REG(DMA2D->OCOLR, color565);
/* Enable the Peripheral and Enable the transfer complete interrupt */
WRITE_REG(DMA2D->CR, (DMA2D_CR_START | DMA2D_R2M));
}
}
void lineFromRGB565(uint16_t* const ptr, const uint16_t* const data, const unsigned count, const uint8_t alpha)
{
/* Wait for DMA2D to finish last run */
while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);
/* Clear transfer flags */
WRITE_REG(DMA2D->IFCR, DMA2D_FLAG_TC | DMA2D_FLAG_CE | DMA2D_FLAG_TE);
/* DMA2D OPFCCR register configuration */
WRITE_REG(DMA2D->OPFCCR, DMA2D_OUTPUT_RGB565);
/* Configure DMA2D data size */
WRITE_REG(DMA2D->NLR, (1 | (count << DMA2D_NLR_PL_Pos)));
/* Configure DMA2D destination address */
WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(ptr));
/* Configure DMA2D source address */
WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(data));
if (alpha < 0xFF)
{
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (alpha << DMA2D_FGPFCCR_ALPHA_Pos));
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(ptr));
/* Set DMA2D mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_CR_START);
}
else
{
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (alpha << DMA2D_FGPFCCR_ALPHA_Pos));
/* Start DMA2D : M2M Mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M | DMA2D_CR_START);
}
}
void lineFromARGB8888(uint16_t* const ptr, const uint32_t* const data, const unsigned count, const uint8_t alpha)
{
/* Wait for DMA2D to finish last run */
while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);
/* Clear transfer flags */
WRITE_REG(DMA2D->IFCR, DMA2D_FLAG_TC | DMA2D_FLAG_CE | DMA2D_FLAG_TE);
/* DMA2D OPFCCR register configuration */
WRITE_REG(DMA2D->OPFCCR, DMA2D_OUTPUT_RGB565);
/* Configure DMA2D data size */
WRITE_REG(DMA2D->NLR, (1 | (count << DMA2D_NLR_PL_Pos)));
/* Configure DMA2D destination address */
WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(ptr));
/* Configure DMA2D source address */
WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(data));
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_ARGB8888 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (alpha << DMA2D_FGPFCCR_ALPHA_Pos));
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(ptr));
/* Set DMA2D mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_CR_START);
}
void lineFromL8RGB888(uint16_t* const ptr, const uint8_t* const data, const unsigned count, const uint8_t alpha)
{
/* wait for DMA2D to finish last run */
while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);
/* DMA2D OPFCCR register configuration */
WRITE_REG(DMA2D->OPFCCR, DMA2D_OUTPUT_RGB565);
/* Configure DMA2D data size */
WRITE_REG(DMA2D->NLR, (1 | (count << DMA2D_NLR_PL_Pos)));
/* Configure DMA2D destination address */
WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(ptr));
/* Configure DMA2D source address */
WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(data));
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(ptr));
/* Load CLUT if not already loaded */
if (L8ClutLoaded == 0)
{
/* Write foreground CLUT memory address */
WRITE_REG(DMA2D->FGCMAR, reinterpret_cast<uint32_t>(&L8CLUT->data));
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_L8 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (alpha << DMA2D_FGPFCCR_ALPHA_Pos));
MODIFY_REG(DMA2D->FGPFCCR, (DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM), (((L8CLUT->size - 1) << DMA2D_FGPFCCR_CS_Pos) | (DMA2D_CCM_RGB888 << DMA2D_FGPFCCR_CCM_Pos)));
/* Enable the CLUT loading for the foreground */
SET_BIT(DMA2D->FGPFCCR, DMA2D_FGPFCCR_START);
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Mark CLUT loaded */
L8ClutLoaded = 1;
/* Wait for load to finish */
while ((READ_REG(DMA2D->FGPFCCR) & DMA2D_FGPFCCR_START) != 0U);
/* Clear CLUT Transfer Complete flag */
DMA2D->IFCR = (DMA2D_FLAG_CTC);
}
else
{
/* Set correct alpha for these pixels */
MODIFY_REG(DMA2D->FGPFCCR, DMA2D_BGPFCCR_ALPHA_Msk, alpha << DMA2D_FGPFCCR_ALPHA_Pos);
}
/* Start pixel transfer in correct mode */
if (alpha < 0xFF)
{
/* Set DMA2D mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_CR_START);
}
else
{
/* Set DMA2D mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M_PFC | DMA2D_CR_START);
}
}
void lineFromL8ARGB8888(uint16_t* const ptr, const uint8_t* const data, const unsigned count, const uint8_t alpha)
{
/* wait for DMA2D to finish last run */
while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);
/* DMA2D OPFCCR register configuration */
WRITE_REG(DMA2D->OPFCCR, DMA2D_OUTPUT_RGB565);
/* Configure DMA2D data size */
WRITE_REG(DMA2D->NLR, (1 | (count << DMA2D_NLR_PL_Pos)));
/* Configure DMA2D destination address */
WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(ptr));
/* Configure DMA2D source address */
WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(data));
/* Configure DMA2D Stream source2 address */
WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(ptr));
/* Load CLUT if not already loaded */
if (L8ClutLoaded == 0)
{
/* Write foreground CLUT memory address */
WRITE_REG(DMA2D->FGCMAR, reinterpret_cast<uint32_t>(&L8CLUT->data));
/* Set DMA2D color mode and alpha mode */
WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_L8 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (alpha << DMA2D_FGPFCCR_ALPHA_Pos));
MODIFY_REG(DMA2D->FGPFCCR, (DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM), (((L8CLUT->size - 1) << DMA2D_FGPFCCR_CS_Pos) | (DMA2D_CCM_ARGB8888 << DMA2D_FGPFCCR_CCM_Pos)));
/* Enable the CLUT loading for the foreground */
SET_BIT(DMA2D->FGPFCCR, DMA2D_FGPFCCR_START);
/* Write DMA2D BGPFCCR register */
WRITE_REG(DMA2D->BGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));
/* Mark CLUT loaded */
L8ClutLoaded = 1;
/* Wait for load to finish */
while ((READ_REG(DMA2D->FGPFCCR) & DMA2D_FGPFCCR_START) != 0U);
/* Clear CLUT Transfer Complete flag */
DMA2D->IFCR = (DMA2D_FLAG_CTC);
}
else
{
/* Set correct alpha for these pixels */
MODIFY_REG(DMA2D->FGPFCCR, DMA2D_BGPFCCR_ALPHA_Msk, alpha << DMA2D_FGPFCCR_ALPHA_Pos);
}
/* Start pixel transfer in blending mode */
WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_CR_START);
}
} // namespace rgb565
} // namespace paint
} // namespace touchgfx
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,164 @@
/**
******************************************************************************
* File Name : STM32DMA.hpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.26.0. Please, do not edit!
******************************************************************************
* @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.
*
******************************************************************************
*/
#ifndef STM32DMA_HPP
#define STM32DMA_HPP
#include <touchgfx/Bitmap.hpp>
#include <touchgfx/hal/DMA.hpp>
/**
* @class STM32DMA
*
* @brief This class specializes DMA_Interface for the STM32 processors.
*
* @sa touchgfx::DMA_Interface
*/
class STM32DMA : public touchgfx::DMA_Interface
{
/**
* @typedef touchgfx::DMA_Interface Base
*
* @brief Defines an alias representing the base.
*
Defines an alias representing the base.
*/
typedef touchgfx::DMA_Interface Base;
public:
/**
* @fn STM32DMA::STM32DMA();
*
* @brief Default constructor.
*
* Default constructor.
*/
STM32DMA();
/**
* @fn STM32DMA::~STM32DMA();
*
* @brief Destructor.
*
* Destructor.
*/
virtual ~STM32DMA();
/**
* @fn DMAType touchgfx::STM32DMA::getDMAType()
*
* @brief Function for obtaining the DMA type of the concrete DMA_Interface implementation.
*
* Function for obtaining the DMA type of the concrete DMA_Interface implementation.
* As default, will return DMA_TYPE_CHROMART type value.
*
* @return a DMAType value of the concrete DMA_Interface implementation.
*/
virtual touchgfx::DMAType getDMAType(void)
{
return touchgfx::DMA_TYPE_CHROMART;
}
/**
* @fn touchgfx::BlitOperations STM32DMA::getBlitCaps();
*
* @brief Gets the blit capabilities.
*
* Gets the blit capabilities.
*
* This DMA supports a range of blit caps: BLIT_OP_COPY, BLIT_OP_COPY_ARGB8888,
* BLIT_OP_COPY_ARGB8888_WITH_ALPHA, BLIT_OP_COPY_A4, BLIT_OP_COPY_A8.
*
*
* @return Currently supported blitcaps.
*/
virtual touchgfx::BlitOperations getBlitCaps();
/**
* @fn void STM32DMA::initialize();
*
* @brief Perform hardware specific initialization.
*
* Perform hardware specific initialization.
*/
virtual void initialize();
/**
* @fn void STM32DMA::signalDMAInterrupt()
*
* @brief Raises a DMA interrupt signal.
*
* Raises a DMA interrupt signal.
*/
virtual void signalDMAInterrupt()
{
executeCompleted();
}
protected:
/**
* @fn virtual void STM32DMA::setupDataCopy(const touchgfx::BlitOp& blitOp);
*
* @brief Configures the DMA for copying data to the frame buffer.
*
* Configures the DMA for copying data to the frame buffer.
*
* @param blitOp Details on the copy to perform.
*/
virtual void setupDataCopy(const touchgfx::BlitOp& blitOp);
/**
* @fn virtual void STM32DMA::setupDataFill(const touchgfx::BlitOp& blitOp);
*
* @brief Configures the DMA for "filling" the frame-buffer with a single color.
*
* Configures the DMA for "filling" the frame-buffer with a single color.
*
* @param blitOp Details on the "fill" to perform.
*/
virtual void setupDataFill(const touchgfx::BlitOp& blitOp);
private:
touchgfx::LockFreeDMA_Queue dma_queue;
touchgfx::BlitOp queue_storage[96];
/**
* @fn void STM32DMA::getChromARTInputFormat()
*
* @brief Convert Bitmap format to ChromART Input format.
*
* @param format Bitmap format.
*
* @return ChromART Input format.
*/
inline uint32_t getChromARTInputFormat(touchgfx::Bitmap::BitmapFormat format);
/**
* @fn void STM32DMA::getChromARTOutputFormat()
*
* @brief Convert Bitmap format to ChromART Output format.
*
* @param format Bitmap format.
*
* @return ChromART Output format.
*/
inline uint32_t getChromARTOutputFormat(touchgfx::Bitmap::BitmapFormat format);
};
#endif // STM32DMA_HPP
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,579 @@
/**
******************************************************************************
* File Name : SoftwareMJPEGDecoder.cpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.26.0. Please, do not edit!
******************************************************************************
* @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.
*
******************************************************************************
*/
#include <jinclude.h>
#include <jpeglib.h>
#include <string.h>
#include <SoftwareMJPEGDecoder.hpp>
#define RGB565 0
#define RGB888 1
#define ARGB8888 2
#define VIDEO_DECODE_FORMAT RGB565
namespace
{
struct JPEG_RGB
{
uint8_t B;
uint8_t G;
uint8_t R;
};
} // namespace
SoftwareMJPEGDecoder::SoftwareMJPEGDecoder(uint8_t* buffer)
: frameNumber(0), currentMovieOffset(0), indexOffset(0), firstFrameOffset(0), lastFrameEnd(0), movieLength(0), movieData(0),
reader(0), lineBuffer(buffer), aviBuffer(0), aviBufferLength(0), aviBufferStartOffset(0), lastError(AVI_NO_ERROR)
{
// Clear video info
videoInfo.frame_height = 0;
videoInfo.frame_width = 0;
videoInfo.ms_between_frames = 0;
videoInfo.number_of_frames = 0;
}
int SoftwareMJPEGDecoder::compare(const uint32_t offset, const char* str, uint32_t num)
{
const char* src;
if (reader != 0)
{
// Assuming data is in buffer!
src = reinterpret_cast<const char*>(aviBuffer + (offset - aviBufferStartOffset));
}
else
{
src = (const char*)movieData + offset;
}
return strncmp(src, str, num);
}
inline uint32_t SoftwareMJPEGDecoder::getU32(const uint32_t offset)
{
if (reader != 0)
{
// Assuming data is in buffer!
const uint32_t index = offset - aviBufferStartOffset;
return aviBuffer[index + 0] | (aviBuffer[index + 1] << 8) | (aviBuffer[index + 2] << 16) | (aviBuffer[index + 3] << 24);
}
else
{
const uint8_t* const d = movieData + offset;
return d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
}
}
inline uint32_t SoftwareMJPEGDecoder::getU16(const uint32_t offset)
{
if (reader != 0)
{
// Assuming data is in buffer!
const uint32_t index = offset - aviBufferStartOffset;
return aviBuffer[index + 0] | (aviBuffer[index + 1] << 8);
}
else
{
const uint8_t* const d = movieData + offset;
return d[0] | (d[1] << 8);
}
}
const uint8_t* SoftwareMJPEGDecoder::readData(uint32_t offset, uint32_t length)
{
if (reader != 0)
{
if (length > aviBufferLength)
{
lastError = AVI_ERROR_FILE_BUFFER_TO_SMALL;
assert(!"Buffer to small");
}
reader->seek(offset);
if (!reader->readData(aviBuffer, length))
{
lastError = AVI_ERROR_EOF_REACHED;
}
aviBufferStartOffset = offset;
return aviBuffer;
}
return movieData + offset;
}
bool SoftwareMJPEGDecoder::decodeNextFrame(uint8_t* buffer, uint16_t buffer_width, uint16_t buffer_height, uint32_t buffer_stride)
{
assert((frameNumber > 0) && "SoftwareMJPEGDecoder decoding without frame data!");
//find next frame and decode it
readData(currentMovieOffset, 8);
uint32_t streamNo = getU16(currentMovieOffset);
uint32_t chunkType = getU16(currentMovieOffset + 2);
uint32_t chunkSize = getU32(currentMovieOffset + 4);
const uint16_t STREAM0 = 0x3030;
const uint16_t TYPEDC = 0x6364;
bool isCurrentFrameLast;
//play frame if we have it all
if (currentMovieOffset + 8 + chunkSize < movieLength)
{
if (streamNo == STREAM0 && chunkType == TYPEDC && chunkSize > 0)
{
currentMovieOffset += 8;
//decode frame
const uint8_t* chunk = readData(currentMovieOffset, chunkSize);
decodeMJPEGFrame(chunk, chunkSize, buffer, buffer_width, buffer_height, buffer_stride);
frameNumber++;
}
isCurrentFrameLast = false;
// Advance to next frame
currentMovieOffset += chunkSize;
if (chunkSize == 0) // Empty frame - Skip
{
currentMovieOffset += 8;
}
currentMovieOffset = (currentMovieOffset + 1) & 0xFFFFFFFE; //pad to next word
if (currentMovieOffset == lastFrameEnd)
{
frameNumber = 1;
currentMovieOffset = firstFrameOffset; //start over
isCurrentFrameLast = true;
}
}
else
{
frameNumber = 1;
currentMovieOffset = firstFrameOffset; //start over
isCurrentFrameLast = true;
}
return !isCurrentFrameLast;
}
bool SoftwareMJPEGDecoder::gotoNextFrame()
{
assert((frameNumber > 0) && "SoftwareMJPEGDecoder decoding without frame data!");
readData(currentMovieOffset, 8);
uint32_t chunkSize = getU32(currentMovieOffset + 4);
//increment until next video frame
while (currentMovieOffset + 8 + chunkSize < movieLength)
{
//increment one frame
currentMovieOffset += chunkSize + 8;
currentMovieOffset = (currentMovieOffset + 1) & 0xFFFFFFFE; //pad to next word
frameNumber++;
//next chunk
readData(currentMovieOffset, 8);
//check it is a video frame
uint32_t streamNo = getU16(currentMovieOffset);
uint32_t chunkType = getU16(currentMovieOffset + 2);
chunkSize = getU32(currentMovieOffset + 4);
const uint16_t STREAM0 = 0x3030;
const uint16_t TYPEDC = 0x6364;
if (streamNo == STREAM0 && chunkType == TYPEDC && chunkSize > 0)
{
// Found next frame
return true;
}
}
//skip back to first frame
frameNumber = 1;
currentMovieOffset = firstFrameOffset; //start over
return false;
}
void SoftwareMJPEGDecoder::setVideoData(const uint8_t* movie, const uint32_t length)
{
movieData = movie;
movieLength = length;
reader = 0; //not using reader
readVideoHeader();
}
void SoftwareMJPEGDecoder::setVideoData(touchgfx::VideoDataReader& reader)
{
this->reader = &reader;
movieData = 0;
movieLength = reader.getDataLength();
readVideoHeader();
}
bool SoftwareMJPEGDecoder::hasVideo()
{
return (reader != 0) || (movieData != 0);
}
void SoftwareMJPEGDecoder::readVideoHeader()
{
// Start from the start
currentMovieOffset = 0;
lastError = AVI_NO_ERROR;
// Make header available in buffer
readData(0, 72);
// Decode the movie header to find first frame
// Must be RIFF file
if (compare(currentMovieOffset, "RIFF", 4))
{
lastError = AVI_ERROR_NOT_RIFF;
assert(!"RIFF header not found");
}
//skip fourcc and length
currentMovieOffset += 8;
if (compare(currentMovieOffset, "AVI ", 4))
{
lastError = AVI_ERROR_AVI_HEADER_NOT_FOUND;
assert(!"AVI header not found");
}
currentMovieOffset += 4;
if (compare(currentMovieOffset, "LIST", 4))
{
lastError = AVI_ERROR_AVI_LIST_NOT_FOUND;
assert(!"AVI LIST not found");
}
//save AVI List info
const uint32_t aviListSize = getU32(currentMovieOffset + 4);
const uint32_t aviListOffset = currentMovieOffset;
assert(aviListSize);
//look into header to find frame rate
bool foundFrame = true;
uint32_t offset = currentMovieOffset + 8;
if (compare(offset, "hdrl", 4))
{
lastError = AVI_ERROR_AVI_HDRL_NOT_FOUND;
foundFrame = false;
}
offset += 4;
if (compare(offset, "avih", 4))
{
lastError = AVI_ERROR_AVI_AVIH_NOT_FOUND;
foundFrame = false;
}
if (foundFrame)
{
offset += 8; //skip fourcc and cb in AVIMAINHEADER
videoInfo.ms_between_frames = getU32(offset) / 1000;
videoInfo.number_of_frames = getU32(offset + 16);
videoInfo.frame_width = getU32(offset + 32);
videoInfo.frame_height = getU32(offset + 36);
}
//skip rest of AVI header, start from end of AVI List
//look for list with 'movi' header
uint32_t listOffset = aviListOffset + aviListSize + 8;
readData(listOffset, 12);
while (compare(listOffset + 8, "movi", 4) && (lastError == AVI_NO_ERROR) && listOffset < movieLength)
{
const uint32_t listSize = getU32(listOffset + 4) + 8;
listOffset += listSize;
readData(listOffset, 12);
}
if (lastError != AVI_NO_ERROR)
{
lastError = AVI_ERROR_MOVI_NOT_FOUND;
return;
}
//save first frame and end of last frame
currentMovieOffset = listOffset + 8 + 4; //skip LIST and 'movi'
lastFrameEnd = listOffset + 8 + getU32(listOffset + 4);
//find idx
const uint32_t listSize = getU32(listOffset + 4) + 8;
listOffset += listSize;
readData(listOffset, 4);
if (!compare(listOffset, "idx1", 4))
{
indexOffset = listOffset;
}
else
{
lastError = AVI_ERROR_IDX1_NOT_FOUND;
return;
}
//start on first frame
frameNumber = 1; //next frame number is 1
firstFrameOffset = currentMovieOffset;
}
#if VIDEO_DECODE_FORMAT == RGB565 || VIDEO_DECODE_FORMAT == RGB888 || VIDEO_DECODE_FORMAT == ARGB8888
void SoftwareMJPEGDecoder::decodeMJPEGFrame(const uint8_t* const mjpgdata, const uint32_t length, uint8_t* outputBuffer, uint16_t bufferWidth, uint16_t bufferHeight, uint32_t bufferStride)
{
if (length == 0)
{
return;
}
if (outputBuffer && lineBuffer) //only decode if buffers are assigned.
{
/* This struct contains the JPEG decompression parameters */
struct jpeg_decompress_struct cinfo;
/* This struct represents a JPEG error handler */
struct jpeg_error_mgr jerr;
JSAMPROW lines[2] = { lineBuffer, 0 }; /* Output row buffer */
/* Step 1: allocate and initialize JPEG decompression object */
cinfo.err = jpeg_std_error(&jerr);
/* Initialize the JPEG decompression object */
jpeg_create_decompress(&cinfo);
//jpeg_stdio_src (&cinfo, file);
jpeg_mem_src(&cinfo, const_cast<uint8_t*>(mjpgdata), length);
/* Step 3: read image parameters with jpeg_read_header() */
jpeg_read_header(&cinfo, TRUE);
/* Step 4: set parameters for decompression */
cinfo.dct_method = JDCT_FLOAT;
/* Step 5: start decompressor */
jpeg_start_decompress(&cinfo);
//restrict to minimum of movie and output buffer size
const uint32_t width = MIN(bufferWidth, cinfo.image_width);
const uint32_t height = MIN(bufferHeight, cinfo.output_height);
#if VIDEO_DECODE_FORMAT == RGB565
uint16_t* lineptr = reinterpret_cast<uint16_t*>(outputBuffer);
#elif VIDEO_DECODE_FORMAT == RGB888
uint8_t* lineptr = outputBuffer;
#else
uint32_t* lineptr = reinterpret_cast<uint32_t*>(outputBuffer);
#endif
while (cinfo.output_scanline < height)
{
(void)jpeg_read_scanlines(&cinfo, lines, 1);
#if VIDEO_DECODE_FORMAT == RGB565
JPEG_RGB* RGB_matrix = (JPEG_RGB*)lineBuffer;
JPEG_RGB* const RGB_end = RGB_matrix + width;
while (RGB_matrix < RGB_end)
{
const uint16_t pix = ((RGB_matrix->R & 0xF8) << 8) | ((RGB_matrix->G & 0xFC) << 3) | ((RGB_matrix->B & 0xF8) >> 3);
*lineptr++ = pix;
RGB_matrix++;
}
lineptr += bufferWidth - width; //move to next line
#elif VIDEO_DECODE_FORMAT == RGB888
memcpy(lineptr, lineBuffer, width * 3);
lineptr += bufferStride; //move to next line
#else
JPEG_RGB* RGB_matrix = (JPEG_RGB*)lineBuffer;
JPEG_RGB* const RGB_end = RGB_matrix + width;
while (RGB_matrix < RGB_end)
{
const uint32_t pix = (0xFF << 24) | (RGB_matrix->R << 16) | (RGB_matrix->G << 8) | (RGB_matrix->B);
*lineptr++ = pix;
RGB_matrix++;
}
lineptr += bufferWidth - width; //move to next line
#endif
}
#ifdef SIMULATOR
cinfo.output_scanline = cinfo.output_height;
#endif
/* Step 6: Finish decompression */
jpeg_finish_decompress(&cinfo);
/* Step 7: Release JPEG decompression object */
jpeg_destroy_decompress(&cinfo);
}
}
bool SoftwareMJPEGDecoder::decodeFrame(const touchgfx::Rect& area, uint8_t* frameBuffer, uint32_t framebuffer_width)
{
// Assuming that chunk is available and streamNo and chunkType is correct.
// Check by gotoNextFrame
readData(currentMovieOffset, 8);
const uint32_t length = getU32(currentMovieOffset + 4);
// Ensure whole frame is read
const uint8_t* mjpgdata = readData(currentMovieOffset + 8, length);
assert(lineBuffer && "LineBuffer must be assigned prior to decoding directly to framebuffer");
/* This struct contains the JPEG decompression parameters */
struct jpeg_decompress_struct cinfo;
/* This struct represents a JPEG error handler */
struct jpeg_error_mgr jerr;
JSAMPROW lines[2] = { lineBuffer, 0 }; /* Output row buffer */
/* Step 1: allocate and initialize JPEG decompression object */
cinfo.err = jpeg_std_error(&jerr);
/* Initialize the JPEG decompression object */
jpeg_create_decompress(&cinfo);
//jpeg_stdio_src (&cinfo, file);
jpeg_mem_src(&cinfo, const_cast<uint8_t*>(mjpgdata), length);
/* Step 3: read image parameters with jpeg_read_header() */
jpeg_read_header(&cinfo, TRUE);
/* Step 4: set parameters for decompression */
cinfo.dct_method = JDCT_FLOAT;
/* Step 5: start decompressor */
jpeg_start_decompress(&cinfo);
//restrict to minimum of movie and output buffer size
const uint32_t startY = area.y;
//scan down to startY
while (cinfo.output_scanline < startY)
{
(void)jpeg_read_scanlines(&cinfo, lines, 1);
}
const uint32_t startX = area.x;
const uint32_t endX = MIN((uint32_t)area.right(), cinfo.image_width);
#if VIDEO_DECODE_FORMAT == RGB565
uint16_t* lineptr = reinterpret_cast<uint16_t*>(frameBuffer);
lineptr += framebuffer_width * startY;
#elif VIDEO_DECODE_FORMAT == RGB888
uint8_t* lineptr = frameBuffer;
lineptr += framebuffer_width * 3 * startY;
#else
uint32_t* lineptr = reinterpret_cast<uint32_t*>(frameBuffer);
lineptr += framebuffer_width * startY;
#endif
const uint32_t endY = MIN((uint32_t)area.bottom(), cinfo.output_height);
//scan relevant part
while (cinfo.output_scanline < endY)
{
(void)jpeg_read_scanlines(&cinfo, lines, 1);
#if VIDEO_DECODE_FORMAT == RGB565
JPEG_RGB* RGB_matrix = (JPEG_RGB*)lineBuffer;
//loop row RGB888->RGB565 for required line part
for (uint32_t counter = startX; counter < endX; counter++)
{
const uint16_t pix = ((RGB_matrix[counter].R & 0xF8) << 8) | ((RGB_matrix[counter].G & 0xFC) << 3) | ((RGB_matrix[counter].B & 0xF8) >> 3);
*(lineptr + counter) = pix;
}
lineptr += framebuffer_width; //move to next line
#elif VIDEO_DECODE_FORMAT == RGB888
memcpy(lineptr + startX * 3, lineBuffer + startX * 3, (endX - startX) * 3);
lineptr += framebuffer_width * 3; //move to next line
#else
JPEG_RGB* RGB_matrix = (JPEG_RGB*)lineBuffer;
//loop row RGB888->ARGB8888 for required line part
for (uint32_t counter = startX; counter < endX; counter++)
{
const uint32_t pix = (0xFF << 24) | (RGB_matrix[counter].R << 16) | (RGB_matrix[counter].G << 8) | RGB_matrix[counter].B;
*(lineptr + counter) = pix;
}
lineptr += framebuffer_width; //move to next line
#endif
}
#ifdef SIMULATOR
cinfo.output_scanline = cinfo.output_height;
#endif
/* Step 6: Finish decompression */
jpeg_finish_decompress(&cinfo);
/* Step 7: Release JPEG decompression object */
jpeg_destroy_decompress(&cinfo);
return true;
}
#else
void SoftwareMJPEGDecoder::decodeMJPEGFrame(const uint8_t* const, const uint32_t, uint8_t*, uint16_t, uint16_t, uint32_t)
{
}
bool SoftwareMJPEGDecoder::decodeFrame(const touchgfx::Rect&, uint8_t*, uint32_t)
{
return true;
}
#endif // VIDEO_DECODE_FORMAT == RGB565 || VIDEO_DECODE_FORMAT == RGB888 || VIDEO_DECODE_FORMAT == ARGB888
bool SoftwareMJPEGDecoder::decodeThumbnail(uint32_t frameno, uint8_t* buffer, uint16_t width, uint16_t height)
{
assert(0);
return false;
}
void SoftwareMJPEGDecoder::gotoFrame(uint32_t frameNumber)
{
if (frameNumber == 0)
{
frameNumber = 1;
}
if (frameNumber > getNumberOfFrames())
{
frameNumber = getNumberOfFrames();
}
uint32_t offset = indexOffset + 8 + (frameNumber - 1) * 16;
readData(offset, 16);
currentMovieOffset = getU32(offset + 8) + firstFrameOffset - 4;
this->frameNumber = frameNumber;
}
uint32_t SoftwareMJPEGDecoder::getNumberOfFrames()
{
return videoInfo.number_of_frames;
}
void SoftwareMJPEGDecoder::getVideoInfo(touchgfx::VideoInformation* data)
{
*data = videoInfo;
// For unsupported decode formats, set video dimension to 0x0, to avoid drawing anything
#if VIDEO_DECODE_FORMAT == RGB565 || VIDEO_DECODE_FORMAT == RGB888 || VIDEO_DECODE_FORMAT == ARGB8888
#else
data->frame_width = 0;
data->frame_height = 0;
#endif
}
//#ifndef SIMULATOR
//link libjpeg file operation to fileinput namespace
extern "C" {
size_t jpeg_read_file(FILE* file, uint8_t* buf, uint32_t sizeofbuf)
{
assert(!"jpeg_read_file called with no implementation");
return 0;
}
}
//#endif

View File

@@ -0,0 +1,86 @@
/**
******************************************************************************
* File Name : SoftwareMJPEGDecoder.hpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.26.0. Please, do not edit!
******************************************************************************
* @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.
*
******************************************************************************
*/
#ifndef TOUCHGFX_SOFTWAREMJPEGDECODER_HPP
#define TOUCHGFX_SOFTWAREMJPEGDECODER_HPP
#include <MJPEGDecoder.hpp>
class SoftwareMJPEGDecoder : public MJPEGDecoder
{
public:
SoftwareMJPEGDecoder(uint8_t* linebuffer);
virtual void setVideoData(const uint8_t* movie, const uint32_t length);
virtual void setVideoData(touchgfx::VideoDataReader& reader);
virtual bool hasVideo();
virtual bool decodeNextFrame(uint8_t* frameBuffer, uint16_t width, uint16_t height, uint32_t framebuffer_width);
virtual bool gotoNextFrame();
virtual bool decodeFrame(const touchgfx::Rect& area, uint8_t* frameBuffer, uint32_t framebuffer_width);
virtual bool decodeThumbnail(uint32_t frameno, uint8_t* buffer, uint16_t width, uint16_t height);
virtual void gotoFrame(uint32_t frameno);
virtual uint32_t getCurrentFrameNumber() const
{
return frameNumber;
}
virtual uint32_t getNumberOfFrames();
virtual void getVideoInfo(touchgfx::VideoInformation* data);
void setAVIFileBuffer(uint8_t* buffer, uint32_t size)
{
aviBuffer = buffer, aviBufferLength = size;
}
virtual AVIErrors getLastError()
{
return lastError;
}
private:
void readVideoHeader();
void decodeMJPEGFrame(const uint8_t* const mjpgdata, const uint32_t length, uint8_t* buffer, uint16_t width, uint16_t height, uint32_t stride);
int compare(const uint32_t offset, const char* str, uint32_t num);
uint32_t getU32(const uint32_t offset);
uint32_t getU16(const uint32_t offset);
const uint8_t* readData(uint32_t offset, uint32_t length);
touchgfx::VideoInformation videoInfo;
uint32_t frameNumber;
uint32_t currentMovieOffset;
uint32_t indexOffset;
uint32_t firstFrameOffset;
uint32_t lastFrameEnd;
uint32_t movieLength;
const uint8_t* movieData;
touchgfx::VideoDataReader* reader;
uint8_t* lineBuffer;
uint8_t* aviBuffer;
uint32_t aviBufferLength;
uint32_t aviBufferStartOffset;
AVIErrors lastError;
};
#endif // TOUCHGFX_SOFTWAREMJPEGDECODER_HPP

View File

@@ -0,0 +1,80 @@
/**
******************************************************************************
* File Name : TouchGFXConfiguration.cpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.26.0. Please, do not edit!
******************************************************************************
* @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.
*
******************************************************************************
*/
#include <texts/TypedTextDatabase.hpp>
#include <fonts/ApplicationFontProvider.hpp>
#include <gui/common/FrontendHeap.hpp>
#include <BitmapDatabase.hpp>
#include <touchgfx/VectorFontRendererImpl.hpp>
#include <platform/driver/lcd/LCD16bpp.hpp>
#include <STM32DMA.hpp>
#include <TouchGFXHAL.hpp>
#include <STM32TouchController.hpp>
#include <stm32f7xx_hal.h>
extern "C" void touchgfx_init();
extern "C" void touchgfx_taskEntry();
extern "C" void touchgfx_components_init();
static STM32TouchController tc;
static STM32DMA dma;
static LCD16bpp display;
static VectorFontRendererImpl vectorFontRenderer;
static ApplicationFontProvider fontProvider;
static Texts texts;
static TouchGFXHAL hal(dma, display, tc, 480, 272);
void touchgfx_init()
{
Bitmap::registerBitmapDatabase(BitmapDatabase::getInstance(), BitmapDatabase::getInstanceSize());
TypedText::registerTexts(&texts);
Texts::setLanguage(0);
display.setVectorFontRenderer(&vectorFontRenderer);
FontManager::setFontProvider(&fontProvider);
FrontendHeap& heap = FrontendHeap::getInstance();
/*
* we need to obtain the reference above to initialize the frontend heap.
*/
(void)heap;
/*
* Initialize TouchGFX
*/
hal.initialize();
}
void touchgfx_components_init()
{
}
void touchgfx_taskEntry()
{
/*
* Main event loop. Will wait for VSYNC signal, and then process next frame. Call
* this function from your GUI task.
*
* Note This function never returns
*/
hal.taskEntry();
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,211 @@
/**
******************************************************************************
* File Name : TouchGFXGeneratedHAL.cpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.26.0. Please, do not edit!
******************************************************************************
* @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.
*
******************************************************************************
*/
#include <TouchGFXGeneratedHAL.hpp>
#include <touchgfx/hal/OSWrappers.hpp>
#include <gui/common/FrontendHeap.hpp>
#include <touchgfx/hal/GPIO.hpp>
#include <touchgfx/widgets/canvas/CWRVectorRenderer.hpp>
#include <DoubleBufferedVideoController.hpp>
#include <SoftwareMJPEGDecoder.hpp>
uint32_t lineBuffer[480];
SoftwareMJPEGDecoder mjpegdecoder1((uint8_t*)lineBuffer);
namespace
{
LOCATION_PRAGMA_NOLOAD("Video_RGB_Buffer")
uint32_t videoRGBBuffer[130560] LOCATION_ATTRIBUTE_NOLOAD("Video_RGB_Buffer");
DoubleBufferedVideoController<1, 480, 272, 480 * 2U, Bitmap::RGB565> videoController;
}
//Singleton Factory
VideoController& VideoController::getInstance()
{
return videoController;
}
namespace touchgfx
{
VectorRenderer* VectorRenderer::getInstance()
{
static CWRVectorRendererRGB565 renderer;
return &renderer;
}
} // namespace touchgfx
#include "stm32f7xx.h"
#include "stm32f7xx_hal_ltdc.h"
using namespace touchgfx;
namespace
{
// Use the section "TouchGFX_Framebuffer" in the linker script to specify the placement of the buffer
LOCATION_PRAGMA_NOLOAD("TouchGFX_Framebuffer")
uint32_t frameBuf[(480 * 272 * 2 + 3) / 4 * 2] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Framebuffer");
static uint16_t lcd_int_active_line;
static uint16_t lcd_int_porch_line;
}
void TouchGFXGeneratedHAL::initialize()
{
HAL::initialize();
registerEventListener(*(Application::getInstance()));
setFrameBufferStartAddresses((void*)frameBuf, (void*)(frameBuf + sizeof(frameBuf) / (sizeof(uint32_t) * 2)), (void*)0);
/*
* Add software decoder to video controller
*/
videoController.addDecoder(mjpegdecoder1, 0);
videoController.setRGBBuffer((uint8_t*)videoRGBBuffer, sizeof(videoRGBBuffer));
}
void TouchGFXGeneratedHAL::configureInterrupts()
{
NVIC_SetPriority(DMA2D_IRQn, 9);
NVIC_SetPriority(LTDC_IRQn, 9);
}
void TouchGFXGeneratedHAL::enableInterrupts()
{
NVIC_EnableIRQ(DMA2D_IRQn);
NVIC_EnableIRQ(LTDC_IRQn);
}
void TouchGFXGeneratedHAL::disableInterrupts()
{
NVIC_DisableIRQ(DMA2D_IRQn);
NVIC_DisableIRQ(LTDC_IRQn);
}
void TouchGFXGeneratedHAL::enableLCDControllerInterrupt()
{
lcd_int_active_line = (LTDC->BPCR & LTDC_BPCR_AVBP_Msk) - 1;
lcd_int_porch_line = (LTDC->AWCR & LTDC_AWCR_AAH_Msk) - 1;
/* Sets the Line Interrupt position */
LTDC->LIPCR = lcd_int_active_line;
/* Line Interrupt Enable */
LTDC->IER |= LTDC_IER_LIE;
}
bool TouchGFXGeneratedHAL::beginFrame()
{
return HAL::beginFrame();
}
void TouchGFXGeneratedHAL::endFrame()
{
HAL::endFrame();
videoController.endFrame();
}
uint16_t* TouchGFXGeneratedHAL::getTFTFrameBuffer() const
{
return (uint16_t*)LTDC_Layer1->CFBAR;
}
void TouchGFXGeneratedHAL::setTFTFrameBuffer(uint16_t* adr)
{
LTDC_Layer1->CFBAR = (uint32_t)adr;
/* Reload immediate */
LTDC->SRCR = (uint32_t)LTDC_SRCR_IMR;
}
void TouchGFXGeneratedHAL::flushFrameBuffer(const touchgfx::Rect& rect)
{
HAL::flushFrameBuffer(rect);
}
bool TouchGFXGeneratedHAL::blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes)
{
return HAL::blockCopy(dest, src, numBytes);
}
void TouchGFXGeneratedHAL::InvalidateCache()
{
// Because DMA2D access main memory directly, the DCache must be invalidated
// becuase it could hold a wrong image of the framebuffer. That's done
// using the function SCB_CleanInvalidateDCache(). Remember to enable
// "CPU Cache" in the "System Core" settings for "Cortex M7" in CubeMX
// in order for this function call to work.
if (SCB->CCR & SCB_CCR_DC_Msk)
{
SCB_CleanInvalidateDCache();
}
}
void TouchGFXGeneratedHAL::FlushCache()
{
// If the framebuffer is placed in Write-Back cached memory (e.g. SRAM) then
// the DCache must be flushed prior to DMA2D accessing it. That's done
// using the function SCB_CleanInvalidateDCache(). Remember to enable
// "CPU Cache" in the "System Core" settings for "Cortex M7" in CubeMX in
// order for this function call to work.
if (SCB->CCR & SCB_CCR_DC_Msk)
{
SCB_CleanInvalidateDCache();
}
}
extern "C" void videoTaskFunc(void* argument)
{
videoController.decoderTaskEntry();
}
extern "C"
{
void HAL_LTDC_LineEventCallback(LTDC_HandleTypeDef* hltdc)
{
if (!HAL::getInstance())
{
return;
}
if (LTDC->LIPCR == lcd_int_active_line)
{
//entering active area
HAL_LTDC_ProgramLineEvent(hltdc, lcd_int_porch_line);
HAL::getInstance()->vSync();
OSWrappers::signalVSync();
// Swap frame buffers immediately instead of waiting for the task to be scheduled in.
// Note: task will also swap when it wakes up, but that operation is guarded and will not have
// any effect if already swapped.
HAL::getInstance()->swapFrameBuffers();
GPIO::set(GPIO::VSYNC_FREQ);
}
else
{
//exiting active area
HAL_LTDC_ProgramLineEvent(hltdc, lcd_int_active_line);
// Signal to the framework that display update has finished.
HAL::getInstance()->frontPorchEntered();
GPIO::clear(GPIO::VSYNC_FREQ);
}
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -0,0 +1,188 @@
/**
******************************************************************************
* File Name : TouchGFXGeneratedHAL.hpp
******************************************************************************
* This file is generated by TouchGFX Generator 4.26.0. Please, do not edit!
******************************************************************************
* @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.
*
******************************************************************************
*/
#ifndef TouchGFXGeneratedHAL_HPP
#define TouchGFXGeneratedHAL_HPP
#include <touchgfx/hal/HAL.hpp>
/**
* @class TouchGFXGeneratedHAL
*
* @brief HAL implementation for TouchGFXGenerated.
*
* @sa HAL
*/
class TouchGFXGeneratedHAL : public touchgfx::HAL
{
public:
/**
* @fn TouchGFXGeneratedHAL::TouchGFXGeneratedHAL(touchgfx::DMA_Interface& dma, touchgfx::LCD& display, touchgfx::TouchController& tc, uint16_t width, uint16_t height) : touchgfx::HAL(dma, display, tc, width, height)
*
* @brief Constructor.
*
* Constructor. Initializes members.
*
* @param [in,out] dma Reference to DMA interface.
* @param [in,out] display Reference to LCD interface.
* @param [in,out] tc Reference to Touch Controller driver.
* @param width Width of the display.
* @param height Height of the display.
*/
TouchGFXGeneratedHAL(touchgfx::DMA_Interface& dma, touchgfx::LCD& display, touchgfx::TouchController& tc, uint16_t width, uint16_t height) :
touchgfx::HAL(dma, display, tc, width, height)
{
}
/**
* @fn void TouchGFXGeneratedHAL::initialize();
*
* @brief This function is responsible for initializing the entire framework.
*
* This function is responsible for initializing the entire framework.
*/
virtual void initialize();
/**
* @fn virtual void TouchGFXGeneratedHAL::configureInterrupts();
*
* @brief Sets the DMA, LCD, and GPU2D (if enabled) interrupt priorities.
*
* Sets the DMA, LCD, and GPU2D (if enabled) interrupt priorities.
*/
virtual void configureInterrupts();
/**
* @fn virtual void TouchGFXGeneratedHAL::enableInterrupts();
*
* @brief Enables the DMA, LCD, and GPU2D (if enabled) interrupts.
*
* Enables the DMA, LCD, and GPU2D (if enabled) interrupts.
*/
virtual void enableInterrupts();
/**
* @fn virtual void TouchGFXGeneratedHAL::disableInterrupts();
*
* @brief Disables the DMA, LDC, and GPU2D (if enabled) interrupts.
*
* Disables the DMA, LDC, and GPU2D (if enabled) interrupts.
*/
virtual void disableInterrupts();
/**
* @fn virtual void TouchGFXGeneratedHAL::enableLCDControllerInterrupt();
*
* @brief Configure the LCD controller to fire interrupts at VSYNC.
*
* Configure the LCD controller to fire interrupts at VSYNC. Called automatically
* once TouchGFX initialization has completed.
*/
virtual void enableLCDControllerInterrupt();
/**
* @fn virtual void TouchGFXGeneratedHAL::flushFrameBuffer();
*
* @brief This function is called whenever the framework has performed a complete draw.
*
* This specialization is only in place to keep compilers happy. Base impl. will call the
* Rect version.
* @see HAL::flushFrameBuffer
*/
virtual void flushFrameBuffer()
{
HAL::flushFrameBuffer();
}
/**
* @fn virtual void TouchGFXGeneratedHAL::flushFrameBuffer(const touchgfx::Rect& rect);
*
* @brief This function is called whenever the framework has performed a partial draw.
*
* This function is called whenever the framework has performed a partial draw.
*
* @param rect The area of the screen that has been drawn, expressed in absolute coordinates.
*
* @see flushFrameBuffer().
*/
virtual void flushFrameBuffer(const touchgfx::Rect& rect);
/**
*
* @fn virtual void TouchGFXGeneratedHAL::blockCopy();
*
* This function performs a platform-specific memcpy, if supported by the hardware.
*
* @param [out] dest Pointer to destination memory.
* @param [in] src Pointer to source memory.
* @param numBytes Number of bytes to copy.
*
* @return true if the copy succeeded, false if copy was not performed.
*/
virtual bool blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes);
/**
* @fn virtual void TouchGFXGeneratedHAL::beginFrame();
*
* @brief Called when beginning to rendering a frame.
*
* Called when beginning to rendering a frame.
*
* @return true if rendering can begin, false otherwise.
*/
virtual bool beginFrame();
/**
* @fn virtual void TouchGFXGeneratedHAL::endFrame();
*
* @brief Called when a rendering pass is completed.
*
* Called when a rendering pass is completed.
*/
virtual void endFrame();
protected:
/**
* @fn virtual uint16_t* TouchGFXGeneratedHAL::getTFTFrameBuffer() const;
*
* @brief Gets the frame buffer address used by the TFT controller.
*
* Gets the frame buffer address used by the TFT controller.
*
* @return The address of the frame buffer currently being displayed on the TFT.
*/
virtual uint16_t* getTFTFrameBuffer() const;
/**
* @fn virtual void TouchGFXGeneratedHAL::setTFTFrameBuffer(uint16_t* adr);
*
* @brief Sets the frame buffer address used by the TFT controller.
*
* Sets the frame buffer address used by the TFT controller.
*
* @param [in,out] adr New frame buffer address.
*/
virtual void setTFTFrameBuffer(uint16_t* adr);
virtual void InvalidateCache();
virtual void FlushCache();
};
#endif // TouchGFXGeneratedHAL_HPP
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/