「電子ペーパー を ESP32 と Arduino開発環境で使う その3」
https://qiita.com/nanbuwks/items/1a4d58fc7f74ab8c8d85
では ESP32 で WAVESHARE の e-Paper を使いましたが、これを TWELITE に移植してみます。
「TWELITE で SPI を試す」
https://qiita.com/nanbuwks/items/e3e8c66ad67624cd8639
では ADコンバータIC MCP3008 を SPI でアクセスしましたが、この SPI アクセスプログラムに e-Paper のコードをあてはめていきます。
環境
- TWELITE BLUE
- 型番:TWE-L-DI-W
- WaveShareの電子ペーパーモジュール
- https://www.waveshare.com/wiki/2.9inch_e-Paper_Module_(B)
- TWELITE SDK MWSDK_Linux-i386_201805.tgz
- TWELITE の SDK は、 C ライブラリと MWX ライブラリの2つがありますが C ライブラリを試してみます。
配線
TWELITE DIP基板ピン番号 | TWELITE DIP基板上のシルク表記 | TWELITE CHIP パッド番号 | TWELITE IO名 | WAVESHARE e-Paper 信号名 | WAVESHARE ケーブル色 | SPI 信号名 |
---|---|---|---|---|---|---|
(4) | (5) | (7) | (DIO5) | BUSY | 紫 | |
(9) | (4) | (6) | (DIO4) | RST | 白 | |
(11) | (8) | (10) | (DIO8) | DC | 緑 | |
8 | 19 | 4 | DIO19 | CS | 橙 | CS |
6 | C | 1 | DO0 | CLK | 黄 | SCLK |
5 | 18 | 3 | DIO18 | DIN | 青 | MOSI |
GND | GND | GND | GND | GND | 黒 | |
28 | VCC | VCC | VCC | VCC | 赤 |
TWELITE のSPI はポートが決まっていますが、SPI専用以外のRSTやBUSYなどについては適当なGPIOにあわせておきます。表では括弧付きで表しています。
WAVESHARE の e-Paper モジュールは、SPI の MISO 信号線は使いません。その代わり、DC 信号線が使用され Data/Command 及び Write/Read をコントロールします(デフォルトの4-Wire SPI モードの場合。3-Wire SPIモードの場合はコントロールビットを MOSI 信号に付加して DC 信号線の代わりとなります)。
上述のことから、当初は使用しないMISO信号線をDC信号線に割り当ててみました。しかしうまく動かなかったのでリストのようにした所動くようになりました。
コード
e-Paper モジュールにテストパターンを表示するだけのものになります。
「TWELITE で SPI を試す」
https://qiita.com/nanbuwks/items/e3e8c66ad67624cd8639
では無線通信なしで MCP3008 を動かすためだけのコードでしたが、これも同様に無線通信はありません。
# include <AppHardwareApi.h>
# include "utils.h"
# include "ToCoNet.h"
# include "ToCoNet_mod_prototype.h"
# include "serial.h"
# include "fprintf.h"
# define LED 12
# define RST_PIN 4
# define DC_PIN 8
// #define CS_PIN 19 // fix by TWELITE
# define BUSY_PIN 5
# define EPD_WIDTH 128
# define EPD_HEIGHT 296
const unsigned char EPD_2IN9D_lut_vcomDC[] = {
0x00,0x08,0x00,0x00,0x00,0x02,0x60,0x28,0x28,0x00,0x00,0x01,0x00,0x14,0x00,0x00,0x00,0x01,0x00,0x12,
0x12,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
};
const unsigned char EPD_2IN9D_lut_ww[] = {
0x40,0x08,0x00,0x00,0x00,0x02,0x90,0x28,0x28,0x00,0x00,0x01,0x40,0x14,0x00,0x00,0x00,0x01,0xA0,0x12,
0x12,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const unsigned char EPD_2IN9D_lut_bw[] = {
0x40,0x17,0x00,0x00,0x00,0x02,0x90,0x0F,0x0F,0x00,0x00,0x03,0x40,0x0A,0x01,0x00,0x00,0x01,0xA0,0x0E,
0x0E,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const unsigned char EPD_2IN9D_lut_wb[] = {
0x80,0x08,0x00,0x00,0x00,0x02,0x90,0x28,0x28,0x00,0x00,0x01,0x80,0x14,0x00,0x00,0x00,0x01,0x50,0x12,
0x12,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
const unsigned char EPD_2IN9D_lut_bb[] = {
0x80,0x08,0x00,0x00,0x00,0x02,0x90,0x28,0x28,0x00,0x00,0x01,0x80,0x14,0x00,0x00,0x00,0x01,0x50,0x12,
0x12,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};
tsFILE sSerial0Stream;
static tsSerialPortSetup sSerial0;
void SendCommand( int32_t command)
{
vPortSetLo(DC_PIN);
vAHI_SpiSelect(1); // SPISEL0 スタート
vAHI_SpiStartTransfer8( command );
int i;
for ( i=0; bAHI_SpiPollBusy(); i++) // timeout 付 Busy チェック
{
if ( 1000 < i )
{
vfPrintf(&sSerial0Stream, "error! SPI timeout\n\r");
break;
}
vWait(1);
}
}
void SendData(char data)
{
vPortSetHi(DC_PIN);
vAHI_SpiSelect(1); // SPISEL0 スタート
vAHI_SpiStartTransfer8( data );
int i;
for ( i=0; bAHI_SpiPollBusy(); i++) // timeout 付 Busy チェック
{
if ( 1000 < i )
{
vfPrintf(&sSerial0Stream, "error! SPI timeout\n\r");
break;
}
vWait(1);
}
}
void WaitUntilIdle(void)
{
bool_t busy;
do {
SendCommand(0x71); // Command Get Status (FLG)
busy = bPortRead(BUSY_PIN); // busy is low active ( TWILITE low means 1 )
vWait(300); // 100uS
} while( busy );
vWait(600000); // 200mS
}
void SetFullReg(void)
{
SendCommand(0X50); //VCOM AND DATA INTERVAL SETTING
SendData(0xb7); //WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
unsigned int count;
SendCommand(0x20);
for(count=0; count<44; count++) {
SendData(EPD_2IN9D_lut_vcomDC[count]);
}
SendCommand(0x21);
for(count=0; count<42; count++) {
SendData(EPD_2IN9D_lut_ww[count]);
}
SendCommand(0x22);
for(count=0; count<42; count++) {
SendData(EPD_2IN9D_lut_bw[count]);
}
SendCommand(0x23);
for(count=0; count<42; count++) {
SendData(EPD_2IN9D_lut_wb[count]);
}
SendCommand(0x24);
for(count=0; count<42; count++) {
SendData(EPD_2IN9D_lut_bb[count]);
}
}
void TurnOnDisplay(void)
{
SendCommand(0x12); //DISPLAY REFRESH
vWait(30000); // 100mS //!!!The delay here is necessary, 200uS at least!!!
WaitUntilIdle();
}
static void vProcessEvCore(tsEvent *pEv, teEvent eEvent, uint32 u32evarg)
{
bool_t inputdata;
static int counter=0;
static int counter2=0;
if (eEvent == E_EVENT_TICK_TIMER) { // 4ms timer
counter++;
if ( 0 == counter % 1000 ) {
counter2++;
vPortSetHi(LED);
vfPrintf(&sSerial0Stream, "%d : LED Hi\n\r",counter2);
vPortSetHi( DC_PIN);
}
if ( 250 == counter % 1000 ) {
vPortSetLo(LED);
vfPrintf(&sSerial0Stream, "%d : LED Lo\n\r",counter2);
vPortSetLo( DC_PIN);
}
}
}
void cbAppColdStart(bool_t bStart)
{
if (!bStart) {
} else {
vPortAsOutput(LED); // GPIO set
// vPortAsOutput(CS_PIN);
vPortSetLo( RST_PIN);
vPortAsOutput(RST_PIN);
vPortSetLo( DC_PIN);
vPortAsOutput(DC_PIN);
vPortAsInput(BUSY_PIN); // with pullup
ToCoNet_Event_Register_State_Machine(vProcessEvCore); // add Event handler
// serial init
static uint8 au8SerialBuffTx[32];
static uint8 au8SerialBuffRx[16];
sSerial0.pu8SerialRxQueueBuffer = au8SerialBuffRx;
sSerial0.pu8SerialTxQueueBuffer = au8SerialBuffTx;
sSerial0.u32BaudRate = 115200;
sSerial0.u16AHI_UART_RTS_LOW = 0xffff;
sSerial0.u16AHI_UART_RTS_HIGH = 0xffff;
sSerial0.u16SerialRxQueueSize = sizeof(au8SerialBuffRx);
sSerial0.u16SerialTxQueueSize = sizeof(au8SerialBuffTx);
sSerial0.u8SerialPort = E_AHI_UART_0;
sSerial0.u8RX_FIFO_LEVEL = E_AHI_UART_FIFO_LEVEL_1;
SERIAL_vInit(&sSerial0);
sSerial0Stream.bPutChar = SERIAL_bTxChar;
sSerial0Stream.u8Device = E_AHI_UART_0;
vfPrintf(&sSerial0Stream, "Hello World!\n\r");
vPortSetHi(RST_PIN);
vWait(600000); // 200mS
vPortSetLo(RST_PIN); // module reset
vWait(30000); // 10mS
vPortSetHi(RST_PIN);
vWait(600000); // 200mS
// digitalWrite(CS_PIN, LOW);
// SPI リソース初期化
vAHI_SpiConfigure(0, // use SPISEL0
FALSE, // MSB FIRST
FALSE, // SPI mode 0
FALSE, // SPI mode 0
4, // 16 / (num * 2 ) MHz clock
FALSE, // no use interrupt SPI transfer end
FALSE); // CSEL control by vAHI_SpiSelect
vAHI_SpiSelect(1); // SPISEL0 スタート
vPortSetLo( DC_PIN);
vPortAsOutput(DC_PIN);
//POWER SETTING
SendCommand(0x01);
SendData(0x03);
SendData(0x00);
SendData(0x2b);
SendData(0x2b);
SendData(0x03);
SendCommand(0x06); //boost soft start
SendData(0x17); //A
SendData(0x17); //B
SendData(0x17); //C
SendCommand(0x04); // power on
WaitUntilIdle(); // check BUSY pin
SendCommand(0x00); //panel setting
SendData(0xbf); //LUT from OTP,128x296
SendData(0x0e); //VCOM to 0V fast
SendCommand(0x30); //PLL setting
SendData(0x3a); // 3a 100HZ 29 150Hz 39 200HZ 31 171HZ
SendCommand(0x61); //resolution setting
SendData(EPD_WIDTH);
SendData((EPD_HEIGHT >> 8) & 0xff);
SendData(EPD_HEIGHT & 0xff);
SendCommand(0x82); //vcom_DC setting
SendData(0x28);
vfPrintf(&sSerial0Stream, "e-Paper initialized.\n\r");
int w, h,i,j;
w = (EPD_WIDTH % 8 == 0)? (EPD_WIDTH / 8 ): (EPD_WIDTH / 8 + 1);
h = EPD_HEIGHT;
SendCommand(0x10); // Display Transmission1 B/W Pixel Data
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
SendData(0x00);
}
}
// SendCommand(0x13);
// for (int j = 0; j < h; j++) {
// for (int i = 0; i < w; i++) {
// SendData(0xFF);
// }
// }
SendCommand(0x13); // Display Transmission2 Red Pixel Data
for ( j = 0; j < h; j++) {
for ( i = 0; i < w; i++) {
if ( 0 == ( j / 8 ) % 2 ){
SendData(0x00);
SendData(0xFF);
} else {
SendData(0xFF);
SendData(0x00);
}
}
j++;
}
vfPrintf(&sSerial0Stream, "e-Paper cleared\n\r");
SetFullReg();
TurnOnDisplay();
SendCommand(0X50);
SendData(0xf7);
SendCommand(0X02); //power off
WaitUntilIdle();
SendCommand(0X07); //deep sleep
SendData(0xA5);
vPortSetLo(RST_PIN);
} // if (!bStart) block end
}
void cbAppWarmStart(bool_t bStart) { return; }
void cbToCoNet_vRxEvent(tsRxDataApp *psRx) { return; }
void cbToCoNet_vTxEvent(uint8 u8CbId, uint8 bStatus) { return; }
void cbToCoNet_vNwkEvent(teEvent eEvent, uint32 u32arg) { return; }
void cbToCoNet_vHwEvent(uint32 u32DeviceId, uint32 u32ItemBitmap) { return; }
uint8 cbToCoNet_u8HwInt(uint32 u32DeviceId, uint32 u32ItemBitmap) { return FALSE; }
void cbToCoNet_vMain(void) { return; }
結果
「電子ペーパー を ESP32 と Arduino開発環境で使う その3」
https://qiita.com/nanbuwks/items/1a4d58fc7f74ab8c8d85
と同様に、チェッカーが表示されました。