2018年2月17日土曜日

FON2405E(LEDE・Openwrt)でSPI〜1.44インチのグラフィック液晶制御(高速化)


前回作ったものが表示が遅い+メモリリークで落ちるため、いくつか見直しを行った
実際の表示はわからないけど、LCDへの書き出し処理は大体16fpsくらい できているみたい

フリー素材のGIF動画を使わせてもらった「いいね!」
https://www.pakutaso.com/gif/gifpost-135.html



やったことは
・vecterの開放(vector<uint8_t>().swap(tbx);)
・SPIの開放忘れ(free(&spi);)

やってもあまり効果なかったこと
・SPI_IOC_MESSAGEのサイズ 結局1度に送れるのは4096Byte?


差分はここんな感じ
/*
* 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
}
view raw LibST7735S.cpp hosted with ❤ by GitHub
/*
* 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_ */
view raw LibST7735S.h hosted with ❤ by GitHub

メモ
動画やGIFから連続したBMPを作成する
 convert -coalesce -resize 128x128! cinemagraph.gif +adjoin SL%02d.bmp
色を24bitにする
 mogrify -type truecolor SL*.bmp

参考
http://www.c-lang.net/general43/index.html
http://yoppa.org/blog/5862.html
http://cdecrement.blog.fc2.com/blog-entry-65.html

2018年2月11日日曜日

FON2405E(LEDE・Openwrt)でSPI〜1.44インチのグラフィック液晶制御

SPIの動作確認を兼ねて昔に入手した1.44インチのTFT液晶モジュール(多分Z144SN005/aitendo)を繋いでみた。
本当は、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用ライブラリ
 先人たちの偉業を参考に作成
 現状、若干モジュールに特化してしまっている感もある

/*
* 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
}
view raw LibST7735S.cpp hosted with ❤ by GitHub
/*
* 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_ */
view raw LibST7735S.h hosted with ❤ by GitHub

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的なドライバをカーネルコンフィグ時に選択すれば良いような気がする

FON2405E(LEDE・Openwrt)でSPIデバイス追加

ようやくFONの活用に向けての一歩

フラッシュメモリが接続されているSPIポートを汎用的に使えないか

考えることはみんな同じで、すでにやっている人が居る
というかOpenWrtのHPに書いてある→Deep MMC Mod

・もともとのCS#1にインバーターを繋いでCS#2とするもの
・GPIOを1つ潰してCS#2に割り当てるもの

実現方法
極力ハードを増やしたくなかったので、GPIOにCS#2を割り当てる方法を考えることにした。
CSは負論理なので、起動時からHのままのGPIO12を使うことにした。
ubootもカスタマイズできれば、どのGPIOでも良いんだろうけど。

SPI通信のためにハードは16pinSPIフラッシュ用のランドから線出し
外れないようにホットボンドで固定
黒なので見栄えが少しイマイチ

ソフトは変更点だけを書き出すとこれだけ・・・。
dtsファイル変更、カーネルコンフィグでSPI_SPIDEV追加。
・gpio-ledsからGPIO12に関する定義をコメントアウト
・spi定義部分にcs-gpios追加
・spi定義部分にspidevを追加
+&spi0 {
+ status = "okay";
+
+ num-chipselects = <2>;
+ cs-gpios = <0>,<&gpio0 12 GPIO_ACTIVE_LOW>;
+
+ m25p80@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0 0x10000>;
+ read-only;
+ };
+
+ devconf: partition@10000 {
+ label = "devconf";
+ reg = <0x10000 0x10000>;
+ read-only;
+ };
+ firmware: partition@20000 {
+ label = "firmware";
+ reg = <0x20000 0x7b0000>;
+ };
+ };
+
+ spidev@1 {
+ compatible = "spidev";
+ reg = <1>;
+ spi-max-frequency = <10000000>;
+ };
+
+};

ビルド→ファームアップ→デバイス確認

おぉぉぉ
ちなみに、spidevドライバを組み込むとbootログで注意されるみたい
[ 1.459196] spi spi0.1: force spi mode3
[ 1.467875] spidev spi0.1: buggy DT: spidev listed directly in DT
[ 1.480327] ------------[ cut here ]------------
[ 1.489758] WARNING: CPU: 0 PID: 1 at drivers/spi/spidev.c:758 spidev_probe+0x1c0/0x1f0
[ 1.505958] Modules linked in:
[ 1.512139] CPU: 0 PID: 1 Comm: swapper Not tainted 4.9.57 #0
[ 1.523776] Stack : 8041751a 00000031 00000000 00000001 8182c284 803caba7 8037fcdc 00000001
[ 1.540724] 80413660 000002f6 803d0000 803e0000 803a0000 8004d540 8038549c 803d0000
[ 1.557718] 00000003 000002f6 8038368c 81827aa4 803a0000 8007b1dc 8041751a 0000004b
[ 1.574709] 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1.591649] 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1.608636] ...
[ 1.613628] Call Trace:
[ 1.618611] [<8000e358>] show_stack+0x54/0x88
[ 1.627515] [<80023ec0>] __warn+0xe4/0x118
[ 1.635873] [<80023f88>] warn_slowpath_null+0x1c/0x34
[ 1.646166] [<80229cfc>] spidev_probe+0x1c0/0x1f0
[ 1.655766] [<802095f4>] driver_probe_device+0x140/0x290
[ 1.666574] [<80207ac4>] bus_for_each_drv+0xa0/0xb0
[ 1.676505] [<80209440>] __device_attach+0x8c/0xe4
[ 1.686262] [<802089bc>] bus_probe_device+0x3c/0xb0
[ 1.696191] [<80206b38>] device_add+0x468/0x560
[ 1.705455] [<80226fc4>] spi_add_device+0x118/0x16c
[ 1.715399] [<80228e0c>] spi_register_master+0x4d0/0x770
[ 1.726205] [<802290f8>] devm_spi_register_master+0x4c/0x9c
[ 1.737539] [<8022a98c>] rt2880_spi_probe+0x160/0x1c4
[ 1.747842] [<8020afdc>] platform_drv_probe+0x28/0x70
[ 1.758127] [<802095f4>] driver_probe_device+0x140/0x290
[ 1.768935] [<802097d0>] __driver_attach+0x8c/0xc4
[ 1.778690] [<80207a00>] bus_for_each_dev+0x9c/0xac
[ 1.788622] [<80208c3c>] bus_add_driver+0xec/0x204
[ 1.798381] [<80209f08>] driver_register+0xa8/0xf8
[ 1.808135] [<80004658>] do_one_initcall+0xdc/0x1a4
[ 1.818094] [<803e9d3c>] kernel_init_freeable+0x168/0x220
[ 1.829077] [<8030660c>] kernel_init+0x10/0x10c
[ 1.838313] [<80009258>] ret_from_kernel_thread+0x14/0x1c
[ 1.849303] ---[ end trace ac6e1c084ca3bbc0 ]---
view raw boot.log hosted with ❤ by GitHub
次は動作確認だー