Graphics processing using LTDC and DMA2D example

Dependencies:   mbed BSP_DISCO_F746NG

Files at this revision

API Documentation at this revision

Comitter:
codebreaker7
Date:
Thu Dec 09 13:36:25 2021 +0000
Commit message:
Initial commit for graphics processing project example

Changed in this revision

BSP_DISCO_F746NG.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 0e534ad140f5 BSP_DISCO_F746NG.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BSP_DISCO_F746NG.lib	Thu Dec 09 13:36:25 2021 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/ST/code/BSP_DISCO_F746NG/#fe313c53cdb5
diff -r 000000000000 -r 0e534ad140f5 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Dec 09 13:36:25 2021 +0000
@@ -0,0 +1,277 @@
+/**
+  ******************************************************************************
+  * @file    main.c
+  * @author  Ac6
+  * @version V1.0
+  * @date    01-December-2013
+  * @brief   Default main function.
+  ******************************************************************************
+*/
+
+
+#include "stm32f7xx.h"
+#include "stm32746g_discovery.h"
+#include "stm32746g_discovery_lcd.h"
+#include "stm32746g_discovery_ts.h"
+#include "stm32f7xx_hal_dma2d.h"
+
+#define LCD_INMEM_BUF_ADDR (LCD_FB_START_ADDRESS + (480 * 272) * 4) // address to draw off-screen
+#define BUFFER_WIDTH 272
+#define BUFFER_HEIGHT 240
+#define INMEM_BUF_SIZE (BUFFER_WIDTH * BUFFER_HEIGHT * 4)
+#define CUBE_SIDE_SIZE 15
+#define CUBES_WIDTH 17
+#define CUBES_HEIGHT 15
+
+struct game_state {
+    int cur_car_pos;
+    int obstacle_posx;
+    int obstacle_posy;
+    int scores;
+    int prev_car_pos;
+    int prev_obstacle_posy;
+};
+
+struct game_state gs = {7, 1, 1, 0, 7 ,1};
+
+DMA2D_HandleTypeDef dma2d;
+
+void EXTI15_10_IRQHandler(void) {
+    HAL_GPIO_EXTI_IRQHandler(TS_INT_PIN);
+}
+
+void SystemClock_Config(void)
+{
+  RCC_ClkInitTypeDef RCC_ClkInitStruct;
+  RCC_OscInitTypeDef RCC_OscInitStruct;
+  HAL_StatusTypeDef ret = HAL_OK;
+
+  /* Enable HSE Oscillator and activate PLL with HSE as source */
+  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+  RCC_OscInitStruct.PLL.PLLM = 25;
+  RCC_OscInitStruct.PLL.PLLN = 400;
+  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
+  RCC_OscInitStruct.PLL.PLLQ = 8;
+
+  ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
+  if(ret != HAL_OK)
+  {
+    while(1) { ; }
+  }
+
+  /* Activate the OverDrive to reach the 200 MHz Frequency */
+  ret = HAL_PWREx_EnableOverDrive();
+  if(ret != HAL_OK)
+  {
+    while(1) { ; }
+  }
+
+  /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */
+  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
+  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
+  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
+
+  ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6);
+  if(ret != HAL_OK)
+  {
+    while(1) { ; }
+  }
+  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
+}
+
+void DMA2D_Config(void) {
+    dma2d.Init.ColorMode = DMA2D_ARGB8888;
+    dma2d.Init.Mode = DMA2D_R2M;
+    dma2d.Init.OutputOffset = 0;
+
+    dma2d.Instance = DMA2D;
+
+    dma2d.LayerCfg[1].InputAlpha = 0xff;
+    dma2d.LayerCfg[1].InputOffset = 0;
+    dma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
+    dma2d.LayerCfg[1].InputColorMode = CM_ARGB8888;
+    HAL_DMA2D_Init(&dma2d);
+    HAL_DMA2D_ConfigLayer(&dma2d, 1);
+}
+
+void Init_Field(void) {
+    int i, j;
+    // draw first square in R2M mode
+    HAL_DMA2D_Start(&dma2d, 0xff000000, LCD_INMEM_BUF_ADDR, BUFFER_WIDTH, BUFFER_HEIGHT);
+    while(HAL_DMA2D_PollForTransfer(&dma2d, 1000) != HAL_OK);
+    dma2d.Init.OutputOffset = 272 - CUBE_SIDE_SIZE;
+    HAL_DMA2D_Init(&dma2d);
+    HAL_DMA2D_Start(&dma2d, 0xffffffff, LCD_INMEM_BUF_ADDR, 15, 15);
+    while(HAL_DMA2D_PollForTransfer(&dma2d, 1000) != HAL_OK);
+    // and then just copy this one into necessary position
+    dma2d.Init.Mode = DMA2D_M2M;
+    dma2d.Init.OutputOffset = BUFFER_WIDTH - CUBE_SIDE_SIZE;
+    dma2d.LayerCfg[1].InputOffset = BUFFER_WIDTH - CUBE_SIDE_SIZE;
+    HAL_DMA2D_Init(&dma2d);
+    HAL_DMA2D_ConfigLayer(&dma2d, 1);
+    for (i = 0; i < 15; i++) {
+        for (j = 0; j < 17; j++) {
+            if (i == 0 && j == 0)
+                continue;
+            HAL_DMA2D_Start(&dma2d, LCD_INMEM_BUF_ADDR, LCD_INMEM_BUF_ADDR +
+                                                        (4 * (CUBE_SIDE_SIZE + 1) * j) +
+                                                        (4 * i * (CUBE_SIDE_SIZE + 1) * BUFFER_WIDTH)
+                                                        , 15, 15);
+            while(HAL_DMA2D_PollForTransfer(&dma2d, 1000) != HAL_OK);
+        }
+    }
+}
+
+//void Draw_Car(void) {
+void Draw_Car(uint32_t color, int posx) {
+    int i, j;
+    dma2d.Init.Mode = DMA2D_R2M;
+    dma2d.Init.OutputOffset = BUFFER_WIDTH - CUBE_SIDE_SIZE;
+    HAL_DMA2D_Init(&dma2d);
+    // draw in the 11-15 rows according to current position
+    for (i = 0; i < 4; i++) {
+        for (j = 0; j < 3; j++) {
+            if (i == 0 || i == 2)
+                if (j == 0 || j == 2)
+                    continue;
+            HAL_DMA2D_Start(&dma2d, color, LCD_INMEM_BUF_ADDR +
+                                                //(4 * (gs.cur_car_pos + j) * (CUBE_SIDE_SIZE + 1)) +
+                                                (4 * (posx + j) * (CUBE_SIDE_SIZE + 1)) +
+                                                (4 * (i + 11) * (CUBE_SIDE_SIZE + 1) * BUFFER_WIDTH), 15, 15);
+            while (HAL_DMA2D_PollForTransfer(&dma2d, 1000) != HAL_OK);
+        }
+    }
+}
+
+//void Draw_Obstacle(void) {
+void Draw_Obstacle(uint32_t color, int posy) {
+    int i, j;
+    dma2d.Init.Mode = DMA2D_R2M;
+    dma2d.Init.OutputOffset = BUFFER_WIDTH - CUBE_SIDE_SIZE;
+    HAL_DMA2D_Init(&dma2d);
+    // draw obstacle according to game state
+    for (i = 0; i < 3; i++) {
+        for (j = 0; j < 3; j++) {
+            //if (gs.obstacle_posy + i < 0 || gs.obstacle_posy > 15)
+            if (posy + i < 0 || posy > 15)
+                continue;
+            HAL_DMA2D_Start(&dma2d, color, LCD_INMEM_BUF_ADDR +
+                                                (4 * (gs.obstacle_posx + j) * (CUBE_SIDE_SIZE + 1)) +
+                                                (4 * (posy + i) * (CUBE_SIDE_SIZE + 1) * BUFFER_WIDTH), 15, 15);
+                                                //(4 * (gs.obstacle_posy + i) * (CUBE_SIDE_SIZE + 1) * BUFFER_WIDTH), 15, 15);
+            while(HAL_DMA2D_PollForTransfer(&dma2d, 1000) != HAL_OK);
+        }
+    }
+}
+
+int main(void)
+{
+    int game_counter = 0;
+    uint8_t score_str[4];
+
+    HAL_Init();
+    SystemClock_Config();
+
+    BSP_LCD_Init();
+    BSP_LCD_LayerDefaultInit(1, LCD_FB_START_ADDRESS);
+    BSP_LCD_SelectLayer(1);
+    BSP_LCD_Clear(0xff000000);
+
+    BSP_TS_Init(480, 272);
+    BSP_TS_ITConfig();
+
+    DMA2D_Config();
+    // form the in-buffer game field start state
+    Init_Field();
+    Draw_Car(LCD_COLOR_GREEN, gs.cur_car_pos);
+    Draw_Obstacle(LCD_COLOR_BLUE, gs.obstacle_posy);
+    dma2d.Init.Mode = DMA2D_M2M;
+    dma2d.Init.OutputOffset = 480 - 272;
+    dma2d.LayerCfg[1].InputOffset = 0;
+    HAL_DMA2D_Init(&dma2d);
+    HAL_DMA2D_ConfigLayer(&dma2d, 1);
+    HAL_DMA2D_Start(&dma2d, LCD_INMEM_BUF_ADDR, LCD_FB_START_ADDRESS, BUFFER_WIDTH, BUFFER_HEIGHT);
+    while(HAL_DMA2D_PollForTransfer(&dma2d, 1000) != HAL_OK);
+    BSP_LCD_SetBackColor(LCD_COLOR_RED);
+    BSP_LCD_SetTextColor(LCD_COLOR_RED);
+    BSP_LCD_FillRect(0, BUFFER_HEIGHT + 1, 90, 30);
+    BSP_LCD_FillRect(182, BUFFER_HEIGHT + 1, 90, 30);
+    BSP_LCD_SetBackColor(LCD_COLOR_YELLOW);
+    BSP_LCD_SetTextColor(LCD_COLOR_YELLOW);
+    BSP_LCD_DrawHLine(10, 256, 70);
+    BSP_LCD_DrawLine(10, 256, 20, 266);
+    BSP_LCD_DrawLine(10, 256, 20, 246);
+    BSP_LCD_DrawHLine(192, 256, 70);
+    BSP_LCD_DrawLine(262, 256, 252, 266);
+    BSP_LCD_DrawLine(262, 256, 252, 246);
+    BSP_LCD_SetFont(&Font24);
+    sprintf((char*)score_str, "%d\0", gs.scores);
+    BSP_LCD_SetTextColor(LCD_COLOR_DARKGREEN);
+    BSP_LCD_DisplayStringAt(95, 244, (uint8_t*)score_str, LEFT_MODE);
+    while(1) {
+        // draw car
+        if (gs.cur_car_pos != gs.prev_car_pos) {
+            Draw_Car(LCD_COLOR_WHITE, gs.prev_car_pos);
+            Draw_Car(LCD_COLOR_GREEN, gs.cur_car_pos);
+            gs.prev_car_pos = gs.cur_car_pos;
+        }
+        // draw obstacle
+        if (gs.obstacle_posy != gs.prev_obstacle_posy) {
+            Draw_Obstacle(LCD_COLOR_WHITE, gs.prev_obstacle_posy);
+            Draw_Obstacle(LCD_COLOR_BLUE, gs.obstacle_posy);
+            gs.prev_obstacle_posy = gs.obstacle_posy;
+        }
+        // update game state
+        if (game_counter == 10) {
+            gs.obstacle_posy += 1;
+            if (gs.obstacle_posy == 17) {
+                gs.obstacle_posy = -2;
+                gs.obstacle_posx = (gs.obstacle_posx + 3) % 14;
+                gs.scores += 1;
+                sprintf((char*)score_str, "%d\0", gs.scores);
+                BSP_LCD_DisplayStringAt(95, 244, (uint8_t*)score_str, LEFT_MODE);
+            }
+            game_counter = 0;
+        }
+        // delay
+        HAL_Delay(50);
+        game_counter++;
+        // draw on screen
+        dma2d.Init.Mode = DMA2D_M2M;
+        dma2d.Init.OutputOffset = 480 - 272;
+        dma2d.LayerCfg[1].InputOffset = 0;
+        HAL_DMA2D_Init(&dma2d);
+        HAL_DMA2D_ConfigLayer(&dma2d, 1);
+        HAL_DMA2D_Start(&dma2d, LCD_INMEM_BUF_ADDR, LCD_FB_START_ADDRESS, BUFFER_WIDTH, BUFFER_HEIGHT);
+        while(HAL_DMA2D_PollForTransfer(&dma2d, 1000) != HAL_OK);
+    }
+}
+
+void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
+    TS_StateTypeDef ts_data;
+    if (GPIO_Pin == TS_INT_PIN) {
+        BSP_TS_ITClear();
+        HAL_NVIC_DisableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn));
+        HAL_Delay(20);
+        BSP_TS_GetState(&ts_data);
+        if (ts_data.touchDetected > 0) {
+            if (ts_data.touchX[0] > 1 && ts_data.touchX[0] < 90
+                    && ts_data.touchY[0] > 240 && ts_data.touchY[0] < 272) {
+                if (gs.cur_car_pos > 0)
+                    gs.cur_car_pos -= 1;
+            }
+            if (ts_data.touchX[0] > 181 && ts_data.touchX[0] < 272
+                    && ts_data.touchY[0] > 240 && ts_data.touchY[0] < 272) {
+                    if (gs.cur_car_pos < 14)
+                        gs.cur_car_pos += 1;
+            }
+        }
+        HAL_NVIC_EnableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn));
+        BSP_TS_ResetTouchData(&ts_data);
+    }
+}
diff -r 000000000000 -r 0e534ad140f5 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Dec 09 13:36:25 2021 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/ad3be0349dc5
\ No newline at end of file