712 lines
19 KiB
C
712 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)
|
||
{
|
||
// 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 d’attendre la fin complète de l’envoi 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;
|
||
}
|
||
|