Ср ноя 22, 2017 12:15:25
TFT STM32
----------
VCC 5v
GND GND
CS PB11
RESET PB12
DC PB10
MOSI PA7
SCK PA5
LED 3v
MISO PA6
#include "main.h"
/*
Подключение экрана:
TFT STM32
----------
VCC 5v
GND GND
CS PB11
RESET PB12
DC PB10
MOSI PA7
SCK PA5
LED 3v
MISO PA6
*/
int main(void)
{
//Инициализация UART2, используется для вывода отладки
uart_init();
//Включение тактирования порта B (для DC, RST, CS)
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
//Режим output для пинов 10, 11, 12
GPIOB->MODER |= GPIO_MODER_MODE10_0|GPIO_MODER_MODE11_0|GPIO_MODER_MODE12_0;
//Скорость порта Very High speed для 10, 11, 12
GPIOB->OSPEEDR |= GPIO_OSPEEDR_OSPEED10_0|GPIO_OSPEEDR_OSPEED10_1;
GPIOB->OSPEEDR |= GPIO_OSPEEDR_OSPEED11_0|GPIO_OSPEEDR_OSPEED11_1;
GPIOB->OSPEEDR |= GPIO_OSPEEDR_OSPEED12_0|GPIO_OSPEEDR_OSPEED12_1;
//Установка подтяжки:
//Обнуление на всякий случай
GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPD10_0|GPIO_PUPDR_PUPD10_1);
GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPD11_0|GPIO_PUPDR_PUPD11_1);
GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPD12_0|GPIO_PUPDR_PUPD12_1);
//Установка подтяжки к GND (Pull-down)
GPIOB->PUPDR |= GPIO_PUPDR_PUPD10_1|GPIO_PUPDR_PUPD11_1|GPIO_PUPDR_PUPD12_1;
//Перед инициализацией SPI, устанавливаю CS в HIGH, т.е. отключаю выбор (активное состояние LOW)
GPIOB->BSRR |= GPIO_BSRR_BS11;
//Инициализация SPI
//Включить тактирование SPI1
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
//Включить тактирование порта А
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
//Включение AF5 на пинах 5,6,7
GPIOA->AFR[0] |= GPIO_AFRL_AFSEL5_0|GPIO_AFRL_AFSEL5_2;
GPIOA->AFR[0] |= GPIO_AFRL_AFSEL6_0|GPIO_AFRL_AFSEL6_2;
GPIOA->AFR[0] |= GPIO_AFRL_AFSEL7_0|GPIO_AFRL_AFSEL7_2;
//Режим альтернативной функция для PA5,PA6,PA7
GPIOA->MODER |= GPIO_MODER_MODE5_1|GPIO_MODER_MODE6_1|GPIO_MODER_MODE7_1;
//Скорость High speed
GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED5_0|GPIO_OSPEEDR_OSPEED5_1;
GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED6_0|GPIO_OSPEEDR_OSPEED6_1;
GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED7_0|GPIO_OSPEEDR_OSPEED7_1;
//Режим push-pull
GPIOA->OTYPER &= ~GPIO_OTYPER_OT5;
GPIOA->OTYPER &= ~GPIO_OTYPER_OT6;
GPIOA->OTYPER &= ~GPIO_OTYPER_OT7;
//Отключение подтяжки на PA5, PA6, PA7
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD5_0|GPIO_PUPDR_PUPD5_1);
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD6_0|GPIO_PUPDR_PUPD6_1);
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD7_0|GPIO_PUPDR_PUPD7_1);
//Режим работы по двум линиям
SPI1->CR1 &= ~SPI_CR1_BIDIMODE;
//Отключение CRC
SPI1->CR1 &= ~SPI_CR1_CRCEN;
//8-bit передача
SPI1->CR1 &= ~SPI_CR1_DFF;
//Програмное управление SS
SPI1->CR1 |= SPI_CR1_SSI|SPI_CR1_SSM;
//Режим работы SPI 0
SPI1->CR1 &= ~SPI_CR1_CPHA;
SPI1->CR1 &= ~SPI_CR1_CPOL;
//Выбор скорости /8
SPI1->CR1 &= ~SPI_CR1_BR;
SPI1->CR1 |= (SPI_CR1_BR_1);
//Установка флага Master
SPI1->CR1 |= SPI_CR1_MSTR;
//Выбор формата фрейма, какой бит передавать первым
//SPI1->CR1 |= SPI_CR1_LSBFIRST;
//Включение SPI1
SPI1->CR1 |= SPI_CR1_SPE;
//Установка CS в LOW, для выбора slave
GPIOB->BSRR |= GPIO_BSRR_BR11;
//Судя по описанию ili9341, RST активен кошда LOW.
//Т.е. для работы, нужно установить в HIGH
GPIOB->BSRR |= GPIO_BSRR_BS12;
//Экрану буду слать только команду на чтение, поэтому DC в LOW
GPIOB->BSRR |= GPIO_BSRR_BR10;
//Перед началом работы надо отправить команду SOFWARE RESET (0x1)
//Пока бит TXE не будет установлен, просто ждать
while(!(SPI1->SR & SPI_SR_TXE)){};
//Команда для чтения из экрана
SPI1->DR=0x1;
//Дисплею надо 5ms, чтобы выполнить reset, тупая пауза с запасом
for(int i=0; i < 10000000; i++);
while(1)
{
uint8_t d,f,g=0; //переменные, чтобы складывать ответы экрана
//Пока бит TXE не будет установлен, просто ждать
while(!(SPI1->SR & SPI_SR_TXE)){};
//Команда для чтения из экрана 0x4
//В ответ вернет 4 байта. В первом мусор, остальные 3 с ID
SPI1->DR=0x4;
//Сразу после отправки команды, в ответ сначала придет мусор
d=SPI1->DR;
//Чтобы получить ответ на команду, надо продолжить тактировать
//передавая 0 (NOP)
while(!(SPI1->SR & SPI_SR_TXE)){};
SPI1->DR=0;
// 1 из 3 байт ответа
d=SPI1->DR;
//Чтобы получить ответ на команду, надо продолжить тактировать
//передавая 0
while(!(SPI1->SR & SPI_SR_TXE)){};
SPI1->DR=0;
// 2 из 3 байт ответа
f=SPI1->DR;
//Чтобы получить ответ на команду, надо продолжить тактировать
//передавая 0
while(!(SPI1->SR & SPI_SR_TXE)){};
SPI1->DR=0;
// 3 из 3 байт ответа
g=SPI1->DR;
sprintf(str_buffer, "d: %02X f: %02X g: %02X \r\n",d,f,g);
uart_send_string(str_buffer);
};
};
Ср ноя 22, 2017 14:40:49
Ср ноя 22, 2017 20:39:28
#define Orient_Book 0xE8
#define Orient_Land 0x88
#define ILI9341_RESET 0x01
#define ILI9341_SLEEP_OUT 0x11
#define ILI9341_GAMMA 0x26
#define ILI9341_DISPLAY_OFF 0x28
#define ILI9341_DISPLAY_ON 0x29
#define ILI9341_COLUMN_ADDR 0x2A
#define ILI9341_PAGE_ADDR 0x2B
#define ILI9341_GRAM 0x2C
#define ILI9341_MAC 0x36
#define ILI9341_PIXEL_FORMAT 0x3A
#define ILI9341_WDB 0x51
#define ILI9341_WCD 0x53
#define ILI9341_RGB_INTERFACE 0xB0
#define ILI9341_FRC 0xB1
#define ILI9341_BPC 0xB5
#define ILI9341_DFC 0xB6
#define ILI9341_POWER1 0xC0
#define ILI9341_POWER2 0xC1
#define ILI9341_VCOM1 0xC5
#define ILI9341_VCOM2 0xC7
#define ILI9341_POWERA 0xCB
#define ILI9341_POWERB 0xCF
#define ILI9341_PGAMMA 0xE0
#define ILI9341_NGAMMA 0xE1
#define ILI9341_DTCA 0xE8
#define ILI9341_DTCB 0xEA
#define ILI9341_POWER_SEQ 0xED
#define ILI9341_3GAMMA_EN 0xF2
#define ILI9341_INTERFACE 0xF6
#define ILI9341_PRC 0xF7
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40
#define BRRED 0XFC07
#define GRAY 0X8430
#define DGRAY 0X2104
#define DARKBLUE 0X01CF
#define LIGHTBLUE 0X7D7C
#define GRAYBLUE 0X5458
#define LIGHTGREEN 0X841F
#define LGRAY 0XC618
#define LGRAYBLUE 0XA651
#define LBBLUE 0X2B12
void LCDinit(void)
{
GPIO_ResetBits(GPIOB, LCD_RESET);
Delay(10000);
GPIO_SetBits(GPIOB, LCD_RESET);
SendCMD(ILI9341_RESET);
Delay(10000);
SendCMD(ILI9341_POWERA);
SendDAT(0x39);
SendDAT(0x2C);
SendDAT(0x00);
SendDAT(0x34);
SendDAT(0x02);
SendCMD(ILI9341_POWERB);
SendDAT(0x00);
SendDAT(0xC1);
SendDAT(0x30);
SendCMD(ILI9341_DTCA);
SendDAT(0x85);
SendDAT(0x00);
SendDAT(0x78);
SendCMD(ILI9341_DTCB);
SendDAT(0x00);
SendDAT(0x00);
SendCMD(ILI9341_POWER_SEQ);
SendDAT(0x64);
SendDAT(0x03);
SendDAT(0x12);
SendDAT(0x81);
SendCMD(ILI9341_PRC);
SendDAT(0x20);
SendCMD(ILI9341_POWER1);
SendDAT(0x23);
SendCMD(ILI9341_POWER2);
SendDAT(0x10);
SendCMD(ILI9341_VCOM1);
SendDAT(0x3E);
SendDAT(0x28);
SendCMD(ILI9341_VCOM2);
SendDAT(0x86);
SendCMD(ILI9341_MAC);
SendDAT(Orient_Book); // SendDAT(0x48);
SendCMD(ILI9341_PIXEL_FORMAT);
SendDAT(0x55);
SendCMD(ILI9341_FRC);
SendDAT(0x00);
SendDAT(0x18);
SendCMD(ILI9341_DFC);
SendDAT(0x08);
SendDAT(0x82);
SendDAT(0x27);
SendCMD(ILI9341_3GAMMA_EN);
SendDAT(0x00);
SendCMD(ILI9341_COLUMN_ADDR);
SendDAT(0x00);
SendDAT(0x00);
SendDAT(0x01); // SendDAT(0x00);
SendDAT(0x3F); // SendDAT(0xEF);
SendCMD(ILI9341_PAGE_ADDR);
SendDAT(0x00);
SendDAT(0x00);
SendDAT(0x00); // SendDAT(0x01);
SendDAT(0xEF); // SendDAT(0x3F);
SendCMD(ILI9341_GAMMA);
SendDAT(0x01);
SendCMD(ILI9341_PGAMMA);
SendDAT(0x0F);
SendDAT(0x31);
SendDAT(0x2B);
SendDAT(0x0C);
SendDAT(0x0E);
SendDAT(0x08);
SendDAT(0x4E);
SendDAT(0xF1);
SendDAT(0x37);
SendDAT(0x07);
SendDAT(0x10);
SendDAT(0x03);
SendDAT(0x0E);
SendDAT(0x09);
SendDAT(0x00);
SendCMD(ILI9341_NGAMMA);
SendDAT(0x00);
SendDAT(0x0E);
SendDAT(0x14);
SendDAT(0x03);
SendDAT(0x11);
SendDAT(0x07);
SendDAT(0x31);
SendDAT(0xC1);
SendDAT(0x48);
SendDAT(0x08);
SendDAT(0x0F);
SendDAT(0x0C);
SendDAT(0x31);
SendDAT(0x36);
SendDAT(0x0F);
SendCMD(ILI9341_SLEEP_OUT);
Delay(100000);
SendCMD(ILI9341_DISPLAY_ON);
}
void SendDAT(uint8_t byteToSend)
{
GPIO_SetBits(GPIOB, LCD_RS); // data
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) {}
SPI_I2S_SendData(SPI1, byteToSend);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET) {}
}
void SendCMD(uint8_t byteToSend)
{
GPIO_ResetBits(GPIOB, LCD_RS); // comand
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) {}
SPI_I2S_SendData(SPI1, byteToSend);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET) {}
}
void LCDclr(uint16_t X, uint8_t Y, uint16_t L, uint8_t H, uint16_t color)
{
SendCMD(ILI9341_MAC);
SendDAT(Orient_Book);
SendCMD(ILI9341_COLUMN_ADDR);
SendDAT(X>>8);
SendDAT(X);
SendDAT((X+L-1)>>8);
SendDAT(X+L-1);
SendCMD(ILI9341_PAGE_ADDR);
SendDAT(0);
SendDAT(Y);
SendDAT(0);
SendDAT(Y+H-1);
SendCMD(ILI9341_GRAM);
GPIO_SetBits(GPIOB, LCD_RS); // data
for (uint32_t i = 0; i < L*H; i++) {
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) {}
SPI_I2S_SendData(SPI1, color>>8);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) {}
SPI_I2S_SendData(SPI1, color);
}
}
uint8_t ReadSPI(void)
{
while (!(SPI1->SR & SPI_SR_TXE)) {}
*((__IO uint8_t *)&SPI1->DR) = 0x00;
while (!(SPI1->SR & SPI_SR_RXNE)) {}
return (uint8_t)SPI1->DR;
}
Пт ноя 24, 2017 13:41:47
//Инициализация SPI1 на пинах PA5, PA6, PA7
//Включить тактирование SPI1
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
//Включить тактирование порта А
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
//Включение AF5 на пинах 5,6,7
GPIOA->AFR[0] |= GPIO_AFRL_AFSEL5_0|GPIO_AFRL_AFSEL5_2;
GPIOA->AFR[0] |= GPIO_AFRL_AFSEL6_0|GPIO_AFRL_AFSEL6_2;
GPIOA->AFR[0] |= GPIO_AFRL_AFSEL7_0|GPIO_AFRL_AFSEL7_2;
//Режим альтернативной функция для PA5,PA6,PA7
GPIOA->MODER |= GPIO_MODER_MODE5_1|GPIO_MODER_MODE6_1|GPIO_MODER_MODE7_1;
//Скорость High speed
GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED5_0|GPIO_OSPEEDR_OSPEED5_1;
GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED6_0|GPIO_OSPEEDR_OSPEED6_1;
GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED7_0|GPIO_OSPEEDR_OSPEED7_1;
//Режим push-pull
GPIOA->OTYPER &= ~GPIO_OTYPER_OT5;
GPIOA->OTYPER &= ~GPIO_OTYPER_OT6;
GPIOA->OTYPER &= ~GPIO_OTYPER_OT7;
//Отключение подтяжки на PA5, PA6, PA7
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD5_0|GPIO_PUPDR_PUPD5_1);
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD6_0|GPIO_PUPDR_PUPD6_1);
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD7_0|GPIO_PUPDR_PUPD7_1);
//Режим работы по двум линиям
SPI1->CR1 &= ~SPI_CR1_BIDIMODE;
//Отключение CRC
SPI1->CR1 &= ~SPI_CR1_CRCEN;
//8-bit передача
SPI1->CR1 &= ~SPI_CR1_DFF;
//Программное управление SS
SPI1->CR1 |= SPI_CR1_SSI|SPI_CR1_SSM;
//Режим работы SPI 0
SPI1->CR1 &= ~SPI_CR1_CPHA;
SPI1->CR1 &= ~SPI_CR1_CPOL;
//Выбор скорости /2
SPI1->CR1 &= ~SPI_CR1_BR;
//Установка флага Master
SPI1->CR1 |= SPI_CR1_MSTR;
//DMA на TX
SPI1->CR2 |= SPI_CR2_TXDMAEN;
//Выбор формата фрейма, какой бит передавать первым
//SPI1->CR1 |= SPI_CR1_LSBFIRST;
//Включение SPI1
SPI1->CR1 |= SPI_CR1_SPE;
void LCD_DC_set(uint8_t data){
while((SPI1->SR & SPI_SR_BSY) == 1){}; //Дождаться окончания передачи, перед изменением режима
if(data == 0){
GPIOA->BSRR |= GPIO_BSRR_BR3;
}else{
GPIOA->BSRR |= GPIO_BSRR_BS3;
};
}
void LCD_SendCommand(uint8_t data) {
LCD_DC_set(0);
spi1_send(data);
}
void LCD_SendFastData(uint8_t data) {
while((SPI1->SR & SPI_SR_TXE) == 0){};
SPI1->DR = data;
}
void LCD_SendData(uint8_t data) {
LCD_DC_set(1);
spi1_send(data);
}
void spi1_send(uint8_t data){
while((SPI1->SR & SPI_SR_TXE) == 0){};
SPI1->DR = data;
};
void LCD_Fill_dma(uint16_t color) {
LCD_SetCursorPosition(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1);
LCD_SendCommand(ILI9341_GRAM);
LCD_DC_set(1);
//Цвета у экрана 16 бит и передавать их удобнее тоже по 16 бит.
//Для этого надо переключить SPI1 в режим 16 бит
//Сначала надо выключить передачу. Я не жду тут флага BSY, поскольку перед этим устанавливал DC и там этот
//флаг проверяется.
SPI1->CR1 &= ~SPI_CR1_SPE;
//16бит
SPI1->CR1 |= SPI_CR1_DFF;
//Включаем SPI
SPI1->CR1 |= SPI_CR1_SPE;
//NDTR 16 битный регистр и значение 76800 в него не влезет. Поэтому передаем двумя кусками по 38400
DMA2_Stream3 -> NDTR = LCD_PIXEL_COUNT/2; //Количество байт для передачи
DMA2_Stream3 -> PAR = (uint32_t)&(SPI1 -> DR); //Адрес переферии
DMA2_Stream3 -> M0AR = (uint32_t)&color; //Адрес в памяти
DMA2_Stream3 -> CR |= DMA_SxCR_CHSEL_0|DMA_SxCR_CHSEL_1; //Канал 3
DMA2_Stream3 -> CR &= ~DMA_SxCR_MINC; //Инкремент в памяти не нужен, заливка будет одним цветом
DMA2_Stream3 -> CR |=DMA_SxCR_DIR_0; //Направление, из памяти в переферию
DMA2_Stream3 -> CR |=DMA_SxCR_MSIZE_0; //16 бит
DMA2_Stream3 -> CR |=DMA_SxCR_PSIZE_0; //16 бит
DMA2_Stream3 -> CR |= DMA_SxCR_EN; //Запустить копирование
while((DMA2->LISR & DMA_LISR_TCIF3) == 0) {}; //подождать окончания копирования
DMA2->LIFCR |= DMA_LIFCR_CTCIF3; //Сбросить флаг окончания
//Копирование 2 половины данных
DMA2_Stream3 -> NDTR = LCD_PIXEL_COUNT/2; //Количество байт для передачи
DMA2_Stream3 -> CR |= DMA_SxCR_EN; //Запустить копирование
while((DMA2->LISR & DMA_LISR_TCIF3) == 0) {}; //Подождать окончания копирования
DMA2->LIFCR |= DMA_LIFCR_CTCIF3; //Сбросить флаг
//После заливки экрана надо вернуть режим работы SPI в 8 бит
//Ждем пока закончится передача
while((SPI1->SR & SPI_SR_BSY) == 1){};
//Выключаю SPI, устанавливаю 8 бит, включаю SPI
SPI1->CR1 &= ~SPI_CR1_SPE;
SPI1->CR1 &= ~SPI_CR1_DFF;
SPI1->CR1 |= SPI_CR1_SPE;
}
cur_time=get_ms();
while(get_ms() - cur_time < 20000){
color=(color == 0x00F8 ? 0xF800 : 0x00F8);
LCD_Fill_dma(color);
j++;
};
cur_time=get_ms();
while(get_ms() - cur_time < 20000){
color=(color == 0x00F8 ? 0xF800 : 0x00F8);
LCD_Fill(color);
l++;
};
j=j/20;
l=l/20;
Пт ноя 24, 2017 23:31:06
Сб ноя 25, 2017 00:17:24
Вт ноя 28, 2017 15:46:44