ow-dash-cube/Core/Src/LCD_driver.c
Clément Grennerat 6e6abff60c setup project
2025-08-18 21:34:19 +02:00

712 lines
19 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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)
{
// principe : on attend toujours la fin du transfert, à cause du CS_OFF soft qui arrive après.
// donc à priori pas besoin de tester l'état du buffer TX avant l'envoi :
// le buffer devrait toujours vide
CMD; //Ligne de commande a '1'
//CS_ON;
while ((SPI1->SR & SPI_SR_TXE) != 0); // SPI_SR_BSY si besoin dattendre la fin complète de lenvoi des trames SPI.
*(uint8_t *)(SPI1_DR_ADR) = Command; //Cast sur pointeur, pour ecriture 8 bits. Sinon l'acces 16 bits provoque un tfert 16 bits
//CS_OFF;
}
/* Send Data (char) to LCD via SPI bus */
void LCD_Write_Data(uint8_t Data)
{
DATA; //Ligne de data a '1'
CS_ON;
*(uint8_t *)(SPI1_DR_ADR) = Data;
while ((SPI1->SR & SPI_SR_BSY) != 0); //Attendre fin envoi trame (cf RM P1289)
CS_OFF;
}
/* Set Address - Location block - to draw into */
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 attente @80M
//POWER CONTROL A
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
LCD_Write_Command(0xCF);
LCD_Write_Data(0x00);
LCD_Write_Data(0xC1);
LCD_Write_Data(0x30);
//DRIVER TIMING CONTROL A
LCD_Write_Command(0xE8);
LCD_Write_Data(0x85);
LCD_Write_Data(0x00);
LCD_Write_Data(0x78);
//DRIVER TIMING CONTROL B
LCD_Write_Command(0xEA);
LCD_Write_Data(0x00);
LCD_Write_Data(0x00);
//POWER ON SEQUENCE CONTROL
LCD_Write_Command(0xED);
LCD_Write_Data(0x64);
LCD_Write_Data(0x03);
LCD_Write_Data(0x12);
LCD_Write_Data(0x81);
//PUMP RATIO CONTROL
LCD_Write_Command(0xF7);
LCD_Write_Data(0x20);
//POWER CONTROL,VRH[5:0]
LCD_Write_Command(0xC0);
LCD_Write_Data(0x23);
//POWER CONTROL,SAP[2:0];BT[3:0]
LCD_Write_Command(0xC1);
LCD_Write_Data(0x10);
//VCM 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 attente
//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;
}