電子ペーパーを TWELITE に接続する

「電子ペーパー を 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
と同様に、チェッカーが表示されました。

![IMG_20200915_191141763.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/f89647f0-9337-c0d6-51af-6b7238dd182f.jpeg)