Top.Mail.Ru
Уведомления
Очистить все

[Решено] TFT дисплей ILI9341. SPI

Страница 3 / 6
 stm
(@stm)
Level 4
Мой драйвер был тоже рабочий)))
Но была одна ошибка.
Я забыл отправить Memory_Write перед заполнением дисплея цветом.
)))наконец
Полный код такой:
 
#define Software_Reset 0x01
#define Power_Control_A 0xCB
#define Power_Control_B 0xCF
#define Driver_Timing_Control_A 0xE8
#define Driver_Timing_Control_B 0xEA
#define Power_On_Sequence_Control 0xED
#define Pump_Ratio_Control 0xF7
#define Power_Control_1 0xC0
#define Power_Control_2 0xC1
#define VCOM_Control_1 0xC5
#define VCOM_Control_2 0xC7
#define Memory_Access_Control 0x36
#define Pixel_Format_Set 0x3A
#define Frame_Rate_Control 0xB1
#define Display_Function_Control 0xB6
#define Enable_3G 0xF2
#define Column_Address_Set 0x2A
#define Page_Address_Set 0x2B
#define Gamma_Set 0x26
#define Positive_Gamma_Correction 0xE0
#define Negative_Gamma_Correction 0xE1
#define Sleep_Out 0x11
#define Display_ON 0x29
#define Memory_Write 0x2C


#define TFT_DC_SET()          HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
#define TFT_DC_RESET()        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
#define TFT_RST_SET()         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
#define TFT_RST_RESET()       HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
#define TFT_CS_SET()          HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
#define TFT_CS_RESET()        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);


void TFT_SendCommand(uint8_t command) 
{
  TFT_DC_RESET();
  TFT_CS_RESET();
  HAL_SPI_Transmit(&hspi2, &command,1,1000);
  TFT_CS_SET();
}


void TFT_SendData(uint8_t data) 
{
  TFT_DC_SET();
  TFT_CS_RESET();
  HAL_SPI_Transmit(&hspi2, &data,1,1000);
  TFT_CS_SET();
}


void TFT_SetCursorPosition(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) 
{
  TFT_SendCommand(Column_Address_Set);
  TFT_SendData(x1 >> 8);
  TFT_SendData(x1 & 0xFF);
  TFT_SendData(x2 >> 8);
  TFT_SendData(x2 & 0xFF);

  TFT_SendCommand(Page_Address_Set);
  TFT_SendData(y1 >> 8);
  TFT_SendData(y1 & 0xFF);
  TFT_SendData(y2 >> 8);
  TFT_SendData(y2 & 0xFF);
}


void TFT_Init()
{
  TFT_CS_RESET();
  TFT_RST_RESET();
  HAL_Delay(10);
  TFT_RST_SET();
  TFT_SendCommand(Software_Reset);
  HAL_Delay(1000);
  
  TFT_SendCommand(Power_Control_A);
  TFT_SendData(0x39);
  TFT_SendData(0x2C);
  TFT_SendData(0x00);
  TFT_SendData(0x34);
  TFT_SendData(0x02);
  TFT_SendCommand(Power_Control_B);
  TFT_SendData(0x00);
  TFT_SendData(0xC1);
  TFT_SendData(0x30);

  TFT_SendCommand(Driver_Timing_Control_A);
  TFT_SendData(0x85);
  TFT_SendData(0x00);
  TFT_SendData(0x78);
  TFT_SendCommand(Driver_Timing_Control_B);
  TFT_SendData(0x00);
  TFT_SendData(0x00);
  TFT_SendCommand(Power_On_Sequence_Control);
  TFT_SendData(0x64);
  TFT_SendData(0x03);
  TFT_SendData(0x12);
  TFT_SendData(0x81);
  TFT_SendCommand(Pump_Ratio_Control);
  TFT_SendData(0x20);
  TFT_SendCommand(Power_Control_1);
  TFT_SendData(0x23);
  TFT_SendCommand(Power_Control_2);
  TFT_SendData(0x10);

  TFT_SendCommand(VCOM_Control_1);
  TFT_SendData(0x3E);
  TFT_SendData(0x28);
  TFT_SendCommand(VCOM_Control_2);
  TFT_SendData(0x86);
  TFT_SendCommand(Memory_Access_Control);
  TFT_SendData(0x48);
  TFT_SendCommand(Pixel_Format_Set);
  TFT_SendData(0x55);
  TFT_SendCommand(Frame_Rate_Control);
  TFT_SendData(0x00);
  TFT_SendData(0x18);
  TFT_SendCommand(Display_Function_Control);
  TFT_SendData(0x08);
  TFT_SendData(0x82);
  TFT_SendData(0x27);
  TFT_SendCommand(Enable_3G);
  TFT_SendData(0x00);

  TFT_SendCommand(Column_Address_Set);
  TFT_SendData(0x00);
  TFT_SendData(0x00);
  TFT_SendData(0x00);
  TFT_SendData(0xEF);
  TFT_SendCommand(Page_Address_Set);
  TFT_SendData(0x00);
  TFT_SendData(0x00);
  TFT_SendData(0x01);
  TFT_SendData(0x3F);

  TFT_SendCommand(Gamma_Set);
  TFT_SendData(0x01);
  TFT_SendCommand(Positive_Gamma_Correction);
  TFT_SendData(0x0F);
  TFT_SendData(0x31);
  TFT_SendData(0x2B);
  TFT_SendData(0x0C);
  TFT_SendData(0x0E);
  TFT_SendData(0x08);
  TFT_SendData(0x4E);
  TFT_SendData(0xF1);
  TFT_SendData(0x37);
  TFT_SendData(0x07);
  TFT_SendData(0x10);
  TFT_SendData(0x03);
  TFT_SendData(0x0E);
  TFT_SendData(0x09);
  TFT_SendData(0x00);
  TFT_SendCommand(Negative_Gamma_Correction);
  TFT_SendData(0x00);
  TFT_SendData(0x0E);
  TFT_SendData(0x14);
  TFT_SendData(0x03);
  TFT_SendData(0x11);
  TFT_SendData(0x07);
  TFT_SendData(0x31);
  TFT_SendData(0xC1);
  TFT_SendData(0x48);
  TFT_SendData(0x08);
  TFT_SendData(0x0F);
  TFT_SendData(0x0C);
  TFT_SendData(0x31);
  TFT_SendData(0x36);
  TFT_SendData(0x0F);
  TFT_SendCommand(Sleep_Out);
  
  HAL_Delay(100);
  TFT_SendCommand(Display_ON);
  HAL_Delay(100);
  //---------------------------
  TFT_SendCommand(0x36);
  TFT_SendData(72);
  TFT_SendCommand(Memory_Write);
}


int main()
{
  TFT_Init();
  TFT_SetCursorPosition(0,0,239,319);


  TFT_SendCommand(Memory_Write); //Memory_Write


  for(int i=0; i<(239*319); i++)
  {
    TFT_SendData(0xbb);
    TFT_SendData(0xbb);
  }
}
ОтветитьЦитата
Создатель темы Размещено : 11.10.2023 21:28
 stm
(@stm)
Level 4

Совершенно не понимаю зачем в инициализации выставляется адрес курсора:

TFT_SendCommand(Column_Address_Set);
TFT_SendData(0x00);
TFT_SendData(0x00);
TFT_SendData(0x00);
TFT_SendData(0xEF);
TFT_SendCommand(Page_Address_Set);
TFT_SendData(0x00);
TFT_SendData(0x00);
TFT_SendData(0x01);
TFT_SendData(0x3F);

Действие никакое не производится с этими данными курсора.
Если этот код убрать, то ничего не изменится.

ОтветитьЦитата
Создатель темы Размещено : 11.10.2023 21:32
 stm
(@stm)
Level 4

Это тоже какая то ерунда

TFT_SendCommand(0x36);
TFT_SendData(0x48);
TFT_SendCommand(Memory_Write);

Не нужно при инициализации.
TFT_SendCommand(0x36); вообще повторение Memory Access Control.

ОтветитьЦитата
Создатель темы Размещено : 11.10.2023 22:41
 stm
(@stm)
Level 4

TFT_CS_RESET(); в самом начале TFT_Init тоже не нужен.
Все действия с чип селектом находятся в функциях, например в TFT_SendCommand.
В начале надо просто сбросить дисплей
Сначала аппаратный резет

TFT_RST_RESET();
HAL_Delay(10);
TFT_RST_SET();

Потом программный резет.

TFT_SendCommand(Software_Reset);
HAL_Delay(1000);

Или надо сначала выбрать чип CS, чтоб на нём сделать аппаратный сброс?

ОтветитьЦитата
Создатель темы Размещено : 11.10.2023 23:18
 stm
(@stm)
Level 4

Непонятно с этим TFT_CS_RESET(); вначале TFT_Init.
Я видел драйверы где стоит TFT_CS_RESET(); видел драйверы где стоит TFT_CS_SET();
На яндекс диске TFT_CS_SET();
Непонятно зачем он нужен здесь.

ОтветитьЦитата
Создатель темы Размещено : 11.10.2023 23:39
 stm
(@stm)
Level 4

Проверил.
Аппаратный RESET срабатывает и с выбранным чипом TFT_CS_RESET(); и без выбранного чипа TFT_CS_SET();
То есть всё равно. Выбор чипа для аппаратного сброса не нужен.
Присутствие "TFT_CS_RESET();" в начале TFT_Init непонятно.

ОтветитьЦитата
Создатель темы Размещено : 12.10.2023 00:06
(@eduard)
Level 5 Moderator
От: @stm

Присутствие "TFT_CS_RESET();" в начале TFT_Init непонятно.

Бывает люди пишут. Пробуют. Потом убрать забывают.

ОтветитьЦитата
Размещено : 12.10.2023 19:33
 stm
(@stm)
Level 4

TFT_RST_SET();
Это обязательно для запуска дисплея.
TFT_RST_RESET(); не обязательно, но желательно.
---------------------------
Чаще всего я видел это
TFT_CS_SET();
Может это тоже необходимо. Ну стандартное состояние дисплея, когда CS не выбран и дисплей находится в бездействии.
Сейчас мне кажется, что это просто для порядка надо.
Во всех драйверах это пишут, не думаю, что везде забыли убрать.

А вот для чего пишут Column_Address_Set и Page_Address_Set в инициализации, мне непонятно.
Может это надо для гаммы цветов, ну на какой области надо применить настройки гаммы цветов.

Например команда Memory Write использует всё доступное пространство, которое было выбрано координатами курсора.
Но если убрать из инициализации Column_Address_Set и Page_Address_Set, то ничего не изменится.
Не во всех драйверах есть Column_Address_Set и Page_Address_Set, но в некоторых видел.
Может если нет Column_Address_Set и Page_Address_Set, то идёт как то автоматическое определение границ дисплея, а если есть Column_Address_Set и Page_Address_Set, то границы дисплея указываются для настроек гаммы цветов.
Ведь сразу после Column_Address_Set и Page_Address_Set идёт команда Gamma_Set.

ОтветитьЦитата
Создатель темы Размещено : 12.10.2023 19:57
(@eduard)
Level 5 Moderator
От: @stm

команда Gamma_Set

Гамма применяется для TFT матрицы. На "окно" влиять не должна.

https://microtechnics.ru/profilegrid_blogs/rabota-s-tft-displeyami-na-primere-kontrollera-ili9341/

 

ОтветитьЦитата
Размещено : 12.10.2023 20:24
 stm
(@stm)
Level 4
Да, что то подобное есть, а может и полностью как я описал.
Я проверил работу Column_Address_Set и Page_Address_Set на команде Memory Write.
Если перед заполнением дисплея цветом, перед командой Memory Write указать координаты Column_Address_Set и Page_Address_Set, то происходит всё как обычно, заполняется тот участок, который указали.
200х200 это часть дисплея, не весь дисплей.
  TFT_SetCursorPosition(0,0,200,200);
TFT_SendCommand(Memory_Write);
  for(int i=0; i<(239*319); i++)
{
TFT_SendData(0x68);
TFT_SendData(0x97);
  }
1
 
А следующее интереснее:
Если НЕ указывать перед Memory Write координаты Column_Address_Set и Page_Address_Set, то заполняется весь дисплей.
То есть координаты начала и конца дисплея как то распознаются.
TFT_SendCommand(Memory_Write);
  for(int i=0; i<(239*319); i++)
{
TFT_SendData(0x68);
TFT_SendData(0x97);
  }
2

Количество заполняемых пикселей здесь определяется циклом for(int i=0; i<(239*319); i++)

ОтветитьЦитата
Создатель темы Размещено : 12.10.2023 20:29
(@eduard)
Level 5 Moderator

@stm Если я не ошибаюсь, если после инициализации не вводить "окно", оно равно левому верхнему углу и правому нижнему.
Если указать окно 10х10 и записать 100 раз цвет, а после этого 50 раз другой, то прорисовка будет в том же окне. И мы должны получить нижнюю половину квадрата первым цветом, верхнюю вторым.

Проверить нужно.

ОтветитьЦитата
Размещено : 12.10.2023 20:35
 stm
(@stm)
Level 4

Можно было бы проверить влияет ли Column_Address_Set и Page_Address_Set на команды Gamma_Set, Positive_Gamma_Correction, Negative_Gamma_Correction.
Но проблема в том, что я не вижу разницы если я вообще удалю Gamma_Set, Positive_Gamma_Correction, Negative_Gamma_Correction из кода.
Если б что то менялось при удалении Gamma_Set, Positive_Gamma_Correction, Negative_Gamma_Correction, то можно было бы проверить влияние Column_Address_Set и Page_Address_Set на гамму.

ОтветитьЦитата
Создатель темы Размещено : 12.10.2023 21:40
 stm
(@stm)
Level 4

Я изменил параметры Positive_Gamma_Correction, Negative_Gamma_Correction так что цвета дисплея изменились.
Column_Address_Set и Page_Address_Set не влияют на Positive_Gamma_Correction, Negative_Gamma_Correction.

Но если Column_Address_Set и Page_Address_Set нужны, то думаю они нужны для команды Gamma_Set.
А при изменении параметров этой команды ничего на дисплее не меняется.
Проверить не могу необходимы ли для Gamma_Set координаты курсора.

ОтветитьЦитата
Создатель темы Размещено : 12.10.2023 22:08
 stm
(@stm)
Level 4

https://microtechnics.ru/profilegrid_blogs/rabota-s-tft-displeyami-na-primere-kontrollera-ili9341/
>если что, регистры этого контроллера 18-ти битные
Я тоже заметил в докумментации, что биты идут от D0 до D17

indukt2

Допустим при передаче данных дисплею командой Memory Write
Я передаю ПАРАМЕТРЫ для команды Memory Write через SPI, эти параметры должны заполнить полностью весь регистр от D0 до D17.

Пространство для кодирования пикселя 16 битное, а регистр 18 битный? Это как?

ОтветитьЦитата
Создатель темы Размещено : 12.10.2023 22:49
(@eduard)
Level 5 Moderator

Я об этом в статье писал.
В командах используется только 8 бит.
Остальные отбрасываются.
В заполнении экрана цветом используется от 3х, до 18 бит.
Потому регистры там и 18 битные.

ОтветитьЦитата
Размещено : 13.10.2023 20:13
Страница 3 / 6
Поделиться: