Amazonで1.3インチのOLEDを見かけたので買ってみました。
https://www.amazon.co.jp/dp/B01M9CIFU5/www.amazon.co.jp
レビューを見るとインターフェース(SPI or I2C)と色(白 or 青)は届くまでわからないとのこと。
確かに注文時に選択する箇所が無いので、I2Cが届くことを願いながら注文しました。
結果・・
届いたのは7ピンのSPIでした(笑)
0.96インチと並べると大きさは一目瞭然です。
調べてみると裏の抵抗の位置を変えればI2Cで動かすことができるらしいのですが、せっかくなのでSPIのまま動かしてみることにしました。
また、コントローラーもSSD1306では無く、SH1106と言う型番のようでレジスタ形態が若干違うようです。
データシートは検索したら直ぐに入手できました。
ベースとなる回路とプログラムは前回作った馬のアニメーションgifです。
PICのSSP1はそのままI2CでEEPROMを接続し、SSP2をSPIにしてOLEDと接続しました。
OLEDのピンは左から
GND
VCC
SCK(SPIクロック)
SDI(SPI入力データ)
RES(リセット)
DC(データ/コマンド)
CS(チップセレクト)
の並び順になっています。
DCとCSが存在しているので、4線式のSPIであることが伺えます。
SH1106のデータシートにタイミングチャートが載っていました。
A0がDCに相当しており、Lowでコマンド、Highでデータとなっています。
PICとの接続は下記のようにしました。
RC4 : SCK
RC5 : SDI(SDO)
RA2 : RES
RC2 : DC
SPIデバイスはOLEDのみなので、CSはLow固定にしています。
SPIクロックは最速の1Mにしました。
SPI通信はI2C通信と同様にPICのレジスタを操作することでPICが自動で行いますが、DCはRC2を直接操作して設定しています。
コマンドはほぼSSD1306と同じでしたが、アドレッシングモードはPageモードのみのようで、カラムには2のオフセットを付けて指定する必要があるようです。
(値2で位置0になる)
また、チャージポンプの設定は不要でした。
その他、表示On(0xaf)もSSD1306と同じなのでさほど苦労せずに動かせました。
しかし、せっかく1MHzのSPIクロックで送信しているのに表示はそれほど速くなった感じがしません。
おそらく400KHzのI2CクロックでEEPROMから表示データをリードしているのがボトルネックになっていると予想されます。
そこで、EEPROMも高速版(最大1MHz)の24FC512を使用してSPI、I2C共に1MHzで動かしてみることにしました。
24FC512は秋月電子で140円でした。
8MHzのメインクロックから、I2Cクロック1MHzを作るにはデータシートの式からSSP1ADDには値1を設定しなければいけません。
しかし、注釈のようにSSP1ADDはI2C使用時は3以上では無いといけないようなので、逆算するとメインクロックは最低でも16MHzが必要になります。
また、SSP1STATのビット7 のSMPにも1をセットしないと1MHzで通信できないようでした。
これに気がつかず3時間ほどハマってしまいました(笑)
(ステータスレジスタなのに設定項目があったとは・・)
このように色々と変更を加えたプログラムはこちらになります。
#include <pic.h>
#include <htc.h>
#include <pic16f18326.h>
#define _XTAL_FREQ 16000000
#define DEV_EEPROM_W 0xa0
#define DEV_EEPROM_R 0xa1
#define PAGE_MAX 8
#define PAGE_OFFSET 0x400
#pragma config FCMEN = OFF
#pragma config CSWEN = ON
#pragma config CLKOUTEN = OFF
#pragma config RSTOSC = HFINT1
#pragma config FEXTOSC = OFF
#pragma config DEBUG = OFF
#pragma config STVREN = OFF
#pragma config PPS1WAY = OFF
#pragma config BORV = HIGH
#pragma config BOREN = OFF
#pragma config LPBOREN = OFF
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config LVP = OFF
#pragma config WRT = OFF
#pragma config CPD = OFF
#pragma config CP = OFF
void spi_send(unsigned char, unsigned char);
void i2c_idle(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_send(unsigned char);
unsigned char i2c_recv(void);
void i2c_sack(void);
void i2c_snack(void);
void oled_init(void);
void oled_display(unsigned char);
void main(void){
unsigned char page;
page = 0;
OSCCON1 = 0b01100000;
OSCFRQ = 0b00000110;
TRISA = 0b00000000;
TRISC = 0b00000011;
PORTA = 0b00000000;
PORTC = 0b00000000;
LATA = 0b00000000;
LATC = 0b00000011;
ANSELA = 0b00000000;
ANSELC = 0b00000000;
SSP1CLKPPS = 0x10;
SSP1DATPPS = 0x11;
RC0PPS = 0x18;
RC1PPS = 0x19;
SSP2DATPPS = 0x18;
SSP2SSPPS = 0x18;
RC4PPS = 0x1a;
RC5PPS = 0x1b;
SSP1ADD = 0b00000011;
SSP1CON1 = 0b00101000;
SSP1STAT = 0b10000000;
SSP2ADD = 0b00000011;
SSP2CON1 = 0b00111010;
SSP2STAT = 0b00000000;
INTCON = 0x00;
__delay_ms(10); PORTAbits.RA2 = 1;
__delay_ms(10); PORTAbits.RA2 = 0;
__delay_ms(10); PORTAbits.RA2 = 1;
__delay_ms(100);
oled_init();
while(1){
oled_display(page);
page++;
if(page==PAGE_MAX){
page = 0;
}
}
}
void spi_send(
unsigned char dc,
unsigned char data
){
unsigned char dmy;
PORTCbits.RC2 = dc;
dmy = SSP2BUF;
SSP2BUF = data;
while(!SSP2STATbits.BF){}
}
void i2c_idle(void){
while(SSP1CON2bits.SEN |
SSP1CON2bits.PEN |
SSP1CON2bits.RCEN |
SSP1CON2bits.ACKEN |
SSP1STATbits.R_nW){}
}
void i2c_start(void){
i2c_idle();
SSP1CON2bits.SEN = 1;
while(SSP1CON2bits.SEN){}
}
void i2c_stop(void){
SSP1CON2bits.PEN = 1;
while(SSP1CON2bits.PEN){}
i2c_idle();
}
void i2c_send(unsigned char data){
SSP1BUF = data;
while(SSP1STATbits.BF){}
while(SSP1CON2bits.ACKSTAT){}
i2c_idle();
}
unsigned char i2c_recv(void){
SSP1CON2bits.RCEN = 1;
while(SSP1CON2bits.RCEN){}
return(SSP1BUF);
}
void i2c_sack(void){
SSP1CON2bits.ACKDT = 0;
SSP1CON2bits.ACKEN = 1;
while(SSP1CON2bits.ACKEN){}
}
void i2c_snack(void){
SSP1CON2bits.ACKDT = 1;
SSP1CON2bits.ACKEN = 1;
while(SSP1CON2bits.ACKEN){}
}
void oled_init(void){
spi_send(0, 0xaf);
}
void oled_display(unsigned char page){
unsigned char data00[64], data01[64], data02[64], data03[64],
data04[64], data05[64], data06[64], data07[64],
data08[64], data09[64], data10[64], data11[64],
data12[64], data13[64], data14[64], data15[64];
unsigned char addr_high;
unsigned char addr_low;
unsigned short addr;
addr = page * PAGE_OFFSET;
addr_high = addr >> 8;
addr_low = addr & 0xff;
i2c_start();
i2c_send(DEV_EEPROM_W);
i2c_send(addr_high);
i2c_send(addr_low);
i2c_start();
i2c_send(DEV_EEPROM_R);
for(int i=0; i<64; i++){ data00[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data01[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data02[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data03[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data04[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data05[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data06[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data07[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data08[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data09[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data10[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data11[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data12[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data13[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<64; i++){ data14[i] = i2c_recv(); i2c_sack(); }
for(int i=0; i<63; i++){ data15[i] = i2c_recv(); i2c_sack(); }
data15[63] = i2c_recv();
i2c_snack();
i2c_stop();
spi_send(0, 0x10); spi_send(0, 0x02); spi_send(0, 0xb0);
for(int i=0; i<64; i++){ spi_send(1, data00[i]); }
for(int i=0; i<64; i++){ spi_send(1, data01[i]); }
spi_send(0, 0x10); spi_send(0, 0x02); spi_send(0, 0xb1);
for(int i=0; i<64; i++){ spi_send(1, data02[i]); }
for(int i=0; i<64; i++){ spi_send(1, data03[i]); }
spi_send(0, 0x10); spi_send(0, 0x02); spi_send(0, 0xb2);
for(int i=0; i<64; i++){ spi_send(1, data04[i]); }
for(int i=0; i<64; i++){ spi_send(1, data05[i]); }
spi_send(0, 0x10); spi_send(0, 0x02); spi_send(0, 0xb3);
for(int i=0; i<64; i++){ spi_send(1, data06[i]); }
for(int i=0; i<64; i++){ spi_send(1, data07[i]); }
spi_send(0, 0x10); spi_send(0, 0x02); spi_send(0, 0xb4);
for(int i=0; i<64; i++){ spi_send(1, data08[i]); }
for(int i=0; i<64; i++){ spi_send(1, data09[i]); }
spi_send(0, 0x10); spi_send(0, 0x02); spi_send(0, 0xb5);
for(int i=0; i<64; i++){ spi_send(1, data10[i]); }
for(int i=0; i<64; i++){ spi_send(1, data11[i]); }
spi_send(0, 0x10); spi_send(0, 0x02); spi_send(0, 0xb6);
for(int i=0; i<64; i++){ spi_send(1, data12[i]); }
for(int i=0; i<64; i++){ spi_send(1, data13[i]); }
spi_send(0, 0x10); spi_send(0, 0x02); spi_send(0, 0xb7);
for(int i=0; i<64; i++){ spi_send(1, data14[i]); }
for(int i=0; i<64; i++){ spi_send(1, data15[i]); }
}
前回のI2C 400KHzよりもかなり高速に表示できました。
そして、1.3インチも見やすくていい感じです。
[参考記事]