ow-dash-cube/Core/Src/LCD_driver.c
2025-09-14 16:58:50 +02:00

705 lines
22 KiB
C

// Driver afficheur ADA 1983/chip ILI9341 pour Kit STM32L476 IUT1 de Grenoble Dpt GEII
//
// Adaptations L476, et fusion libs : V. GRENNERAT, IUT1 de Grenoble, Dpt GEII
// Correction bug coordonnees X et Y pour Draw_Char et Draw_Text : V. GRENNERAT
// Ajout fonction LCD_Draw_Image_XY : V. GRENNERAT
// Intégration des fonctions de configuration SPI3 et GPIO : V. GRENNERAT
// Version 2 (1/12/2019) :
// Suppression de l'utilisation de la HAL STM32 : V. GRENNERAT
// Diverses optimisations, dans les burst images.
// --------------------------------
// MIT License
//
// Copyright (c) 2017 Matej Artnak
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
/* Includes ------------------------------------------------------------------*/
#include "LCD_driver.h"
#include "5x5_font.h"
#include "stm32f1xx.h"
/* Global Variables ------------------------------------------------------------------*/
volatile uint16_t LCD_HEIGHT = LCD_SCREEN_HEIGHT;
volatile uint16_t LCD_WIDTH = LCD_SCREEN_WIDTH;
// Set all 16 data pins (DB0-DB15) based on a 16-bit value
//void SetDataPins(uint16_t value) {
// GPIOA->BSRR = (value & (1 << 0) ? DB0_Pin : (DB0_Pin << 16)) | // DB0 (GPIOA)
// (value & (1 << 14) ? DB14_Pin : (DB14_Pin << 16)); // DB14 (GPIOA)
// GPIOB->BSRR = (value & (1 << 1) ? DB1_Pin : (DB1_Pin << 16)) | // DB1 (GPIOB)
// (value & (1 << 3) ? DB3_Pin : (DB3_Pin << 16)) | // DB3 (GPIOB)
// (value & (1 << 5) ? DB5_Pin : (DB5_Pin << 16)) | // DB5 (GPIOB)
// (value & (1 << 7) ? DB7_Pin : (DB7_Pin << 16)) | // DB7 (GPIOB)
// (value & (1 << 9) ? DB9_Pin : (DB9_Pin << 16)) | // DB9 (GPIOB)
// (value & (1 << 11) ? DB11_Pin : (DB11_Pin << 16)) | // DB11 (GPIOB)
// (value & (1 << 12) ? DB12_Pin : (DB12_Pin << 16)) | // DB12 (GPIOB)
// (value & (1 << 13) ? DB13_Pin : (DB13_Pin << 16)) | // DB13 (GPIOB)
// (value & (1 << 15) ? DB15_Pin : (DB15_Pin << 16)); // DB15 (GPIOB)
//
// GPIOD->BSRR = (value & (1 << 2) ? DB2_Pin : (DB2_Pin << 16)) | // DB2 (GPIOD)
// (value & (1 << 4) ? DB4_Pin : (DB4_Pin << 16)); // DB4 (GPIOD)
//
// GPIOC->BSRR = (value & (1 << 6) ? DB6_Pin : (DB6_Pin << 16)) | // DB6 (GPIOC)
// (value & (1 << 8) ? DB8_Pin : (DB8_Pin << 16)) | // DB8 (GPIOC)
// (value & (1 << 10) ? DB10_Pin : (DB10_Pin << 16)); // DB10 (GPIOC)
//}
//void SetDataPins(uint16_t value) {
// // Reset all data pins to 0 first (using BRR)
// GPIOA->BRR = DB0_Pin | DB14_Pin; // Reset DB0, DB14 (GPIOA)
// GPIOB->BRR = DB1_Pin | DB3_Pin | DB5_Pin | DB7_Pin | DB9_Pin |
// DB11_Pin | DB12_Pin | DB13_Pin | DB15_Pin; // Reset DB1, DB3, DB5, DB7, DB9, DB11, DB12, DB13, DB15 (GPIOB)
// GPIOD->BRR = DB2_Pin | DB4_Pin; // Reset DB2, DB4 (GPIOD)
// GPIOC->BRR = DB6_Pin | DB8_Pin | DB10_Pin; // Reset DB6, DB8, DB10 (GPIOC)
//
// // Set pins to 1 if their corresponding bit in 'value' is 1 (using BSRR)
// if (value & (1 << 0)) GPIOA->BSRR = DB0_Pin; // DB0 (GPIOA)
// if (value & (1 << 1)) GPIOB->BSRR = DB1_Pin; // DB1 (GPIOB)
// if (value & (1 << 2)) GPIOD->BSRR = DB2_Pin; // DB2 (GPIOD)
// if (value & (1 << 3)) GPIOB->BSRR = DB3_Pin; // DB3 (GPIOB)
// if (value & (1 << 4)) GPIOD->BSRR = DB4_Pin; // DB4 (GPIOD)
// if (value & (1 << 5)) GPIOB->BSRR = DB5_Pin; // DB5 (GPIOB)
// if (value & (1 << 6)) GPIOC->BSRR = DB6_Pin; // DB6 (GPIOC)
// if (value & (1 << 7)) GPIOB->BSRR = DB7_Pin; // DB7 (GPIOB)
// if (value & (1 << 8)) GPIOC->BSRR = DB8_Pin; // DB8 (GPIOC)
// if (value & (1 << 9)) GPIOB->BSRR = DB9_Pin; // DB9 (GPIOB)
// if (value & (1 << 10)) GPIOC->BSRR = DB10_Pin; // DB10 (GPIOC)
// if (value & (1 << 11)) GPIOB->BSRR = DB11_Pin; // DB11 (GPIOB)
// if (value & (1 << 12)) GPIOB->BSRR = DB12_Pin; // DB12 (GPIOB)
// if (value & (1 << 13)) GPIOB->BSRR = DB13_Pin; // DB13 (GPIOB)
// if (value & (1 << 14)) GPIOA->BSRR = DB14_Pin; // DB14 (GPIOA)
// if (value & (1 << 15)) GPIOB->BSRR = DB15_Pin; // DB15 (GPIOB)
//}
typedef struct {
GPIO_TypeDef* port;
uint16_t pin;
} DataPin;
// Map each data bit (DB0-DB15) to its GPIO port and pin
const DataPin dataPins[16] = {
{DB0_GPIO_Port, DB0_Pin}, // DB0
{DB1_GPIO_Port, DB1_Pin}, // DB1
{DB2_GPIO_Port, DB2_Pin}, // DB2
{DB3_GPIO_Port, DB3_Pin}, // DB3
{DB4_GPIO_Port, DB4_Pin}, // DB4
{DB5_GPIO_Port, DB5_Pin}, // DB5
{DB6_GPIO_Port, DB6_Pin}, // DB6
{DB7_GPIO_Port, DB7_Pin}, // DB7
{DB8_GPIO_Port, DB8_Pin}, // DB8
{DB9_GPIO_Port, DB9_Pin}, // DB9
{DB10_GPIO_Port, DB10_Pin}, // DB10
{DB11_GPIO_Port, DB11_Pin}, // DB11
{DB12_GPIO_Port, DB12_Pin}, // DB12
{DB13_GPIO_Port, DB13_Pin}, // DB13
{DB14_GPIO_Port, DB14_Pin}, // DB14
{DB15_GPIO_Port, DB15_Pin} // DB15
};
void SetDataPins(uint16_t value) {
for (int i = 0; i < 16; i++) {
// Check if the i-th bit in 'value' is set
GPIO_PinState state = (value & (1 << i)) ? GPIO_PIN_SET : GPIO_PIN_RESET;
// Write the state to the corresponding GPIO pin
HAL_GPIO_WritePin(dataPins[i].port, dataPins[i].pin, state);
}
}
//void ScreenWriteCmd(uint16_t command) {
// MCU_RS_LOW();
// MCU_CS_LOW();
// SetDataPins(command);
// __NOP();
//
// MCU_WR_LOW();
// __NOP(); __NOP(); __NOP(); __NOP();
// MCU_WR_HIGH();
// __NOP(); __NOP(); __NOP(); __NOP();
//
// MCU_CS_HIGH();
//}
//void ScreenWriteData(uint16_t data) {
// MCU_RS_HIGH();
// MCU_CS_LOW();
// SetDataPins(data);
// __NOP();
//
// MCU_WR_LOW();
// __NOP(); __NOP(); __NOP(); __NOP();
// MCU_WR_HIGH();
// __NOP(); __NOP(); __NOP(); __NOP();
//
// MCU_CS_HIGH();
//}
// Write Command (optimized for timing)
void ScreenWriteCmd(uint16_t command) {
// 1. Set RS to command mode (t_AS = 10 ns)
MCU_RS_LOW();
__NOP(); // 1 NOP = ~15.625 ns > 10 ns
// 2. Assert CS (t_AS = 10 ns)
MCU_CS_LOW();
__NOP(); // 1 NOP = ~15.625 ns > 10 ns
// 3. Set data pins (t_DSW = 10 ns)
SetDataPins(command);
__NOP(); // 1 NOP = ~15.625 ns > 10 ns
// 4. Pulse WR low (PWLW = 50 ns)
MCU_WR_LOW();
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); // 4 NOPs = ~62.5 ns > 50 ns
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
MCU_WR_HIGH();
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
// 5. Hold time (t_H = 15 ns)
__NOP(); __NOP(); __NOP(); __NOP(); // 4 NOPs
// 6. Deassert CS (t_AH = 5 ns)
MCU_CS_HIGH();
}
// Write Data (same timing as command)
void ScreenWriteData(uint16_t data) {
// 1. Set RS to data mode (t_AS = 10 ns)
MCU_RS_HIGH();
__NOP(); // 1 NOP
// 2. Assert CS (t_AS = 10 ns)
MCU_CS_LOW();
__NOP(); // 1 NOP
// 3. Set data pins (t_DSW = 10 ns)
SetDataPins(data);
__NOP(); // 1 NOP
// 4. Pulse WR low (PWLW = 50 ns)
MCU_WR_LOW();
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); // 4 NOPs
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
MCU_WR_HIGH();
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
// 5. Hold time (t_H = 15 ns)
__NOP(); __NOP(); __NOP(); __NOP(); // 4 NOPs
// 6. Deassert CS (t_AH = 5 ns)
MCU_CS_HIGH();
}
/* Send command (char) to LCD via SPI bus */
void LCD_Write_Command(uint8_t Command) {
while ((SPI1->SR & SPI_SR_BSY) != 0);
CMD
;
while ((SPI1->SR & SPI_SR_TXE) == 0);
SPI1->DR = Command;// Cast sur pointeur, pour ecriture 8 bits. Sinon l'acces 16 bits provoque un tfert 16 bits
}
/* Send Data (char) to LCD via SPI bus */
void LCD_Write_Data(uint8_t Data) {
while ((SPI1->SR & SPI_SR_BSY) != 0);//Attendre fin envoi trame
DATA
;
while ((SPI1->SR & SPI_SR_TXE) == 0);// Waiting for TX register to be available.
SPI1->DR = Data;
}
void LCD_Write_Data16(uint16_t data) {
while ((SPI1->SR & SPI_SR_BSY) != 0);// Wait until SPI is not busy
DATA
;
while ((SPI1->SR & SPI_SR_TXE) == 0);// Wait for TX buffer empty
SPI1->DR = (data >> 8) & 0xFF;// Send MSB
while ((SPI1->SR & SPI_SR_TXE) == 0);// Wait for TX buffer empty
SPI1->DR = data & 0xFF;// Send LSB
}
/* Set the frame to draw into and sends a write into frame command */
void LCD_Set_Address(uint16_t X1, uint16_t Y1, uint16_t X2, uint16_t Y2) {
ScreenWriteCmd(0x2A);
ScreenWriteData(X1 + 10);
ScreenWriteData(X2 + 10);
ScreenWriteCmd(0x2B);
ScreenWriteData(Y1 + 19);
ScreenWriteData(Y2 + 19);
ScreenWriteCmd(0x2C);
}
void LCD_HardwareReset() {
HAL_GPIO_WritePin(DRESET_GPIO_Port, DRESET_Pin, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(DRESET_GPIO_Port, DRESET_Pin, GPIO_PIN_RESET);
HAL_Delay(20);
HAL_GPIO_WritePin(DRESET_GPIO_Port, DRESET_Pin, GPIO_PIN_SET);
HAL_Delay(200);
}
void LCD_Init(void) {
MCU_RD_HIGH();
LCD_HardwareReset();
// Software reset
ScreenWriteCmd(0x01); // 1
HAL_Delay(150);
// Color mode: 16bit/pixels
ScreenWriteCmd(0x3A);
ScreenWriteData(0x55);
HAL_Delay(10);
// Enable color inversion (INVON)
//ScreenWriteCmd(0x21); // 0100001
// 1010001
// Configure orientation stuff
//ScreenWriteCmd(0x36);
//ScreenWriteData(0b10110100);
// Exit sleep
ScreenWriteCmd(0x11);
HAL_Delay(120);
// Turn on display
ScreenWriteCmd(0x29);
HAL_Delay(100);
// Fill white
LCD_Fill_Screen(RED);
// Draw colors columns
// LCD_Set_Address(30, 30, LCD_SCREEN_WIDTH - 30, LCD_SCREEN_HEIGHT - 30);
// uint32_t size = (LCD_SCREEN_WIDTH - 59) * 20;
// LCD_Draw_Colour_Burst(BLACK, size);
// LCD_Draw_Colour_Burst(WHITE, size);
// LCD_Draw_Colour_Burst(BLUE, size);
// LCD_Draw_Colour_Burst(GREEN, size);
// LCD_Draw_Colour_Burst(RED, size);
// LCD_Draw_Colour_Burst(BLACK, 4 * size);
// Draw rectangles in the angles
// LCD_Draw_Rectangle(1, 1, 20, 20, RED);
// LCD_Draw_Rectangle(LCD_SCREEN_WIDTH - 21, 1, 20, 20, GREEN);
// LCD_Draw_Rectangle(LCD_SCREEN_WIDTH - 21, LCD_SCREEN_HEIGHT - 21, 20, 20,
// MAGENTA);
// LCD_Draw_Rectangle(1, LCD_SCREEN_HEIGHT - 21, 20, 20, BLUE);
// STARTING ROTATION
//LCD_Set_Rotation(SCREEN_HORIZONTAL_1);
}
//INTERNAL FUNCTION OF LIBRARY
/*Sends block colour information to LCD*/
void LCD_Draw_Colour_Burst(uint16_t color, uint32_t size) {
//while ((SPI1->SR & SPI_SR_BSY) != 0);// Wait until SPI is not busy
// DATA;
for (uint32_t j = 0; j < size; j++) {
ScreenWriteData(color);
// while ((SPI1->SR & SPI_SR_TXE) == 0);// Waiting for TX register to be available.
// SPI1->DR = (color >> 8) & 0xFF;
// while ((SPI1->SR & SPI_SR_TXE) == 0);// Waiting for TX register to be available.
// SPI1->DR = color & 0xFF;
}
}
//FILL THE ENTIRE SCREEN WITH SELECTED COLOUR (either #define-d ones or custom 16bit)
/*Sets address (entire screen) and Sends Height*Width ammount of colour information to LCD*/
void LCD_Fill_Screen(uint16_t color) {
LCD_Draw_Rectangle(0, 0, LCD_WIDTH, LCD_HEIGHT, color);
}
//DRAW PIXEL AT XY POSITION WITH SELECTED COLOUR
//
//Location is dependant on screen orientation. x0 and y0 locations change with orientations.
//Using pixels to draw big simple structures is not recommended as it is really slow
//Try using either rectangles or lines if possible
//
//void LCD_Draw_Pixel(uint16_t X, uint16_t Y, uint16_t Colour) {
// if ((X >= LCD_WIDTH) || (Y >= LCD_HEIGHT)) return;//OUT OF BOUNDS!
//
////ADDRESS
// LCD_Write_Command(0x2A);
//
////XDATA
// DATA
// ;
// CS_ON;
// SPI3->DR = (X >> 8) | (X << 8);//inversion MSB / LSB pour envoi des 2 mots 8 bits en 1W 16bits
////Pas d'att si FIFO full (TX buffer Empty=0) car juste 2 écriture 16 bits tiennent dans FIFO
// SPI3->DR = ((X + 1) >> 8) | ((X + 1) << 8);
// while ((SPI3->SR & SPI_SR_BSY) != 0);//Attendre fin envoi trame
// CS_OFF;
//
////ADDRESS
// LCD_Write_Command(0x2B);
//
////YDATA
// DATA
// ;
// CS_ON;
// SPI3->DR = (Y >> 8) | (Y << 8);
// SPI3->DR = ((Y + 1) >> 8) | ((Y + 1) << 8);
// while ((SPI3->SR & SPI_SR_BSY) != 0);//Attendre fin envoi trame
// CS_OFF;
//
////ADDRESS
// LCD_Write_Command(0x2C);
//
////COLOUR
// DATA
// ;
// CS_ON;
// SPI3->DR = (Colour >> 8) | (Colour << 8);
// while ((SPI3->SR & SPI_SR_BSY) != 0);//Attendre fin envoi trame
// CS_OFF;
//}
//DRAW RECTANGLE OF SET SIZE AND HEIGTH AT X and Y POSITION WITH CUSTOM COLOUR
//
//Rectangle is hollow. X and Y positions mark the upper left corner of rectangle
//As with all other draw calls x0 and y0 locations dependant on screen orientation
//
void LCD_Draw_Rectangle(
uint16_t X,
uint16_t Y,
uint16_t Width,
uint16_t Height,
uint16_t Colour) {
if ((X >= LCD_WIDTH) || (Y >= LCD_HEIGHT)) return;
if ((X + Width - 1) >= LCD_WIDTH) {
Width = LCD_WIDTH - X;
}
if ((Y + Height - 1) >= LCD_HEIGHT) {
Height = LCD_HEIGHT - Y;
}
LCD_Set_Address(X, Y, X + Width - 1, Y + Height - 1);
LCD_Draw_Colour_Burst(Colour, Height * Width);
}
//DRAW LINE FROM X,Y LOCATION to X+Width,Y LOCATION
void LCD_Draw_Horizontal_Line(
uint16_t X,
uint16_t Y,
uint16_t Width,
uint16_t Colour) {
if ((X >= LCD_WIDTH) || (Y >= LCD_HEIGHT)) return;
if ((X + Width - 1) >= LCD_WIDTH) {
Width = LCD_WIDTH - X;
}
LCD_Set_Address(X, Y, X + Width - 1, Y);
LCD_Draw_Colour_Burst(Colour, Width);
}
//DRAW LINE FROM X,Y LOCATION to X,Y+Height LOCATION
void LCD_Draw_Vertical_Line(
uint16_t X,
uint16_t Y,
uint16_t Height,
uint16_t Colour) {
if ((X >= LCD_WIDTH) || (Y >= LCD_HEIGHT)) return;
if ((Y + Height - 1) >= LCD_HEIGHT) {
Height = LCD_HEIGHT - Y;
}
LCD_Set_Address(X, Y, X, Y + Height - 1);
LCD_Draw_Colour_Burst(Colour, Height);
}
/*********************Partie de la Lib issue de LCD_GFX**************************/
/*Draw hollow circle at X,Y location with specified radius and colour. X and Y represent circles center */
void LCD_Draw_Hollow_Circle(
uint16_t X,
uint16_t Y,
uint16_t Radius,
uint16_t Colour) {
int x = Radius - 1;
int y = 0;
int dx = 1;
int dy = 1;
int err = dx - (Radius << 1);
while (x >= y) {
LCD_Draw_Pixel(X + x, Y + y, Colour);
LCD_Draw_Pixel(X + y, Y + x, Colour);
LCD_Draw_Pixel(X - y, Y + x, Colour);
LCD_Draw_Pixel(X - x, Y + y, Colour);
LCD_Draw_Pixel(X - x, Y - y, Colour);
LCD_Draw_Pixel(X - y, Y - x, Colour);
LCD_Draw_Pixel(X + y, Y - x, Colour);
LCD_Draw_Pixel(X + x, Y - y, Colour);
if (err <= 0) {
y++;
err += dy;
dy += 2;
}
if (err > 0) {
x--;
dx += 2;
err += (-Radius << 1) + dx;
}
}
}
/*Draw filled circle at X,Y location with specified radius and colour. X and Y represent circles center */
void LCD_Draw_Filled_Circle(
uint16_t X,
uint16_t Y,
uint16_t Radius,
uint16_t Colour) {
int x = Radius;
int y = 0;
int xChange = 1 - (Radius << 1);
int yChange = 0;
int radiusError = 0;
while (x >= y) {
for (int i = X - x; i <= X + x; i++) {
LCD_Draw_Pixel(i, Y + y, Colour);
LCD_Draw_Pixel(i, Y - y, Colour);
}
for (int i = X - y; i <= X + y; i++) {
LCD_Draw_Pixel(i, Y + x, Colour);
LCD_Draw_Pixel(i, Y - x, Colour);
}
y++;
radiusError += yChange;
yChange += 2;
if (((radiusError << 1) + xChange) > 0) {
x--;
radiusError += xChange;
xChange += 2;
}
}
//Really slow implementation, will require future overhaul
//TODO: https://stackoverflow.com/questions/1201200/fast-algorithm-for-drawing-filled-circles
}
/*Draw a hollow rectangle between positions X0,Y0 and X1,Y1 with specified colour*/
void LCD_Draw_Hollow_Rectangle_Coord(
uint16_t X0,
uint16_t Y0,
uint16_t X1,
uint16_t Y1,
uint16_t Colour) {
uint16_t X_length = 0;
uint16_t Y_length = 0;
uint8_t Negative_X = 0;
uint8_t Negative_Y = 0;
float Calc_Negative = 0;
Calc_Negative = X1 - X0;
if (Calc_Negative < 0) Negative_X = 1;
Calc_Negative = 0;
Calc_Negative = Y1 - Y0;
if (Calc_Negative < 0) Negative_Y = 1;
//DRAW HORIZONTAL!
if (!Negative_X) {
X_length = X1 - X0;
} else {
X_length = X0 - X1;
}
LCD_Draw_Horizontal_Line(X0, Y0, X_length, Colour);
LCD_Draw_Horizontal_Line(X0, Y1, X_length, Colour);
//DRAW VERTICAL!
if (!Negative_Y) {
Y_length = Y1 - Y0;
} else {
Y_length = Y0 - Y1;
}
LCD_Draw_Vertical_Line(X0, Y0, Y_length, Colour);
LCD_Draw_Vertical_Line(X1, Y0, Y_length, Colour);
if ((X_length > 0) || (Y_length > 0)) {
LCD_Draw_Pixel(X1, Y1, Colour);
}
}
/*Draw a filled rectangle between positions X0,Y0 and X1,Y1 with specified colour*/
void LCD_Draw_Filled_Rectangle_Coord(
uint16_t X0,
uint16_t Y0,
uint16_t X1,
uint16_t Y1,
uint16_t Colour) {
uint16_t X_length = 0;
uint16_t Y_length = 0;
uint8_t Negative_X = 0;
uint8_t Negative_Y = 0;
int32_t Calc_Negative = 0;
uint16_t X0_true = 0;
uint16_t Y0_true = 0;
Calc_Negative = X1 - X0;
if (Calc_Negative < 0) Negative_X = 1;
Calc_Negative = 0;
Calc_Negative = Y1 - Y0;
if (Calc_Negative < 0) Negative_Y = 1;
//DRAW HORIZONTAL!
if (!Negative_X) {
X_length = X1 - X0;
X0_true = X0;
} else {
X_length = X0 - X1;
X0_true = X1;
}
//DRAW VERTICAL!
if (!Negative_Y) {
Y_length = Y1 - Y0;
Y0_true = Y0;
} else {
Y_length = Y0 - Y1;
Y0_true = Y1;
}
LCD_Draw_Rectangle(X0_true, Y0_true, X_length, Y_length, Colour);
}
/*Draws a character (fonts imported from fonts.h) at X,Y location with specified font colour, size and Background colour*/
/*See fonts.h implementation of font on what is required for changing to a different font when switching fonts libraries*/
void LCD_Draw_Char(
char Character,
uint16_t X,
uint16_t Y,
uint16_t Colour,
uint16_t Size,
uint16_t Background_Colour) {
uint8_t function_char;
uint8_t i, j;
function_char = Character;
if (function_char < ' ') {
Character = 0;
} else {
function_char -= 32;
}
char temp[CHAR_WIDTH];
for (uint8_t k = 0; k < CHAR_WIDTH; k++) {
temp[k] = font[function_char][k];
}
// Draw pixels
LCD_Draw_Rectangle(X, Y, CHAR_WIDTH * Size, CHAR_HEIGHT * Size,
Background_Colour);
for (j = 0; j < CHAR_WIDTH; j++) {
for (i = 0; i < CHAR_HEIGHT; i++) {
if (temp[j] & (1 << i)) {
if (Size == 1) {
LCD_Draw_Pixel(X + j, Y + i, Colour);
} else {
LCD_Draw_Rectangle(X + (j * Size), Y + (i * Size), Size, Size,
Colour);
}
}
}
}
}
/*Draws an array of characters (fonts imported from fonts.h) at X,Y location with specified font colour, size and Background colour*/
/*See fonts.h implementation of font on what is required for changing to a different font when switching fonts libraries*/
void LCD_Draw_Text(
const char *Text,
uint16_t X,
uint16_t Y,
uint16_t Colour,
uint16_t Size,
uint16_t Background_Colour) {
while (*Text) {
LCD_Draw_Char(*Text++, X, Y, Colour, Size, Background_Colour);
X += CHAR_WIDTH * Size;
}
}
/*Dessine une image dans une zone de l'ecran, aux coordonnées X et Y*/
//CONVERTISSEUR: http://www.digole.com/tools/PicturetoC_Hex_converter.php
//65K colour (2Bytes / Pixel)
//void LCD_Draw_Image_XY(
// const char *Image_Array,
// uint16_t X,
// uint16_t Y,
// uint16_t Width,
// uint16_t Height) {
// LCD_Set_Address(X, Y, X + Width - 1, Y + Height - 1);
//
// DATA
// ;
// CS_ON;
//
// for (uint32_t i = 0; i < Width * Height * 2; i += 2) {
// while ((SPI3->SR & SPI_SR_TXE) == 0);//Si FIFO full (TX buffer Empty=0), on attend
//// on utilise l'ecriture 16 bits dans DR, pour des envois 8 bits
//// Le LSB doit etre place ds le MSB :
// SPI3->DR = ((short) Image_Array[i + 1]) << 8 | Image_Array[i];
// }
//
// while ((SPI3->SR & SPI_SR_BSY) != 0);//Attendre fin envoi trame
// CS_OFF;
//}
/*Draws a full screen picture from flash. Image converted from RGB .jpeg/other to C array using online converter*/
//USING CONVERTER: http://www.digole.com/tools/PicturetoC_Hex_converter.php
//65K colour (2Bytes / Pixel)
//void LCD_Draw_Image_Full(const char *Image_Array, uint8_t Orientation) {
// switch (Orientation) {
// case SCREEN_HORIZONTAL_1:
// LCD_Set_Rotation(SCREEN_HORIZONTAL_1);
// LCD_Set_Address(0, 0, LCD_SCREEN_WIDTH, LCD_SCREEN_HEIGHT);
// break;
//
// case SCREEN_HORIZONTAL_2:
// LCD_Set_Rotation(SCREEN_HORIZONTAL_2);
// LCD_Set_Address(0, 0, LCD_SCREEN_WIDTH, LCD_SCREEN_HEIGHT);
// break;
//
// case SCREEN_VERTICAL_1:
// LCD_Set_Rotation(SCREEN_VERTICAL_1);
// LCD_Set_Address(0, 0, LCD_SCREEN_HEIGHT, LCD_SCREEN_WIDTH);
// break;
//
// case SCREEN_VERTICAL_2:
// LCD_Set_Rotation(SCREEN_VERTICAL_2);
// LCD_Set_Address(0, 0, LCD_SCREEN_HEIGHT, LCD_SCREEN_WIDTH);
// break;
// }
//
// DATA
// ;
// CS_ON;
//
// for (uint32_t i = 0; i < LCD_SCREEN_WIDTH * LCD_SCREEN_HEIGHT * 2; i += 2) {
// while ((SPI3->SR & SPI_SR_TXE) == 0);//Si FIFO full (TX buffer Empty=0), on attend
//// on utilise l'ecriture 16 bits dans DR, pour des envois 8 bits
//// Le LSB doit etre place ds le MSB :
// SPI3->DR = ((short) Image_Array[i + 1]) << 8 | Image_Array[i];
// }
//
// while ((SPI3->SR & SPI_SR_BSY) != 0);//Attendre fin envoi trame
// CS_OFF;
//}