PSoCにグラフィック液晶モジュール「SG12232」を接続する

psoc_glcd_01.gif
今回はPSoCにモノクロのグラフィックスディスプレイを接続して任意のドットパターンを表示する。グラフィックス液晶には秋月電子で販売されている「SG12232」を使用した。この液晶モジュールは結線数が多いため使い勝手は悪いが入手性がいいので試すにはうってつけだろう。

psoc_glcd_02.gif
今回利用する液晶モジュールは1~3kHzのクロックを入力する必要がある。そのクロックをタイマーを使って生成する。「Timers」の「Timer8」をダブルクリックしてプロジェクトに追加したら「Config」メニューの「Interconnect」で画面を設定画面に切り替える。

psoc_glcd_03.gif
「Timer8_1」を右クリックして現れるメニューから「Place」を選択して配置する。そして左側の設定画面で詳細設定をする。
「Clock」を「CPU_32_KHz」に、「Capture」を「Low」に、「TerminalCountOut」を「None」に、「CompareOut」を「Row_0_Output_3」に、「Period」を「15」に、「CompareValue」を「8」に、「CompareTypeを「Less Than Or Equal」に、「InterruptType」を「Caputure」に、「ClockSync」を「Sync to SysClk」にする。
そして中央の部分で内部配線をポート23に接続する。
これでCPUの32KHzクロックが16分周された2KHzのクロックがポート23に出力される。

psoc_glcd_04.gif
次に各ポートの設定をする。「Port_0_0」から「Port_0_7」と「Port_2_0」から「Port_2_6」までをすべて「Strong」にする。
設定が終わったら「View」メニューの「Application Editor」を選択して画面を切り替える。

psoc_glcd_05.gif
そして「Source Files」の「main.c」の中に処理を書く。


//----------------------------------------------------------------------------
// C main line
//----------------------------------------------------------------------------

#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules

//PORT
#define GLCD_PORT_DB PRT0DR
#define GLCD_PORT_CTRL PRT2DR
#define GLCD_PORT_DB_DM0 PRT0DM0
#define GLCD_PORT_DB_DM1 PRT0DM1
#define GLCD_PORT_DB_DM2 PRT0DM2

//PORT Mask
#define GLCD_PORT_CTRL_A0 0x01
#define GLCD_PORT_CTRL_CS1 0x02
#define GLCD_PORT_CTRL_CS2 0x04
//#define GLCD_PORT_CTRL_CLK 0x08 //by Timer
#define GLCD_PORT_CTRL_E 0x10
#define GLCD_PORT_CTRL_RW 0x20
#define GLCD_PORT_CTRL_RES 0x40

//Command
#define GLCD_CMD_OFF 0xAE //1010 1110
#define GLCD_CMD_ON 0xAF //1010 1111
#define GLCD_CMD_START_LINE 0xC0 //110x xxxx (0 to 31)
#define GLCD_CMD_PAGE0 0xB8 //1011 1000
#define GLCD_CMD_PAGE1 0xB9 //1011 1001
#define GLCD_CMD_PAGE2 0xBA //1011 1010
#define GLCD_CMD_PAGE3 0xBB //1011 1011
#define GLCD_CMD_COL_ADDR 0x00 //0xxx xxxx (0 to 79)

#define GLCD_CMD_ADC_RIGHT 0xA0 //1010 0000
#define GLCD_CMD_ADC_LEFT 0xA1 //1010 0001
#define GLCD_CMD_STATIC_OFF 0xA4 //1010 0100
#define GLCD_CMD_STATIC_ON 0xA5 //1010 0101
#define GLCD_CMD_DUTY_16 0xA8 //1010 1000
#define GLCD_CMD_DUTY_32 0xA9 //1010 1001
#define GLCD_CMD_RW_MOD_ON 0xE0 //1110 0000
#define GLCD_CMD_RW_MOD_OFF 0xEE //1110 1110 ('END' Command)
#define GLCD_CMD_RESET 0xE2 //1110 0010


void GLCD_SetDataPortDriveMode(BOOL bWriteOrRead)
{
if(bWriteOrRead)
{
GLCD_PORT_DB_DM0 = 0xFF;
GLCD_PORT_DB_DM1 = 0x00;
GLCD_PORT_DB_DM2 = 0x00;
}
else
{
GLCD_PORT_DB_DM0 = 0x00;
GLCD_PORT_DB_DM1 = 0xFF;
GLCD_PORT_DB_DM2 = 0x00;
}
}

BYTE GLCD_RW_Data(BOOL bWrite,BOOL bCS1,BOOL bCS2,BOOL bCtrl,BYTE cbData)
{
int i;
BYTE cbRead;

if(bWrite)
GLCD_PORT_CTRL &= ~GLCD_PORT_CTRL_RW; //RW -> LOW
else
GLCD_PORT_CTRL |= GLCD_PORT_CTRL_RW; //RW -> HIGH

if(bCtrl)
GLCD_PORT_CTRL &= ~GLCD_PORT_CTRL_A0; //A0 -> LOW
else
GLCD_PORT_CTRL |= GLCD_PORT_CTRL_A0; //A0 -> HIGH

if(bCS1)
GLCD_PORT_CTRL &= ~GLCD_PORT_CTRL_CS1; //CS1 -> LOW
else
GLCD_PORT_CTRL |= GLCD_PORT_CTRL_CS1; //CS1 -> HIGH

if(bCS2)
GLCD_PORT_CTRL &= ~GLCD_PORT_CTRL_CS2; //CS2 -> LOW
else
GLCD_PORT_CTRL |= GLCD_PORT_CTRL_CS2; //CS2 -> HIGH

if(bWrite)
{
GLCD_SetDataPortDriveMode(TRUE);
GLCD_PORT_DB = cbData; //Write Data set
}
else
{
GLCD_SetDataPortDriveMode(FALSE);
GLCD_PORT_DB = 0;
}

GLCD_PORT_CTRL |= GLCD_PORT_CTRL_E; //E -> HIGH


//wait 40ns
for(i = 0; i < 1; i++)
{
}

GLCD_PORT_CTRL &= ~GLCD_PORT_CTRL_E; //E -> LOW

//wait 200ns
for(i = 0; i < 1; i++)
{
}

cbRead = (bWrite) ? 0x00 : GLCD_PORT_DB;

return cbRead;
}


void GLCD_Clear(void)
{
//both CS1 and CS2 is selected!
int nX;
int nY;

GLCD_RW_Data(TRUE,TRUE,FALSE,TRUE,GLCD_CMD_OFF);

for(nY = 0; nY < 4; nY++)
{
GLCD_RW_Data(TRUE,TRUE,TRUE,TRUE,GLCD_CMD_PAGE0 + nY);
GLCD_RW_Data(TRUE,TRUE,TRUE,TRUE,GLCD_CMD_COL_ADDR + 0);

for(nX = 0 ; nX < 62; nX++)
GLCD_RW_Data(TRUE,TRUE,TRUE,FALSE,0x00);
}
GLCD_RW_Data(TRUE,TRUE,TRUE,TRUE,GLCD_CMD_PAGE0);
GLCD_RW_Data(TRUE,TRUE,TRUE,TRUE,GLCD_CMD_COL_ADDR);
GLCD_RW_Data(FALSE,TRUE,FALSE,FALSE,0); //dummy read
GLCD_RW_Data(FALSE,FALSE,TRUE,FALSE,0); //dummy read

GLCD_RW_Data(TRUE,TRUE,FALSE,TRUE,GLCD_CMD_ON);
}

void GLCD_Reset(void)
{
GLCD_RW_Data(TRUE,TRUE,TRUE,TRUE,GLCD_CMD_RESET);
}

void GLCD_Start(void)
{
GLCD_PORT_DB = 0;
GLCD_PORT_CTRL = 0;
GLCD_PORT_CTRL |= GLCD_PORT_CTRL_RES; //Into 68 mode

GLCD_Reset();
GLCD_RW_Data(TRUE,TRUE,TRUE,TRUE,GLCD_CMD_ON);

GLCD_Clear();
}


//
// nX : 0 - 121
// nPage : 0 - 3
//
void GLCD_Position(unsigned char nX,unsigned char nPage)
{
BOOL bCS1;

bCS1 = (nX < 62) ? TRUE : FALSE;
if(!bCS1)
nX -= 62;

GLCD_RW_Data(TRUE,bCS1,!bCS1,TRUE,GLCD_CMD_PAGE0 + nPage);
GLCD_RW_Data(TRUE,bCS1,!bCS1,TRUE,GLCD_CMD_COL_ADDR + nX);
}


//
// nX : 0 - 121
// nY : 0 - 31
//
void GLCD_PutPixel(unsigned char nX,unsigned char nY,BOOL bSet)
{
int nPage;
BOOL bCS1;
BYTE cbRead;

bCS1 = (nX < 62) ? TRUE : FALSE;
nPage = nY >> 3; // = nY / 8;

if(!bCS1)
nX -= 62;

GLCD_RW_Data(TRUE,bCS1,!bCS1,TRUE,GLCD_CMD_PAGE0 + nPage);
GLCD_RW_Data(TRUE,bCS1,!bCS1,TRUE,GLCD_CMD_COL_ADDR + nX);

GLCD_RW_Data(TRUE,bCS1,!bCS1,TRUE,GLCD_CMD_RW_MOD_ON);
cbRead = GLCD_RW_Data(FALSE,bCS1,!bCS1,FALSE,0); //dummy read
cbRead = GLCD_RW_Data(FALSE,bCS1,!bCS1,FALSE,0); //read
if(bSet)
cbRead |= (1 << (nY - (nPage << 3)));
else
cbRead &= ~(1 << (nY - (nPage << 3)));
GLCD_RW_Data(TRUE,bCS1,!bCS1,FALSE,cbRead);
GLCD_RW_Data(TRUE,bCS1,!bCS1,TRUE,GLCD_CMD_RW_MOD_OFF);
}

void main()
{
Timer8_1_DisableInt();
M8C_EnableGInt;
Timer8_1_Start();

GLCD_Start();

GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0xA0);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0xA0);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0xA0);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0xA0);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0xA0);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0xA0);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);
GLCD_RW_Data(TRUE,TRUE,FALSE,FALSE,0x0A);


/* GLCD_PutPixel(120,40,TRUE);
GLCD_PutPixel(0,3,TRUE);
GLCD_PutPixel(2,7,TRUE);

{
int x;
int y;

for(x = 0; x < 122; x+= 5)
{
for(y = 0; y < 32; y+= 5)
{
GLCD_PutPixel(x,y,TRUE);
}
}
}
*/
}





_DSC9054.JPG
これが今回利用したグラフィック液晶モジュール「SG12232」。秋月電子で1500円程度で販売されている。

_DSC9057.JPG
秋月電子のパッケージにはピンヘッダーが含まれている。これを"表面"に取り付ける。こうするとブレッドボードで実験しやすい。ただしケースなどへの組み込みはできなくなる(困難になる)。

_DSC9058.JPG
接続した状態。液晶モジュールの20本すべてを配線する。1ピンをGND、2ピンをVCC、3ピンをPSoCEval1基板のVR端子、4~9ピンをそれぞれポート20~25、10~17ピンをそれぞれポート00~07、18ピンをポート26、19ピンを47Ωの抵抗を介してVCC、20ピンをGNDに接続する。

_DSC9061.JPG
これでプログラムを実行すると書き込んだデータが表示された。



カテゴリー「電子工作」 のエントリー