2016年11月19日 星期六

使用Raspberry Pi 3 modelB驅動1.8 SPI TFT(st7735r)


首先先須先熟悉如何使用Raspberry Pi的GPIO腳位,並確認映射關係


圖片引用自:http://blog.mcmelectronics.com/post/Raspberry-Pi-3-GPIO-Pin-Layout#.WDAR9HE2u00


接著開始編寫操作GPIO的主要函式,這裡的程式是改寫自

elinux.org/RPi_GPIO_Code_Samples,其主要功能為,初始化GPIO、設定選定的GPIO腳位為

輸出或輸入、若是該腳位為輸出時,則可設定輸出為1或是0。需要注意的是你使用的

Raspberry Pi不是3 model B的話,可能需要更改GPIO_BASE

程式碼如下:
gpio.h
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#define GPIO_BASE                0x3f200000

#define PAGE_SIZE  (4 * 1024)
#define BLOCK_SIZE (4 * 1024)

int  mem_fd;
void *gpio_map;

/* I/O access */
volatile unsigned *gpio;
/* GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y) */
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET *(gpio+7)   /* sets   bits which are 1 ignores bits which are 0 */
#define GPIO_CLR *(gpio+10)  /* clears bits which are 1 ignores bits which are 0 */

/**
 * Set up a memory regions to access GPIO
 *
 */
void ini_gpio();
void set_gpio(int num,int in_out);//0 for in, 1 for out
void gpio_val(int num,int val);

gpio.c
#include "gpio.h"

void ini_gpio()
{
 /* open /dev/mem */
 if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
  printf("can't open /dev/mem \n");
  exit(-1);
 }

 /* mmap GPIO */
 gpio_map = mmap(
   NULL,             /* Any adddress in our space will do */
   BLOCK_SIZE,       /* Map length */
   PROT_READ|PROT_WRITE, /* Enable reading & writting to mapped memory */
   MAP_SHARED,       /* Shared with other processes */
   mem_fd,           /* File to map */
   GPIO_BASE         /* Offset to GPIO peripheral */
         );

 close(mem_fd); /* No need to keep mem_fd open after mmap */

 if (gpio_map == MAP_FAILED) {
  printf("mmap error %d\n", (int)gpio_map); /* errno also set! */
  exit(-1);
 }

 /* Always use volatile pointer! */
 gpio = (volatile unsigned *)gpio_map;
}
void set_gpio(int num,int in_out)//0 for in, 1 for out
{
 INP_GPIO(num);
 if(in_out==1)
 {
  OUT_GPIO(num);
 }
 return; 
}

void gpio_val(int num,int val)
{
 if(val==1)
 {
  GPIO_SET = 1 << num;
 }
 else
 {
  GPIO_CLR = 1 << num;
 }
 return;
}
寫完GPIO的函式後,可以先寫簡單的程式測試是否可以使用,如此範例為將led燈接上GPIO腳位的編號4:

#include "gpio.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include "gpio.h"


int main(int argc, char **argv)
{
	/* Set up gpi pointer for direct register access */
	ini_gpio();
	set_gpio(4,1);
	gpio_val(4,1);
	sleep(1);
	gpio_val(4,0);
	sleep(1);

	return 0;
}
開始編寫驅動tft螢幕的程式,參考http://forum.arduino.cc/index.php?topic=125034.0裡二樓 Arduino版本的實作st7735r的code並改寫。這裡需要注意的地方是reset, cs, scl, sda, rs對應到的GPIO標號,在這裡分別設定為GPIO編號2, 3, 4, 5, 6, 與GPIO編號對應到Raspberry Pi板子上的腳位,和Raspberry Pi的腳位對應到st7735r的腳位。 st7735r.h:
#include "gpio.h"

extern unsigned char reset;
extern unsigned char cs;
extern unsigned char scl;
extern unsigned char  sda;
extern unsigned char rs;

int bitSet(unsigned char num,int pos);
void write_command(unsigned char c);
void  write_data(unsigned char d);
void write_data_2(unsigned char LCD_DataH,unsigned char LCD_DataL);
void write_data_3(unsigned char LCD_DataH,unsigned char LCD_DataM,unsigned char LCD_DataL);
void Reset();
void lcd_initial();
void  RamAdressSet();
void dsp_single_colour(unsigned char DH,unsigned char DL);
void PutPixel(unsigned int x_start,unsigned int y_start,unsigned int color);


st7735r.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include "st7735r.h"

unsigned char reset=2;
unsigned char cs=3;
unsigned char scl=4;
unsigned char sda=5;
unsigned char rs=6;

int bitSet(unsigned char num,int pos)
{
 if((num & (int)(pow(2,pos)))>0)
 {
  return 1;
 }
 return  0;
}

void write_command(unsigned char c){
 gpio_val(cs,0);
 gpio_val(rs,0);
 gpio_val(sda,bitSet(c,7));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(c,6));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(c,5));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(c,4));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(c,3));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(c,2));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(c,1));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(c,0));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(cs,1);
}

void  write_data(unsigned char d) {

 gpio_val(cs,0);
 gpio_val(rs,1);
 gpio_val(sda,bitSet(d,7));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(d,6));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(d,5));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(d,4));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(d,3));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(d,2));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(d,1));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(sda,bitSet(d,0));
 gpio_val(scl,0);
 gpio_val(scl,1);
 gpio_val(cs,1);
}

void write_data_2(unsigned char LCD_DataH,unsigned char LCD_DataL)
{
 write_data(LCD_DataH);
 write_data(LCD_DataL);
}

void write_data_3(unsigned char LCD_DataH,unsigned char LCD_DataM,unsigned char LCD_DataL)
{
 write_data(LCD_DataH);
 write_data(LCD_DataM);
 write_data(LCD_DataL);
}

void Reset()
{
 gpio_val(reset,0);
 usleep(100000);
 gpio_val(reset,1);
 usleep(100000);
}
//////////////////////////////////////////////////////////////////////////////////////////////

void lcd_initial(){
 ini_gpio();
 set_gpio(reset,1);
 set_gpio(cs,1);
 set_gpio(scl,1);
 set_gpio(sda,1);
 set_gpio(rs,1);
 printf("start reset\n");
 Reset();
 printf("start soft reset\n");
 //------------------------------------------------------------------//  
 //-------------------Software Reset-------------------------------//
 //------------------------------------------------------------------//

 write_command(0x11);//Sleep exit 
 usleep(120000);

 //ST7735R Frame Rate
 write_command(0xB1); 
 write_data(0x01); 
 write_data(0x2C); 
 write_data(0x2D); 
 write_command(0xB2); 
 write_data(0x01); 
 write_data(0x2C); 
 write_data(0x2D); 
 write_command(0xB3); 
 write_data(0x01); 
 write_data(0x2C); 
 write_data(0x2D); 
 write_data(0x01); 
 write_data(0x2C); 
 write_data(0x2D); 

 write_command(0xB4); //Column inversion 
 write_data(0x07); 

 //ST7735R Power Sequence
 write_command(0xC0); 
 write_data(0xA2); 
 write_data(0x02); 
 write_data(0x84); 
 write_command(0xC1); 
 write_data(0xC5); 
 write_command(0xC2); 
 write_data(0x0A); 
 write_data(0x00); 
 write_command(0xC3); 
 write_data(0x8A); 
 write_data(0x2A); 
 write_command(0xC4); 
 write_data(0x8A); 
 write_data(0xEE); 

 write_command(0xC5); //VCOM 
 write_data(0x0E); 

 write_command(0x36); //MX, MY, RGB mode 
 write_data(0xC8); 

 //ST7735R Gamma Sequence
 write_command(0xe0); 
 write_data(0x0f); 
 write_data(0x1a); 
 write_data(0x0f); 
 write_data(0x18); 
 write_data(0x2f); 
 write_data(0x28); 
 write_data(0x20); 
 write_data(0x22); 
 write_data(0x1f); 
 write_data(0x1b); 
 write_data(0x23); 
 write_data(0x37); 
 write_data(0x00); 

 write_data(0x07); 
 write_data(0x02); 
 write_data(0x10); 
 write_command(0xe1); 
 write_data(0x0f); 
 write_data(0x1b); 
 write_data(0x0f); 
 write_data(0x17); 
 write_data(0x33); 
 write_data(0x2c); 
 write_data(0x29); 
 write_data(0x2e); 
 write_data(0x30); 
 write_data(0x30); 
 write_data(0x39); 
 write_data(0x3f); 
 write_data(0x00); 
 write_data(0x07); 
 write_data(0x03); 
 write_data(0x10);  

 write_command(0x2a);
 write_data(0x00);
 write_data(0x00);
 write_data(0x00);
 write_data(0x7f);
 write_command(0x2b);
 write_data(0x00);
 write_data(0x00);
 write_data(0x00);
 write_data(0x9f);

 write_command(0xF0); //Enable test command  
 write_data(0x01); 
 write_command(0xF6); //Disable ram power save mode 
 write_data(0x00); 

 write_command(0x3A); //65k mode 
 write_data(0x05); 


 write_command(0x29);//Display on
}





void  RamAdressSet(){
 write_command(0x2A);
 write_data(0x00);
 write_data(0x00);
 write_data(0x00);
 write_data(0x7f);

 write_command(0x2B);
 write_data(0x00);
 write_data(0x00);
 write_data(0x00);
 write_data(0x9f);    
}

void dsp_single_colour(unsigned char DH,unsigned char DL)
{
 unsigned char i,j;
 //RamAdressSet();
 for (i=0;i<160;i++){
  for (j=0;j<128;j++){
   write_data_2(DH,DL);
  }
 }
}

void PutPixel(unsigned int x_start,unsigned int y_start,unsigned int color)
{
 write_command(0x2a);
 write_data(x_start);
 write_data(0x5f);
 write_command(0x2b);
 write_data(y_start+0x34);
 write_data(0x7F);
 write_command(0x2c);
 write_data(color>>8);
 write_data(color&0xff);

}

test_tft.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "st7735r.h"

int main()
{
 printf("%d\n",bitSet(10,4));
 printf("%d\n",bitSet(10,3));
 lcd_initial();
 while(1)
 {
  static unsigned char i = 0;
  i += 10;
  usleep(100000);
  printf("write command\n");
  write_command(0x2C);
  dsp_single_colour(i,i);
 }
 return 0;
}