stm32-moto/Core/Src/gc9a01.c

633 lines
20 KiB
C

/**
* @file gc9a01.c
* @brief Implémentation du driver pour écran TFT rond GC9A01 240x240
*/
#include "gc9a01.h"
#include <math.h>
#include <string.h>
//==============================================================================
// Variables privées
//==============================================================================
static SPI_HandleTypeDef *hspi_gc9a01 = NULL;
// Police simple 8x8 (bitmap)
static const uint8_t font8x8_basic[128][8] = {
// A partir du caractère ' ' (32)
[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // space
[33] = { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // !
[34] = { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // "
[35] = { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // #
[36] = { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // $
[37] = { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // %
[38] = { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // &
[39] = { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // '
[40] = { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // (
[41] = { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // )
[42] = { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // *
[43] = { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // +
[44] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x06, 0x00}, // ,
[45] = { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // -
[46] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // .
[47] = { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // /
[48] = { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // 0
[49] = { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // 1
[50] = { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // 2
[51] = { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // 3
[52] = { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // 4
[53] = { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // 5
[54] = { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // 6
[55] = { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // 7
[56] = { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // 8
[57] = { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // 9
[58] = { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // :
[65] = { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // A
[66] = { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // B
[67] = { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // C
[68] = { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // D
[69] = { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // E
[70] = { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // F
[71] = { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // G
[72] = { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // H
[73] = { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // I
[74] = { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // J
[75] = { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // K
[76] = { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // L
[77] = { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // M
[78] = { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // N
[79] = { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // O
[80] = { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // P
[81] = { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // Q
[82] = { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // R
[83] = { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // S
[84] = { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // T
[85] = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U
[86] = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // V
[87] = { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // W
[88] = { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // X
[89] = { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // Y
[90] = { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // Z
};
//==============================================================================
// Fonctions privées
//==============================================================================
static void GC9A01_WriteCommand(uint8_t cmd) {
HAL_GPIO_WritePin(GC9A01_DC_GPIO_Port, GC9A01_DC_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(hspi_gc9a01, &cmd, 1, HAL_MAX_DELAY);
HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_SET);
}
static void GC9A01_WriteData(uint8_t data) {
HAL_GPIO_WritePin(GC9A01_DC_GPIO_Port, GC9A01_DC_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(hspi_gc9a01, &data, 1, HAL_MAX_DELAY);
HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_SET);
}
static void GC9A01_WriteDataBuffer(uint8_t *buffer, uint16_t len) {
HAL_GPIO_WritePin(GC9A01_DC_GPIO_Port, GC9A01_DC_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(hspi_gc9a01, buffer, len, HAL_MAX_DELAY);
HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_SET);
}
static void GC9A01_SetAddressWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
// Column address set
GC9A01_WriteCommand(GC9A01_CASET);
GC9A01_WriteData(x0 >> 8);
GC9A01_WriteData(x0 & 0xFF);
GC9A01_WriteData(x1 >> 8);
GC9A01_WriteData(x1 & 0xFF);
// Row address set
GC9A01_WriteCommand(GC9A01_RASET);
GC9A01_WriteData(y0 >> 8);
GC9A01_WriteData(y0 & 0xFF);
GC9A01_WriteData(y1 >> 8);
GC9A01_WriteData(y1 & 0xFF);
// Write to RAM
GC9A01_WriteCommand(GC9A01_RAMWR);
}
//==============================================================================
// Fonctions publiques
//==============================================================================
bool GC9A01_Init(SPI_HandleTypeDef *hspi) {
hspi_gc9a01 = hspi;
// Reset de l'écran
GC9A01_Reset();
HAL_Delay(100);
// Séquence d'initialisation GC9A01
GC9A01_WriteCommand(GC9A01_INREGEN2);
GC9A01_WriteCommand(GC9A01_SPI2DATA);
GC9A01_WriteCommand(0xEB);
GC9A01_WriteData(0x14);
GC9A01_WriteCommand(GC9A01_INREGEN2);
GC9A01_WriteCommand(GC9A01_SPI2DATA);
GC9A01_WriteCommand(0x84);
GC9A01_WriteData(0x40);
GC9A01_WriteCommand(0x85);
GC9A01_WriteData(0xFF);
GC9A01_WriteCommand(0x86);
GC9A01_WriteData(0xFF);
GC9A01_WriteCommand(0x87);
GC9A01_WriteData(0xFF);
GC9A01_WriteCommand(0x88);
GC9A01_WriteData(0x0A);
GC9A01_WriteCommand(0x89);
GC9A01_WriteData(0x21);
GC9A01_WriteCommand(0x8A);
GC9A01_WriteData(0x00);
GC9A01_WriteCommand(0x8B);
GC9A01_WriteData(0x80);
GC9A01_WriteCommand(0x8C);
GC9A01_WriteData(0x01);
GC9A01_WriteCommand(0x8D);
GC9A01_WriteData(0x01);
GC9A01_WriteCommand(0x8E);
GC9A01_WriteData(0xFF);
GC9A01_WriteCommand(0x8F);
GC9A01_WriteData(0xFF);
GC9A01_WriteCommand(GC9A01_DFUNCTR);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0x20);
GC9A01_WriteCommand(GC9A01_MADCTL);
GC9A01_WriteData(0x08);
GC9A01_WriteCommand(GC9A01_COLMOD);
GC9A01_WriteData(0x05);
GC9A01_WriteCommand(0x90);
GC9A01_WriteData(0x08);
GC9A01_WriteData(0x08);
GC9A01_WriteData(0x08);
GC9A01_WriteData(0x08);
GC9A01_WriteCommand(0xBD);
GC9A01_WriteData(0x06);
GC9A01_WriteCommand(0xBC);
GC9A01_WriteData(0x00);
GC9A01_WriteCommand(0xFF);
GC9A01_WriteData(0x60);
GC9A01_WriteData(0x01);
GC9A01_WriteData(0x04);
GC9A01_WriteCommand(GC9A01_PWCTR2);
GC9A01_WriteData(0x13);
GC9A01_WriteCommand(GC9A01_PWCTR3);
GC9A01_WriteData(0x13);
GC9A01_WriteCommand(GC9A01_PWCTR4);
GC9A01_WriteData(0x22);
GC9A01_WriteCommand(0xBE);
GC9A01_WriteData(0x11);
GC9A01_WriteCommand(0xE1);
GC9A01_WriteData(0x10);
GC9A01_WriteData(0x0E);
GC9A01_WriteCommand(0xDF);
GC9A01_WriteData(0x21);
GC9A01_WriteData(0x0c);
GC9A01_WriteData(0x02);
GC9A01_WriteCommand(GC9A01_GAMMA1);
GC9A01_WriteData(0x45);
GC9A01_WriteData(0x09);
GC9A01_WriteData(0x08);
GC9A01_WriteData(0x08);
GC9A01_WriteData(0x26);
GC9A01_WriteData(0x2A);
GC9A01_WriteCommand(GC9A01_GAMMA2);
GC9A01_WriteData(0x43);
GC9A01_WriteData(0x70);
GC9A01_WriteData(0x72);
GC9A01_WriteData(0x36);
GC9A01_WriteData(0x37);
GC9A01_WriteData(0x6F);
GC9A01_WriteCommand(GC9A01_GAMMA3);
GC9A01_WriteData(0x45);
GC9A01_WriteData(0x09);
GC9A01_WriteData(0x08);
GC9A01_WriteData(0x08);
GC9A01_WriteData(0x26);
GC9A01_WriteData(0x2A);
GC9A01_WriteCommand(GC9A01_GAMMA4);
GC9A01_WriteData(0x43);
GC9A01_WriteData(0x70);
GC9A01_WriteData(0x72);
GC9A01_WriteData(0x36);
GC9A01_WriteData(0x37);
GC9A01_WriteData(0x6F);
GC9A01_WriteCommand(0xED);
GC9A01_WriteData(0x1B);
GC9A01_WriteData(0x0B);
GC9A01_WriteCommand(0xAE);
GC9A01_WriteData(0x77);
GC9A01_WriteCommand(0xCD);
GC9A01_WriteData(0x63);
GC9A01_WriteCommand(0x70);
GC9A01_WriteData(0x07);
GC9A01_WriteData(0x07);
GC9A01_WriteData(0x04);
GC9A01_WriteData(0x0E);
GC9A01_WriteData(0x0F);
GC9A01_WriteData(0x71);
GC9A01_WriteData(0xEF);
GC9A01_WriteData(0x70);
GC9A01_WriteData(0x70);
GC9A01_WriteCommand(0x63);
GC9A01_WriteData(0x18);
GC9A01_WriteData(0x11);
GC9A01_WriteData(0x71);
GC9A01_WriteData(0xF1);
GC9A01_WriteData(0x70);
GC9A01_WriteData(0x70);
GC9A01_WriteData(0x18);
GC9A01_WriteData(0x13);
GC9A01_WriteData(0x71);
GC9A01_WriteData(0xF3);
GC9A01_WriteData(0x70);
GC9A01_WriteData(0x70);
GC9A01_WriteCommand(0x64);
GC9A01_WriteData(0x28);
GC9A01_WriteData(0x29);
GC9A01_WriteData(0xF1);
GC9A01_WriteData(0x01);
GC9A01_WriteData(0xF1);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0x07);
GC9A01_WriteCommand(0x66);
GC9A01_WriteData(0x3C);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0xCD);
GC9A01_WriteData(0x67);
GC9A01_WriteData(0x45);
GC9A01_WriteData(0x45);
GC9A01_WriteData(0x10);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0x00);
GC9A01_WriteCommand(0x67);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0x3C);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0x01);
GC9A01_WriteData(0x54);
GC9A01_WriteData(0x10);
GC9A01_WriteData(0x32);
GC9A01_WriteData(0x98);
GC9A01_WriteCommand(0x74);
GC9A01_WriteData(0x10);
GC9A01_WriteData(0x85);
GC9A01_WriteData(0x80);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0x00);
GC9A01_WriteData(0x4E);
GC9A01_WriteData(0x00);
GC9A01_WriteCommand(0x98);
GC9A01_WriteData(0x3e);
GC9A01_WriteData(0x07);
GC9A01_WriteCommand(GC9A01_SLPOUT);
HAL_Delay(120);
GC9A01_WriteCommand(GC9A01_DISPON);
HAL_Delay(20);
return true;
}
void GC9A01_Reset(void) {
HAL_GPIO_WritePin(GC9A01_RST_GPIO_Port, GC9A01_RST_Pin, GPIO_PIN_RESET);
HAL_Delay(10);
HAL_GPIO_WritePin(GC9A01_RST_GPIO_Port, GC9A01_RST_Pin, GPIO_PIN_SET);
HAL_Delay(10);
}
void GC9A01_DisplayOn(void) {
GC9A01_WriteCommand(GC9A01_DISPON);
}
void GC9A01_DisplayOff(void) {
GC9A01_WriteCommand(GC9A01_DISPOFF);
}
void GC9A01_SetRotation(uint8_t rotation) {
GC9A01_WriteCommand(GC9A01_MADCTL);
switch (rotation) {
case 0:
GC9A01_WriteData(0x08);
break;
case 1:
GC9A01_WriteData(0x68);
break;
case 2:
GC9A01_WriteData(0xC8);
break;
case 3:
GC9A01_WriteData(0xA8);
break;
}
}
void GC9A01_FillScreen(uint16_t color) {
GC9A01_SetAddressWindow(0, 0, GC9A01_WIDTH-1, GC9A01_HEIGHT-1);
uint8_t color_high = color >> 8;
uint8_t color_low = color & 0xFF;
HAL_GPIO_WritePin(GC9A01_DC_GPIO_Port, GC9A01_DC_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_RESET);
for (uint32_t i = 0; i < GC9A01_WIDTH * GC9A01_HEIGHT; i++) {
uint8_t data[2] = {color_high, color_low};
HAL_SPI_Transmit(hspi_gc9a01, data, 2, HAL_MAX_DELAY);
}
HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_SET);
}
void GC9A01_SetPixel(uint16_t x, uint16_t y, uint16_t color) {
if (x >= GC9A01_WIDTH || y >= GC9A01_HEIGHT) return;
GC9A01_SetAddressWindow(x, y, x, y);
uint8_t data[2] = {color >> 8, color & 0xFF};
GC9A01_WriteDataBuffer(data, 2);
}
void GC9A01_DrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) {
int16_t dx = abs(x1 - x0);
int16_t dy = abs(y1 - y0);
int16_t sx = (x0 < x1) ? 1 : -1;
int16_t sy = (y0 < y1) ? 1 : -1;
int16_t err = dx - dy;
while (1) {
GC9A01_SetPixel(x0, y0, color);
if (x0 == x1 && y0 == y1) break;
int16_t e2 = 2 * err;
if (e2 > -dy) {
err -= dy;
x0 += sx;
}
if (e2 < dx) {
err += dx;
y0 += sy;
}
}
}
void GC9A01_DrawRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) {
GC9A01_DrawLine(x, y, x + width - 1, y, color);
GC9A01_DrawLine(x + width - 1, y, x + width - 1, y + height - 1, color);
GC9A01_DrawLine(x + width - 1, y + height - 1, x, y + height - 1, color);
GC9A01_DrawLine(x, y + height - 1, x, y, color);
}
void GC9A01_FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) {
if (x >= GC9A01_WIDTH || y >= GC9A01_HEIGHT) return;
if (x + width > GC9A01_WIDTH) width = GC9A01_WIDTH - x;
if (y + height > GC9A01_HEIGHT) height = GC9A01_HEIGHT - y;
GC9A01_SetAddressWindow(x, y, x + width - 1, y + height - 1);
uint8_t color_high = color >> 8;
uint8_t color_low = color & 0xFF;
HAL_GPIO_WritePin(GC9A01_DC_GPIO_Port, GC9A01_DC_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_RESET);
for (uint32_t i = 0; i < width * height; i++) {
uint8_t data[2] = {color_high, color_low};
HAL_SPI_Transmit(hspi_gc9a01, data, 2, HAL_MAX_DELAY);
}
HAL_GPIO_WritePin(GC9A01_CS_GPIO_Port, GC9A01_CS_Pin, GPIO_PIN_SET);
}
void GC9A01_DrawCircle(uint16_t x, uint16_t y, uint8_t radius, uint16_t color) {
int16_t f = 1 - radius;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * radius;
int16_t x1 = 0;
int16_t y1 = radius;
GC9A01_SetPixel(x, y + radius, color);
GC9A01_SetPixel(x, y - radius, color);
GC9A01_SetPixel(x + radius, y, color);
GC9A01_SetPixel(x - radius, y, color);
while (x1 < y1) {
if (f >= 0) {
y1--;
ddF_y += 2;
f += ddF_y;
}
x1++;
ddF_x += 2;
f += ddF_x;
GC9A01_SetPixel(x + x1, y + y1, color);
GC9A01_SetPixel(x - x1, y + y1, color);
GC9A01_SetPixel(x + x1, y - y1, color);
GC9A01_SetPixel(x - x1, y - y1, color);
GC9A01_SetPixel(x + y1, y + x1, color);
GC9A01_SetPixel(x - y1, y + x1, color);
GC9A01_SetPixel(x + y1, y - x1, color);
GC9A01_SetPixel(x - y1, y - x1, color);
}
}
void GC9A01_FillCircle(uint16_t x, uint16_t y, uint8_t radius, uint16_t color) {
for (int16_t dy = -radius; dy <= radius; dy++) {
for (int16_t dx = -radius; dx <= radius; dx++) {
if (dx*dx + dy*dy <= radius*radius) {
GC9A01_SetPixel(x + dx, y + dy, color);
}
}
}
}
void GC9A01_DrawChar(uint16_t x, uint16_t y, char c, uint16_t color, uint16_t bg_color, uint8_t size) {
if (c < 32 || c > 127) c = '?';
for (int i = 0; i < 8; i++) {
uint8_t line = font8x8_basic[c][i];
for (int j = 0; j < 8; j++) {
if (line & (1 << j)) {
if (size == 1) {
GC9A01_SetPixel(x + j, y + i, color);
} else {
GC9A01_FillRect(x + j * size, y + i * size, size, size, color);
}
} else if (bg_color != color) {
if (size == 1) {
GC9A01_SetPixel(x + j, y + i, bg_color);
} else {
GC9A01_FillRect(x + j * size, y + i * size, size, size, bg_color);
}
}
}
}
}
void GC9A01_DrawString(uint16_t x, uint16_t y, const char *str, uint16_t color, uint16_t bg_color, uint8_t size) {
while (*str) {
GC9A01_DrawChar(x, y, *str, color, bg_color, size);
x += 8 * size;
str++;
}
}
uint16_t GC9A01_RGB565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
bool GC9A01_IsInCircle(uint16_t x, uint16_t y) {
int16_t dx = x - GC9A01_RADIUS;
int16_t dy = y - GC9A01_RADIUS;
return (dx*dx + dy*dy) <= (GC9A01_RADIUS * GC9A01_RADIUS);
}
// Fonctions spécifiques pour interface moto
void GC9A01_DrawGauge(uint16_t center_x, uint16_t center_y, uint8_t radius,
float value, float min_val, float max_val,
uint16_t color, const char* label) {
// Dessiner le cercle extérieur
GC9A01_DrawCircle(center_x, center_y, radius, GC9A01_WHITE);
// Calculer l'angle (de -90° à +90°, soit 180° total)
float normalized = (value - min_val) / (max_val - min_val);
if (normalized < 0) normalized = 0;
if (normalized > 1) normalized = 1;
float angle = -90.0f + (normalized * 180.0f); // -90° à +90°
float rad = angle * M_PI / 180.0f;
// Dessiner l'aiguille
int16_t needle_x = center_x + (radius - 5) * cos(rad);
int16_t needle_y = center_y + (radius - 5) * sin(rad);
GC9A01_DrawLine(center_x, center_y, needle_x, needle_y, color);
// Dessiner le centre
GC9A01_FillCircle(center_x, center_y, 3, color);
// Afficher la valeur
char value_str[10];
snprintf(value_str, sizeof(value_str), "%.1f", value);
GC9A01_DrawString(center_x - 20, center_y + radius + 10, value_str, color, GC9A01_BLACK, 1);
// Afficher le label
if (label) {
GC9A01_DrawString(center_x - strlen(label) * 4, center_y - radius - 20, label, GC9A01_WHITE, GC9A01_BLACK, 1);
}
}
void GC9A01_DrawAngleIndicator(float roll, float pitch) {
uint16_t center_x = GC9A01_WIDTH / 2;
uint16_t center_y = GC9A01_HEIGHT / 2;
// Effacer la zone central
GC9A01_FillCircle(center_x, center_y, 50, GC9A01_BLACK);
// Dessiner l'horizon artificiel
GC9A01_DrawCircle(center_x, center_y, 50, GC9A01_WHITE);
// Ligne d'horizon (basée sur le pitch)
int16_t horizon_offset = (int16_t)(pitch * 2); // Facteur d'échelle
GC9A01_DrawLine(center_x - 40, center_y + horizon_offset,
center_x + 40, center_y + horizon_offset, GC9A01_CYAN);
// Indicateur de roulis (triangle au centre)
float roll_rad = roll * M_PI / 180.0f;
int16_t tri_x = center_x + 20 * sin(roll_rad);
int16_t tri_y = center_y - 20 * cos(roll_rad);
GC9A01_DrawLine(center_x, center_y, tri_x, tri_y, GC9A01_RED);
GC9A01_FillCircle(tri_x, tri_y, 3, GC9A01_RED);
// Afficher les valeurs numériques
char roll_str[10], pitch_str[10];
snprintf(roll_str, sizeof(roll_str), "R:%.1f", roll);
snprintf(pitch_str, sizeof(pitch_str), "P:%.1f", pitch);
GC9A01_DrawString(10, 10, roll_str, GC9A01_WHITE, GC9A01_BLACK, 1);
GC9A01_DrawString(10, 25, pitch_str, GC9A01_WHITE, GC9A01_BLACK, 1);
}
void GC9A01_DrawStateIndicator(const char* state, uint16_t color) {
// Effacer la zone du bas
GC9A01_FillRect(0, GC9A01_HEIGHT - 30, GC9A01_WIDTH, 30, GC9A01_BLACK);
// Centrer le texte
uint16_t text_width = strlen(state) * 8;
uint16_t start_x = (GC9A01_WIDTH - text_width) / 2;
GC9A01_DrawString(start_x, GC9A01_HEIGHT - 20, state, color, GC9A01_BLACK, 1);
}A01_WriteData(0x09);
GC9A01_WriteData(0x07);
GC9A01_WriteData(0x08);
GC9A01_WriteData(0x03);
GC9A01_WriteCommand(GC9A01_FRAMERATE);
GC9A01_WriteData(0x34);
GC9A01_WriteCommand(0x62);
GC9A01_WriteData(0x18);
GC9A01_WriteData(0x0D);
GC9A01_WriteData(0x71);
GC9A01_WriteData(0xED);
GC9A01_WriteData(0x70);
GC9A01_WriteData(0x70);
GC9A01_WriteData(0x18);
GC9A01_WriteData(0x0F);
GC9