本当は、IOエキスパンダ+キャラクタ液晶でさっくり確認するつもりだったのだけど、
ヘマしたので・・・。
今回は先に結果から どーん
Z144SN005の情報
単体 http://www.aitendo.com/product/11546
変換基板 http://www.aitendo.com/product/11663
グラフィックICはST7735Sらしい
サイズ 128x128
データシートと先人たちのライブラリもありがたく確認させてもらう
データシート https://www.crystalfontz.com/controllers/Sitronix/ST7735S
v1.3が最新?
ライブラリ https://github.com/adafruit/Adafruit-ST7735-Library
https://github.com/michal037/driver-ST7735S
接続
LCD側--------FON側
VLED--------5V
RST--------VCC(3.3V)
A0--------GPIO9 データ/コマンド切り替え
SDA--------SDO(Master Output)
SCK--------SCK
VCC--------VCC(3.3V)
CS--------GPIO12(CS#2)
GND--------GND
SPI制御
/dev/spidev0.1をioctlで制御
ネット上にサンプルいっぱいあるから省略
A0(データ/コマンド切り替え)制御
こちらはGPIOを割り当てる(sysfsというのだろうか)
https://wiki.openwrt.org/doc/hardware/port.gpio
https://elinux.org/RPi_GPIO_Code_Samples
汎用性とかありそうなので・・・。
ただし、ofstreamを使うとタイミングがずれたり出力されないことがあった
たぶん書き込み処理が最適化されてキャッシュされたりなんかだろう
あまり突き詰めたくないので、上記例の通りopen/writeを使う
ST7735S用ライブラリ
先人たちの偉業を参考に作成
現状、若干モジュールに特化してしまっている感もある
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* LibST7735S.cpp | |
* | |
* Created on: 2018/02/05 | |
* Author: adeno | |
*/ | |
#include "LibST7735S.h" | |
#define LCD_X_OFFSET 2 | |
#define LCD_Y_OFFSET 1 | |
LibST7735S::LibST7735S(int SPI_Bus, int SPI_Ce, int SPI_Speed,uint8_t SPI_Mode,int a0, int rst, | |
uint8_t width,uint8_t height) { | |
this->SPI_Bus = SPI_Bus; | |
this->SPI_Ce = SPI_Ce; | |
this->SPI_Speed = SPI_Speed; | |
this->SPI_Mode = SPI_Mode; | |
this->a0 = a0; | |
this->rst = rst; | |
spi = new LibSpi(this->SPI_Bus,this->SPI_Ce,this->SPI_Speed,this->SPI_Mode); | |
this->createDisplay(width,height,COLOR_FORMAT_18BIT); | |
} | |
LibST7735S::~LibST7735S() { | |
dcpin->portClose(); | |
rstpin->portClose(); | |
delete(spi); | |
} | |
void LibST7735S::createDisplay(uint8_t width,uint8_t height,uint8_t color_format){ | |
this->width = width; | |
this->height = height; | |
/* Reset Pin */ | |
if(this->rst != -1) | |
{ | |
this->rstpin = new LibGpio(this->rst,this->OUTPUT); //RST 出力方向 | |
this->rstpin->setVal(this->HIGH); | |
this->HWReset(); | |
} | |
/* Data/Command pin */ | |
this->dcpin = new LibGpio(this->a0,this->OUTPUT); //RST 出力方向 | |
this->dcpin->setVal(this->HIGH); | |
/* Initialzie display */ | |
this->writeCommand(CMD_SW_RESET); usleep(150*1000); //150ms | |
this->writeCommand(CMD_SLEEP_OUT); usleep(150*1000); //150ms | |
this->setMADCTL(0,0,0,0,0,0); | |
// setWindow(1, 1, width, height); | |
this->setColorFormat(color_format); | |
// this->writeCommand(CMD_TEON); this->writeData(0x01); usleep(100*1000); //100ms | |
writeCommand(CMD_DISPLAY_ON); usleep(100*1000); //100ms | |
} | |
void LibST7735S::fillScreen(uint8_t red, uint8_t green, uint8_t blue){ | |
this->fillRect(0,0,this->width,this->height,red, green, blue); | |
} | |
void LibST7735S::fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, | |
uint8_t red, uint8_t green, uint8_t blue){ | |
vector<uint8_t> tbx(w*h*3); | |
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y, | |
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1); | |
int i=0; | |
for(int wy=0; wy<h; wy++){ | |
for(int wx=0; wx<w; wx++){ | |
tbx[i] = blue; | |
tbx[i+1] = green; | |
tbx[i+2] = red; | |
// tbx.push_back(blue); tbx.push_back(green); tbx.push_back(red); | |
i+=3; | |
} | |
} | |
activeRAMWrite(); | |
this->writeData_vector2(&tbx); | |
vector<uint8_t>().swap(tbx); | |
} | |
void LibST7735S::drawPx(uint8_t x, uint8_t y,uint8_t red, uint8_t green, uint8_t blue){ | |
/* Check x and y */ | |
// if((x >= this->width) || (y >= this->height)) return; | |
uint8_t tbram[3] = {blue,green,red}; | |
this->setWindow(LCD_X_OFFSET+x, LCD_X_OFFSET+y, LCD_X_OFFSET+x, LCD_X_OFFSET+y); | |
activeRAMWrite(); | |
this->writeData(3,tbram); | |
} | |
void LibST7735S::drawImage(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d){ | |
//d・・・BGR | |
vector<uint8_t> tbx(w*h*3);//,tbx2; | |
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y, | |
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1); | |
activeRAMWrite(); | |
int i=0; | |
// for(int wy=0; wy<h; wy++){ | |
// for(int wx=0; wx<w; wx++){ | |
// tbx.push_back((uint8_t)d[d.size()-(i+1)]); //blue | |
// tbx.push_back((uint8_t)d[d.size()-(i+2)]); //green | |
// tbx.push_back((uint8_t)d[d.size()-(i)]); //red | |
// i=i+3; | |
// } | |
// reverse_copy(tbx.begin(),tbx.end(),back_inserter(tbx2)); | |
//// copy(tbx.begin(),tbx.end(),back_inserter(tbx2)); | |
// tbx.clear(); | |
// } | |
// if(tbx2.size() > 0){ | |
// this->writeData_vector2(tbx2); | |
// tbx2.clear(); | |
// } | |
vector<char> dp = *d; | |
int index,s=d->size(); | |
for(int dy=0; dy<h; dy++){ | |
for(int dx=0; dx<3*w; dx+=3){ | |
index = s -3*w*dy +dx -3*w; | |
tbx[i] = (uint8_t)dp[index]; | |
tbx[i+1] = (uint8_t)dp[index+1]; | |
tbx[i+2] = (uint8_t)dp[index+2]; | |
// tbx.push_back((uint8_t)d[index]); //blue | |
// tbx.push_back((uint8_t)d[index+1]); //green | |
// tbx.push_back((uint8_t)d[index+2]); //red | |
i+=3; | |
} | |
} | |
this->writeData_vector2(&tbx); | |
tbx.clear(); | |
} | |
void LibST7735S::drawImage2(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d){ | |
//d・・・BGR | |
vector<uint8_t> tbx(w*h*3); | |
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y, | |
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1); | |
activeRAMWrite(); | |
int i=0; | |
vector<char> dp = *d; | |
int index,s=d->size(); | |
for(int dy=0; dy<h; dy++){ | |
for(int dx=0; dx<3*w; dx+=3){ | |
index = s -3*w*dy +dx -3*w; | |
tbx[i] = (uint8_t)dp[index]; | |
tbx[i+1] = (uint8_t)dp[index+1]; | |
tbx[i+2] = (uint8_t)dp[index+2]; | |
i+=3; | |
} | |
} | |
this->writeData_vector3(&tbx); | |
tbx.clear(); | |
} | |
void LibST7735S::drawImage3(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<uint8_t>* d){ | |
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y, | |
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1); | |
activeRAMWrite(); | |
this->writeData_vector2(d); | |
} | |
//==[private]============================================================================ | |
void LibST7735S::setMADCTL(uint8_t MY,uint8_t MX,uint8_t MV,uint8_t ML, | |
uint8_t RGB,uint8_t MH){ | |
//MY Row Address Order | |
//MX Column Address Order | |
//MV Row/Column Exchange | |
//ML Vertical Refresh Order | |
//RGB RGB-BGR ORDER | |
//MH Horizontal Refresh Order | |
this->writeCommand(CMD_MEMORY_DATA_ACCESS_CONTROL); | |
uint8_t d = 0; | |
if(MY > 0) d += 0x80; | |
if(MX > 0) d += 0x40; | |
if(MV > 0) d += 0x20; | |
if(ML > 0) d += 0x10; | |
if(RGB > 0) d += 0x08; | |
if(MH > 0) d += 0x04; | |
this->writeData(d); | |
} | |
void LibST7735S::setWindow(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2){ | |
vector<uint8_t> tbx = {0, x1, 0, x2}; | |
vector<uint8_t> tby = {0, y1, 0, y2}; | |
this->writeCommand(CMD_COLUMN_ADRRESS_SET); | |
this->writeData_vector(&tbx); | |
this->writeCommand(CMD_ROW_ADRRESS_SET); | |
this->writeData_vector(&tby); | |
vector<uint8_t>().swap(tbx); | |
vector<uint8_t>().swap(tby); | |
} | |
void LibST7735S::setColorFormat(uint8_t color_format){ | |
switch(color_format) | |
{ default: color_format = COLOR_FORMAT_18BIT; break; | |
case COLOR_FORMAT_18BIT: break; | |
case COLOR_FORMAT_16BIT: break; | |
case COLOR_FORMAT_12BIT: break; | |
} | |
this->color_format = color_format; | |
writeCommand(CMD_INTERFACE_PIXEL_FORMAT); | |
writeData(color_format); | |
} | |
void LibST7735S::setGamma(uint8_t state){ | |
switch(state) | |
{ /* [GS_Pin = 0] Checked on hardware! */ | |
default: state = 1; break; | |
case 2: break; | |
case 4: break; | |
case 8: break; | |
} | |
this->writeCommand(CMD_GAMMA_SET); | |
this->writeData(state); | |
} | |
void LibST7735S::activeRAMWrite(){ | |
this->writeCommand(CMD_MEMORY_WRITE); | |
this->dcpin->setVal(this->HIGH); | |
} | |
void LibST7735S::writeData(int len, uint8_t *txbuf){ | |
try{ | |
this->dcpin->setVal(this->HIGH); | |
spi->transfer(len,txbuf); | |
}catch(LibSpiException e){ | |
cerr << e.getString() << endl; | |
} | |
} | |
void LibST7735S::writeData_vector(vector<uint8_t>* txbuf){ | |
try{ | |
this->dcpin->setVal(this->HIGH); | |
spi->transfer_vector(txbuf); | |
}catch(LibSpiException e){ | |
cerr << e.getString() << endl; | |
} | |
} | |
void LibST7735S::writeData_vector2(vector<uint8_t>* txbuf){ | |
try{ | |
this->dcpin->setVal(this->HIGH); | |
spi->transfer_vector2(txbuf); | |
}catch(LibSpiException e){ | |
cerr << e.getString() << endl; | |
} | |
} | |
void LibST7735S::writeData_vector3(vector<uint8_t>* txbuf){ | |
try{ | |
this->dcpin->setVal(this->HIGH); | |
spi->transfer_vector3(txbuf); | |
}catch(LibSpiException e){ | |
cerr << e.getString() << endl; | |
} | |
} | |
void LibST7735S::writeData(uint8_t data){ | |
try{ | |
this->dcpin->setVal(this->HIGH); | |
spi->transfer(data); | |
}catch(LibSpiException e){ | |
cerr << e.getString() << endl; | |
} | |
} | |
void LibST7735S::writeCommand(uint8_t cmd){ | |
try{ | |
this->dcpin->setVal(this->LOW); | |
spi->transfer(cmd); | |
}catch(LibSpiException e){ | |
cerr << e.getString() << endl; | |
} | |
} | |
void LibST7735S::HWReset(){ | |
if(this->rst == -1) return; | |
this->rstpin->setVal(this->HIGH); usleep(10*1000); //10ms | |
this->rstpin->setVal(this->LOW); usleep(10*1000); //10ms | |
this->rstpin->setVal(this->HIGH); usleep(150*1000); //150ms | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* LibST7735S.h | |
* | |
* Created on: 2018/02/05 | |
* Author: adeno | |
*/ | |
#ifndef LIBST7735S_H_ | |
#define LIBST7735S_H_ | |
#include <stdint.h> //uint8_t | |
#include <string> | |
#include <unistd.h> | |
#include <vector> | |
#include <algorithm> | |
#include "LibSpi.h" | |
#include "LibGpio.h" | |
class LibST7735S { | |
private: | |
/* SPI */ | |
LibSpi *spi; | |
int SPI_Bus; | |
int SPI_Ce; | |
int SPI_Speed; | |
uint8_t SPI_Mode; | |
/* GPIO */ | |
const static int OUTPUT = 0; | |
const static int INPUT = 1; | |
const static int HIGH = 1; | |
const static int LOW = 0; | |
/* Reset Pin */ | |
LibGpio *rstpin; | |
/* Data/Command Pin */ | |
LibGpio *dcpin; | |
/* st7735s Define*/ | |
const static uint8_t CMD_NOP = 0x00; | |
const static uint8_t CMD_SW_RESET = 0x01; | |
const static uint8_t CMD_SLEEP_OUT = 0x11; | |
const static uint8_t CMD_INVOFF = 0x20; | |
const static uint8_t CMD_INVON = 0x21; | |
const static uint8_t CMD_GAMMA_SET = 0x26; | |
const static uint8_t CMD_DISPLAY_OFF = 0x28; | |
const static uint8_t CMD_DISPLAY_ON = 0x29; | |
const static uint8_t CMD_COLUMN_ADRRESS_SET = 0x2A; | |
const static uint8_t CMD_ROW_ADRRESS_SET = 0x2B; | |
const static uint8_t CMD_MEMORY_WRITE = 0x2C; | |
const static uint8_t CMD_TEOFF = 0x34; | |
const static uint8_t CMD_TEON = 0x35; | |
const static uint8_t CMD_MEMORY_DATA_ACCESS_CONTROL = 0x36; | |
const static uint8_t CMD_INTERFACE_PIXEL_FORMAT = 0x3A; | |
const static uint8_t COLOR_FORMAT_12BIT = 0b011; | |
const static uint8_t COLOR_FORMAT_16BIT = 0b101; | |
const static uint8_t COLOR_FORMAT_18BIT = 0b110; | |
/* st7735s RAW Display Type */ | |
int a0; /* Data/Command line */ | |
int rst; /* Reset line */ | |
uint8_t width; /* Currently used width */ | |
uint8_t height; /* Currently used height */ | |
uint8_t color_format; | |
void createDisplay(uint8_t width,uint8_t height,uint8_t color_format); | |
void HWReset(); | |
void setMADCTL(uint8_t MY,uint8_t MX,uint8_t MV,uint8_t ML,uint8_t RGB,uint8_t MH); | |
void setGamma(uint8_t state); | |
void setColorFormat(uint8_t color_format); | |
void setWindow(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2); | |
void activeRAMWrite(); | |
void writeData(uint8_t data); | |
void writeData(int len, uint8_t *txbuf); | |
void writeData_vector(vector<uint8_t>* txbuf); | |
void writeData_vector2(vector<uint8_t>* txbuf); | |
void writeData_vector3(vector<uint8_t>* txbuf); | |
void writeCommand(uint8_t cmd); | |
public: | |
LibST7735S(int SPI_Bus, int SPI_Ce, int SPI_Speed,uint8_t SPI_Mode,int a0, int rst,uint8_t width,uint8_t height); | |
void fillScreen(uint8_t red, uint8_t green, uint8_t blue); | |
void fillRect(uint8_t x, uint8_t y, uint8_t width, uint8_t height,uint8_t red, uint8_t green, uint8_t blue); | |
void drawPx(uint8_t x, uint8_t y,uint8_t red, uint8_t green, uint8_t blue); | |
void drawImage(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d); | |
void drawImage2(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d); | |
void drawImage3(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<uint8_t>* d); | |
virtual ~LibST7735S(); | |
}; | |
#endif /* LIBST7735S_H_ */ |
200円くらいのジャンクFONでついにここまで来れた。
ArduinoとかRaspberryPiとか使えば一瞬なのは知ってる。
これぞ趣味の世界
他にもいろいろ動かしたい!
他のグラフィック液晶・OLED
なんだか行けそうな気がする
I/Oを増やしたい
SPI IOエキスパンダ(MCP23S08-E)を秋月電子で買ったら、動作電圧が5VだったOrz。
しかもSPI系のHi検出レベルが 0.8VDD。 FONは3.3Vなのでた、足りない。
仕方がないので、動作電圧が1.8V〜5.5VのMCP230S09を入手予定。
8-Eの方は、マイコンとか74HC14とかと一緒に使うとするか。
入手でき次第対応する
まだ、SPIでの入力をやっていないからこのタイミングでやってみよう
キャラクタ液晶が・・・
昔にまとめ買いしたキャラクタ液晶が余ってる。
最近のI2Cとかじゃない8bitパラレルインターフェースだよ。
IOエキスパンダ経由で制御してみるか。
SD/MMCカード
SPIでの入出力できるようになってから
多分SPI-MMC的なドライバをカーネルコンフィグ時に選択すれば良いような気がする
0 件のコメント:
コメントを投稿