ow-dash-cube/Core/Src/LCD_driver.c
2025-08-18 23:08:08 +02:00

706 lines
19 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;
/* SPI3 & GPIOs init function */
void LCD_SPI_Init(void) {
//__HAL_RCC_SPI3_CLK_ENABLE();
RCC->APB1ENR1 |= RCC_APB1ENR1_SPI3EN;// SPI3 clock enable
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOCEN;// GPIOC clock enable
/** CS & DC GPIO signals configuration
PC8 ------> LCD_CS_PIN
PC11 ------> LCD_DC_PIN
*/
GPIOC->BSRR = LCD_CS_PIN | (LCD_DC_PIN << 16);//CS à 1 et DC à 0
GPIOC->MODER |= (1 << 16) | (1 << 22);//GPIO out
GPIOC->MODER &= ~((1 << 17) | (1 << 23));//mise à 0
GPIOC->OTYPER &= (GPIO_OTYPER_OT8 | GPIO_OTYPER_OT11);//PC8 & 11 en PP
GPIOC->OSPEEDR |= (3 << 16) | (3 << 22);//High speed
/**SPI3 GPIO Configuration
PC10 ------> SPI3_SCK
PC12 ------> SPI3_MOSI */
GPIOC->AFR[1] |= (6 << 8) | (6 << 16);//PC10 en AF6 : SPI3_SCK, PC12 en AF6 : SPI3_MOSI
GPIOC->AFR[1] &= 0xFFF6F6FF;//Mise à 0
GPIOC->MODER |= (2 << 20) | (2 << 24);//MODE AF
GPIOC->MODER &= 0xFEEFFFFF;//Mise à 0
GPIOC->OTYPER &= (GPIO_OTYPER_OT10 | GPIO_OTYPER_OT12);//PC10 & 12 en PP
GPIOC->OSPEEDR |= (3 << 24) | (3 << 20);//High speed
/*Configure module SPI3*/
SPI3->CR1 = SPI_CR1_SSM | SPI_CR1_SSI;//CS soft, SSI à 1 sinon decl. mode fault
SPI3->CR1 |= SPI_CR1_MSTR;// 0 sauf SPE et mode Master, BR = 0 => /2=> Fsck=40M
SPI3->CR2 = 0x0700 | SPI_CR2_FRXTH;// | SPI_CR2_NSSP; //mode 8 bits, ITs disabled, no DMA, FRXTH doit être à 1 en 8 bits
SPI3->CR1 |= SPI_CR1_SPE;
}
/* Send command (char) to LCD via SPI bus */
void LCD_Write_Command(uint8_t Command) {
CMD
;
//CS_ON;
while ((SPI1->SR & SPI_SR_TXE) != 0);// Waiting for TX register to be available.
*(uint8_t*) (SPI1_DR_ADR) = Command;// Cast sur pointeur, pour ecriture 8 bits. Sinon l'acces 16 bits provoque un tfert 16 bits
//while ((SPI1->SR & SPI_SR_BSY) != 0); //Attendre fin envoi trame (cf RM P1289)
//CS_OFF;
}
/* Send Data (char) to LCD via SPI bus */
void LCD_Write_Data(uint8_t Data) {
DATA
;
//CS_ON;
while ((SPI1->SR & SPI_SR_TXE) != 0);// Waiting for TX register to be available.
*(uint8_t*) (SPI1_DR_ADR) = Data;
//while ((SPI1->SR & SPI_SR_BSY) != 0); //Attendre fin envoi trame (cf RM P1289)
//CS_OFF;
}
/* 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) {
LCD_Write_Command(0x2A);
LCD_Write_Data(X1 >> 8);
LCD_Write_Data(X1);
LCD_Write_Data(X2 >> 8);
LCD_Write_Data(X2);
LCD_Write_Command(0x2B);
LCD_Write_Data(Y1 >> 8);
LCD_Write_Data(Y1);
LCD_Write_Data(Y2 >> 8);
LCD_Write_Data(Y2);
LCD_Write_Command(0x2C);
}
/*HARDWARE RESET*/
//Reset n'est pas cable sur aff ADA1983
// void LCD_Reset(void)
// {
// HAL_GPIO_WritePin(LCD_RST_PORT, LCD_RST_PIN, GPIO_PIN_SET);
// HAL_Delay(200);
// CS_ON;
// HAL_Delay(200);
// HAL_GPIO_WritePin(LCD_RST_PORT, LCD_RST_PIN, GPIO_PIN_SET);
// }
/*Ser rotation of the screen - changes x0 and y0*/
void LCD_Set_Rotation(uint8_t Rotation) {
uint8_t screen_rotation = Rotation;
LCD_Write_Command(0x36);
for (volatile uint32_t i = 0; i < TEMPO1MS_80M; i++);//~1ms attente
switch (screen_rotation) {
case SCREEN_VERTICAL_1:
LCD_Write_Data(0x40 | 0x08);
LCD_WIDTH = 240;
LCD_HEIGHT = 320;
break;
case SCREEN_HORIZONTAL_1:
LCD_Write_Data(0x20 | 0x08);
LCD_WIDTH = 320;
LCD_HEIGHT = 240;
break;
case SCREEN_VERTICAL_2:
LCD_Write_Data(0x80 | 0x08);
LCD_WIDTH = 240;
LCD_HEIGHT = 320;
break;
case SCREEN_HORIZONTAL_2:
LCD_Write_Data(0x40 | 0x80 | 0x20 | 0x08);
LCD_WIDTH = 320;
LCD_HEIGHT = 240;
break;
default:
//EXIT IF SCREEN ROTATION NOT VALID!
break;
}
}
/*Enable LCD display*/
//Reset n'est pas cable sur aff ADA1983
// void LCD_Enable(void)
// {
// HAL_GPIO_WritePin(LCD_RST_PORT, LCD_RST_PIN, GPIO_PIN_SET);
// }
/*Initialize LCD display*/
void LCD_Init(void) {
volatile uint32_t i;//Boucle att
//Reset n'est pas cable sur aff ADA1983
//LCD_Enable();
LCD_SPI_Init();
//LCD_Reset();
//SOFTWARE RESET
LCD_Write_Command(0x01);
for (i = 0; i < (1000 * TEMPO1MS_80M); i++);// ~1s sleep @80M
//POWER CONTROL A -- command not existing
// LCD_Write_Command(0xCB);
// LCD_Write_Data(0x39);
// LCD_Write_Data(0x2C);
// LCD_Write_Data(0x00);
// LCD_Write_Data(0x34);
// LCD_Write_Data(0x02);
//POWER CONTROL B -- command not existing
// LCD_Write_Command(0xCF);
// LCD_Write_Data(0x00);
// LCD_Write_Data(0xC1);
// LCD_Write_Data(0x30);
//DRIVER TIMING CONTROL A -- Display Output Ctrl Adjust
LCD_Write_Command(0xE8);
LCD_Write_Data(0x85);
LCD_Write_Data(0x00);
LCD_Write_Data(0x78);
//DRIVER TIMING CONTROL B -- command not existing
// LCD_Write_Command(0xEA);
// LCD_Write_Data(0x00);
// LCD_Write_Data(0x00);
//POWER ON SEQUENCE CONTROL -- command not existing
// LCD_Write_Command(0xED);
// LCD_Write_Data(0x64);
// LCD_Write_Data(0x03);
// LCD_Write_Data(0x12);
// LCD_Write_Data(0x81);
//PUMP RATIO CONTROL -- command not existing
// LCD_Write_Command(0xF7);
// LCD_Write_Data(0x20);
//POWER CONTROL,VRH[5:0] -- Power Control 1
LCD_Write_Command(0xC0);
LCD_Write_Data(0x23);
//POWER CONTROL,SAP[2:0];BT[3:0] -- Power Control 2
LCD_Write_Command(0xC1);
LCD_Write_Data(0x10);
//VCM CONTROL -- VCOM Control
LCD_Write_Command(0xC5);
LCD_Write_Data(0x3E);
LCD_Write_Data(0x28);
//VCM CONTROL 2
LCD_Write_Command(0xC7);
LCD_Write_Data(0x86);
//MEMORY ACCESS CONTROL
LCD_Write_Command(0x36);
LCD_Write_Data(0x48);
//PIXEL FORMAT
LCD_Write_Command(0x3A);
LCD_Write_Data(0x55);
//FRAME RATIO CONTROL, STANDARD RGB COLOR
LCD_Write_Command(0xB1);
LCD_Write_Data(0x00);
LCD_Write_Data(0x18);
//DISPLAY FUNCTION CONTROL
LCD_Write_Command(0xB6);
LCD_Write_Data(0x08);
LCD_Write_Data(0x82);
LCD_Write_Data(0x27);
//3GAMMA FUNCTION DISABLE
LCD_Write_Command(0xF2);
LCD_Write_Data(0x00);
//GAMMA CURVE SELECTED
LCD_Write_Command(0x26);
LCD_Write_Data(0x01);
//POSITIVE GAMMA CORRECTION
LCD_Write_Command(0xE0);
LCD_Write_Data(0x0F);
LCD_Write_Data(0x31);
LCD_Write_Data(0x2B);
LCD_Write_Data(0x0C);
LCD_Write_Data(0x0E);
LCD_Write_Data(0x08);
LCD_Write_Data(0x4E);
LCD_Write_Data(0xF1);
LCD_Write_Data(0x37);
LCD_Write_Data(0x07);
LCD_Write_Data(0x10);
LCD_Write_Data(0x03);
LCD_Write_Data(0x0E);
LCD_Write_Data(0x09);
LCD_Write_Data(0x00);
//NEGATIVE GAMMA CORRECTION
LCD_Write_Command(0xE1);
LCD_Write_Data(0x00);
LCD_Write_Data(0x0E);
LCD_Write_Data(0x14);
LCD_Write_Data(0x03);
LCD_Write_Data(0x11);
LCD_Write_Data(0x07);
LCD_Write_Data(0x31);
LCD_Write_Data(0xC1);
LCD_Write_Data(0x48);
LCD_Write_Data(0x08);
LCD_Write_Data(0x0F);
LCD_Write_Data(0x0C);
LCD_Write_Data(0x31);
LCD_Write_Data(0x36);
LCD_Write_Data(0x0F);
//EXIT SLEEP
LCD_Write_Command(0x11);
for (i = 0; i < (120 / TEMPO1MS_80M); i++); // ~120ms sleep
//TURN ON DISPLAY
LCD_Write_Command(0x29);
//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 Colour, uint32_t Size) {
short bufColour;
// On envoie la même couleur sur Size pixels
bufColour = Colour >> 8;// pour le tfert dans DR en 1 seul write mais
bufColour |= Colour << 8;// en mode 8 bits, il faut inverser les octets MSB/LSB
DATA
;
CS_ON;
for (uint32_t j = 0; j < Size; j++) {
while ((SPI3->SR & SPI_SR_TXE) == 0);//Si FIFO full (TX buffer Empty=0), on attend
SPI3->DR = bufColour;
}
while ((SPI3->SR & SPI_SR_BSY) != 0);//Attendre fin envoi trame
CS_OFF;
}
//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 Colour) {
LCD_Set_Address(0, 0, LCD_WIDTH, LCD_HEIGHT);
LCD_Draw_Colour_Burst(Colour, LCD_WIDTH * LCD_HEIGHT);
}
//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;
}