Каталог статей
Сайт создан в системе uCoz
Приветствую Вас, Пробегающий мимо · RSS 25.04.2024, 20:06
Главная » Статьи » Статьи » Микроконтроллеры

STM32F100 в навесок к TFT LCD 240x400 HX8352
Прикручиваем STM32 к TFT дисплею на основе контроллера HX8352






Вот решил испытать как оно будет работать, ну и заодно поделится авось кому интересно :) Значится так, подключаем мы этот TFT по 8-ми битной шине, ага, совсем забыл уточнить модель LCD, вот он - 3.2-st032d6c-e00. Ну приступим, схема подключения очень простая и поэтому схему не привожу да и нет ее у меня, не рисовал :) Шина данных ЖК подключается на выводы PA0-PA7, остальное в таком порядке:

CS - PC5
RS - PB0
WR - PB9
RD - PC4
RESET - PB1

Распиновку  LCD можно посмотреть по линку который я привел выше, даташит на контроллер тоже там. Ну вот, подключили. Теперь начинаем писать чудо программу в IAR, я пропущу создание проекта так как это очень хорошо расписано тут - STM32-VLDiscovery: мой вариант быстрого старта.  Далее настраиваем выводы как нам нужно:

PA.0-PA.7 на выход - GPIOA->CRL = 0x11111111;  //PORTA.0-PORTA.7 Push-pull output 10MHz

ну и остальные тоже все на выход включая контрольный светодиод, кстати про GPIO очень просто и понятно написано сдесь и там же.

/* lcd command signals*/
  GPIOB->CRL = 0x00000011;  //PORTB.0,1 Push-pull
output 10MHz    (RS, RESET)
  GPIOB->CRH = 0x00000010;  //PORTB.9 Push-pull output 10MHz      (WR)
  GPIOC->CRL = 0x00110000;  //PORTC.4,5 Push-pull output 10MHz    (RD, CS)
 
  /* leds*/
  GPIOC->CRH = 0x00000011;  //PORTC.4,5 Push-pull
output 10MHz




Собственно код, main.c:


#include "stm32f10x.h"
#include "hx8352.c"


#define uchar unsigned char
#define uint unsigned int
#define ushort unsigned short



void Init_GPIO(void)
{
  //Enabling clock for GPIO A,B,C 
  RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;
  RCC->APB2ENR|=RCC_APB2ENR_IOPBEN;
  RCC->APB2ENR|=RCC_APB2ENR_IOPCEN; 
 
  /* lcd data port */
  GPIOA->CRL = 0x11111111;  //PORTA.0-PORTA.7 Push-pull output 10MHz
 
  /* lcd command signals*/
  GPIOB->CRL = 0x00000011;  //PORTB.0,1 Push-pull
output 10MHz
  GPIOB->CRH = 0x00000010;  //PORTB.9 Push-pull output 10MHz
  GPIOC->CRL = 0x00110000;  //PORTC.4,5 Push-pull output 10MHz
 
  /* leds*/
  GPIOC->CRH = 0x00000011;  //PORTC.4,5 Push-pull
output 10MHz
}


void Global_Init(void)
{
  Init_GPIO();
}


void main(void)
{
  uchar color_indx;
  ushort y = 0;
 
  Global_Init();
 
  LCD_Init();
 
  while(1)
  {
    //switching the LED 
    GPIOC->BSRR=GPIO_BSRR_BR9;    //set 0
   
    LCD_FillScreen(M256_Colors[
color_indx]);       
   
color_indx += 1;   
   
    //switching the LED   
    GPIOC->BSRR=GPIO_BSRR_BS9;     //set 1   
   
    LCD_FillScreen(M256_Colors[
color_indx]);   
   
color_indx += 1;

    if(color_indx%10 == 0)
    {
      GPIOC->BSRR=GPIO_BSRR_BS8;
    }
    else GPIOC->BSRR=GPIO_BSRR_BR8;

   }   
}




-------------------------------------------------------------------------------------------------------------------------------------

Код hx8352.c :

/*************************************************************************************
Project : HX8352 Driver
Version : 1.0
Author  : Left Radio                         
Comments:

Chip type           :
Program type        : Application
Clock frequency     : 24,000000 MHz
**************************************************************************************/


#include "colors 5-6-5.h"

#define uchar unsigned char
#define uint unsigned int
#define ushort unsigned short

#define LCD_DATA GPIOA->ODR

#define RES_LCD_set GPIOB->BSRR=GPIO_BSRR_BS1
#define RES_LCD_clr GPIOB->BSRR=GPIO_BSRR_BR1

#define RD_LCD_set GPIOC->BSRR=GPIO_BSRR_BS4
#define RD_LCD_clr GPIOC->BSRR=GPIO_BSRR_BR4

#define RS_LCD_set GPIOB->BSRR=GPIO_BSRR_BS0
#define RS_LCD_clr GPIOB->BSRR=GPIO_BSRR_BR0

#define WR_LCD_set GPIOB->BSRR=GPIO_BSRR_BS9
#define WR_LCD_clr GPIOB->BSRR=GPIO_BSRR_BR9

#define CS_LCD_clr GPIOC->BSRR=GPIO_BSRR_BS5
#define CS_LCD_set GPIOC->BSRR=GPIO_BSRR_BR5


void RESET_LCD(void);
void LCD_Init(void);

void Set_LCD_8B_REG(uchar index, uchar data_lcd);
void LCD_Write_Index(uchar index);
void LCD_Write_Data(uchar data_lcd);
void LCD_16B_Write_Data(ushort data_lcd);
void LCD_SetCursor(uchar x, ushort y);
void LCD_FillScreen(uint color);

void LCD_SetArea(uchar x0, ushort y0, uchar x1, ushort y1);
void clear_area(uchar x0, ushort y0, uchar x1, ushort y1, uint color);

void Delay_ms (uint mS);

/* -------------------------------------------------------------------------------- */

volatile ushort TextColor;
volatile ushort BkColor;
volatile ushort graf_color;

volatile unsigned long d;

/* -------------------------------------------------------------------------------- */


void RESET_LCD(void)
{
  RES_LCD_set;
  Delay_ms(5);
  RES_LCD_clr;               //Reset chip
  Delay_ms(10);
  RES_LCD_set;
  Delay_ms(50);
}

void LCD_Init(void)
{
   RD_LCD_set;
   RS_LCD_set;

   RESET_LCD();    
  
   Set_LCD_8B_REG(0x83,0x02); // TESTM=1
   Set_LCD_8B_REG(0x85,0x03); // VDC_SEL=011.
   Set_LCD_8B_REG(0x8C,0x93); // STBA[7]=1, STBA[5:4]=01, STBA[1:0]=11
   Set_LCD_8B_REG(0x91,0x01); // DCDC_SYNC=1
   Set_LCD_8B_REG(0x83,0x00); // TESTM=0
   //--------------------------------------------------------------------------------
   // Gamma Setting
   Set_LCD_8B_REG(0x3E,0xB0);
   Set_LCD_8B_REG(0x3F,0x03);
   Set_LCD_8B_REG(0x40,0x10);
   Set_LCD_8B_REG(0x41,0x56);
   Set_LCD_8B_REG(0x42,0x13);
   Set_LCD_8B_REG(0x43,0x46);
   Set_LCD_8B_REG(0x44,0x23);
   Set_LCD_8B_REG(0x45,0x76);
   Set_LCD_8B_REG(0x46,0x00);
   Set_LCD_8B_REG(0x47,0x5E);
   Set_LCD_8B_REG(0x48,0x4F);
   Set_LCD_8B_REG(0x49,0x40);
   //--------------------------------------------------------------------------------
   // Power Supply Setting
   Set_LCD_8B_REG(0x17,0x01); // RADJ=0110(145%), OSC_EN=1
   Set_LCD_8B_REG(0x2B,0xF9); // N_DCDC=0xF9.
   Delay_ms(10);
   Set_LCD_8B_REG(0x1B,0x14); // BT=0001, AP=100
   Set_LCD_8B_REG(0x1A,0x11); // VC3=001, VC1=001
   Set_LCD_8B_REG(0x1C,0x0d); // VRH=1101
   Set_LCD_8B_REG(0x1F,0x3D); // VCM=100_0010
   Delay_ms(20);
   Set_LCD_8B_REG(0x19,0x0A); // GASENB=0, PON=0, DK=1, XDK=0,
   // VLCD_TRI=1, STB=0
   Set_LCD_8B_REG(0x19,0x1A); // GASENB=0, PON=1, DK=1, XDK=0,
   // VLCD_TRI=1, STB=0
   Delay_ms(40);
   Set_LCD_8B_REG(0x19,0x12); // GASENB=0, PON=1, DK=0, XDK=0,
   // VLCD_TRI=1, STB=0
   Delay_ms(40);
   Set_LCD_8B_REG(0x1E,0x20); // VCOMG=1, VDV=0_1100
   Delay_ms(100);
   //--------------------------------------------------------------------------------
   // Display ON Setting
   Set_LCD_8B_REG(0x3C,0x60); // N_SAP=0110 000
   Set_LCD_8B_REG(0x3D,0x40); // I_SAP =0100 0000
   Set_LCD_8B_REG(0x34,0x38); // EQS=0011 1000
   Set_LCD_8B_REG(0x35,0x38); // EQP=0011 1000
   Set_LCD_8B_REG(0x24,0x38); // GON=1, DTE=1, D=10
   Delay_ms(40);
   Set_LCD_8B_REG(0x24,0x3C); // GON=1, DTE=1, D=11
   Set_LCD_8B_REG(0x16,0x1C); // BGR=0
   Set_LCD_8B_REG(0x01,0x06); // INVON=0, NORNO=1
   Set_LCD_8B_REG(0x55,0x00);
   //--------------------------------------------------------------------------------       
   Set_LCD_8B_REG(0x02,0x00); // Column address start2
   Set_LCD_8B_REG(0x03,0x00); // Column address start1
   Set_LCD_8B_REG(0x04,0x00); // Column address end2
   Set_LCD_8B_REG(0x05,0xEF); // Column address end1
   Set_LCD_8B_REG(0x06,0x00); // Row address start2
   Set_LCD_8B_REG(0x07,0x00); // Row address start1
   Set_LCD_8B_REG(0x08,0x01); // Row address end2
   Set_LCD_8B_REG(0x09,0x8F); // Row address end1   
     
   LCD_Write_Index(0x22);
}



void LCD_Write_Index(uchar index)
{
 CS_LCD_set;
 RS_LCD_clr;                  //register index write active
 
 LCD_DATA = index;
 
 WR_LCD_clr;
 WR_LCD_set;
 
 RS_LCD_set;                  //register index write inactive
 CS_LCD_clr;
}

void LCD_Write_Data(uchar data_lcd)
{
 LCD_DATA = data_lcd;        //
 WR_LCD_clr;
 WR_LCD_set;
}

void Set_LCD_8B_REG(uchar index, uchar data_lcd)  
{   
  CS_LCD_set;
  RS_LCD_clr;                  //register index write active

  LCD_DATA = index;
 
  WR_LCD_clr;
  WR_LCD_set;
 
  RS_LCD_set;                  //register index write inactive
   
  LCD_DATA = data_lcd;        //
 
  WR_LCD_clr;
  WR_LCD_set;
 
  CS_LCD_clr; 
}

void LCD_16B_Write_Data(ushort data_lcd)
{
 //CS_LCD_set;
 LCD_Write_Data(data_lcd >> 8);
 LCD_Write_Data(data_lcd); 
 //CS_LCD_clr;
}

void LCD_SetCursor(uchar x, ushort y)
{
   Set_LCD_8B_REG(0x03, x); // Column start
   Set_LCD_8B_REG(0x06, y >> 8); // Row high
   Set_LCD_8B_REG(0x07, y); // Row low
        
   LCD_Write_Index(0x22);        
}


void LCD_FillScreen(uint color)
{
    long cntT = 96000;   
     
    LCD_SetCursor(0, 0);
   
    CS_LCD_set;
   
    do
    {     
      LCD_16B_Write_Data(color);     
    }
    while(cntT--);
   
    CS_LCD_clr;
}

void LCD_SetArea(uchar x0, ushort y0, uchar x1, ushort y1)
{         
    Set_LCD_8B_REG(0x02,0x00); // Column address start2
    Set_LCD_8B_REG(0x03,x0); // Column address start1
    Set_LCD_8B_REG(0x04,0x00); // Column address end2
    Set_LCD_8B_REG(0x05,x1); // Column address end1
    Set_LCD_8B_REG(0x06,y0 >> 8); // Row address start2
    Set_LCD_8B_REG(0x07,y0); // Row address start1
    Set_LCD_8B_REG(0x08,y1 >> 8); // Row address end2
    Set_LCD_8B_REG(0x09,y1); // Row address end1 
           
    LCD_Write_Index(0x22);
}

void clear_area(uchar x0, ushort y0, uchar x1, ushort y1, uint color)
{
   long a_r_byte = 0;   //12000;     
   ushort temp = 0, temp1 = 0;
  
   temp = (x1-x0)+1;
   temp1 =  (y1-y0)+1;  
   a_r_byte = temp*temp1;
  

   LCD_SetArea(x0, y0, x1, y1);  
  
   CS_LCD_set;
   do
   {   
     LCD_16B_Write_Data(color);
   }
   while(a_r_byte--);  
   CS_LCD_clr;
}

void Delay_ms (uint mS)
{   
   for (d = 0; d<(mS * 25000); ++d);
}


----------------------------------------------------------------------------------------------

Поехали дальше, после инициализации портов ввода/вывода нужно проинициализировать сам ЖК, это делает функция LCD_Init(void),
расписывать ее не буду, кто хочет сам разберется по даташиту.

Ну вот и все, осталось начать рисовать :), делается это так, устанавливаем курсор в нужную позицию дисплея - LCD_SetCursor(uchar x, ushort y), и просто посылаем байт за байтом в ЖК, контроллер в ЖК сам изменяет позицию курсора при приеме очередного 16-битного значения цвета точки, а так как у нас 8-ми битный интерфейс к ЖК, то нам приходится на одну точку посылать два байта. Считаем, 240 точек умножить на 400, получаем 96000 точек, то есть нам нужно послать 192000 байтов что бы полностью закрасить экран ЖК, что и делается в функции LCD_FillScreen(uint color), принимаемый аргумент - цвет заливки. Если же нам например требуется просто нарисовать две точки по разным координатам, то нужно установить курсор в нужную позицию для первой точки, послать два байта цвета, потом опять установить курсор на новые необходимые координаты и опять послать два байта цвета уже для этой точки.
Ага, чуть не забыл почти самое важное :), формат цвета принимаемый ЖК это 5-6-5,  5 бит на синий, 5 на красный и шесть на зеленый. Вот такая вот дискриминация по цвету даже тут :). Это на самом деле очень неудобно, например когда нужно отобразить на ЖК цвет например из граф. редактора на ПК, и после некоторых моих мучений родилась простенькая утилита для конвертации RGB(8-8-8-8, последняя восьмерка это альфа канал) в 5-6-5 для этого LCD




Скачать утилиту - RGB_to_16bit-5-6-6-convert.exe


Написана она в Visual C# от мелкософта и умеет конвертировать выбранный одиночный цвет, 256-ти цветовою гамму и 256 оттенков серого сразу генерируя, для вставки в код, массив из 256-ти значений. Если есть какие предложения по навешиванию функционала пишите, пока мне и этого вполне хватало.

Думаю на этом и остановимся, а напоследок небольшое видео, МК просто заливает одним цветом ЖК, подряд по гамме. Замечу, хоть на видео и не сильно заметны смены кадров на ЖК, но в реальности очень заметно и анимированную картинку перерисовывая весь экран получить не выйдет, точнее выйдет, но медленно, всего около 10 кадров за сек., думаю если заменить STM32F100 на STM32F103 и подключится к этому ЖК по 16-ти битной шине будет намного быстрее но бесполезно так как все равно видны смены кадров из-за асинхронности вычитки внутренней памяти контроллером ЖК и ее заполнением микроконтроллером.
На плате STM32VLDISCOVERY использован вывод PA0 так что кнопку USER использовать нельзя, так же задействованы светодиоды, зеленый горит каждый второй кадр, синий каждый десятый.

Готовый проект для STM32VLDISCOVERY под IAR - project.rar, так как это писалось сразу в расчете на новую версию осцилла, то и называется в IAR-е NeilScope3, так что не пугайтесь :)


Все, всем спасибо :) , вопросы если есть можно на форум.






Категория: Микроконтроллеры | Добавил: LeftRadio (25.07.2011)
Просмотров: 12283 | Комментарии: 6 | Рейтинг: 3.8/8
Всего комментариев: 6
1 vbox  
А проекта то нету :'(
http://hobby-research.at.ua/NS3/project.rar
Выложите пожалуйста

2 LeftRadio  
Исправил ссылку

3 vbox  
Благодарю.
У меня вот такая штука
http://www.ebay.com/itm/3-2-inch-TFT-LCD-Module-Display-Touch-Panel-SD-card-cage-/230684823376?pt=LH_DefaultDomain_0&hash=item35b5e30f50
и я собbраюсь подключить ее к STM32L-DISCOVERY board
с вашей помощью :)
Пока только подпаялся и проверил подсветку дисплея
Щас начну копаться в вашем проекте.

4 LeftRadio  
Понятно, ну если что спрашивайте :)

5 rotla  
Ссылка на RGB_to_16bit-5-6-6-convert.exe не работает!

6 LeftRadio  
Используйте Bitmap2Code, там есть функция конвертации цвета

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]