ラベル OLED の投稿を表示しています。 すべての投稿を表示
ラベル OLED の投稿を表示しています。 すべての投稿を表示

2012年8月17日金曜日

有機ELディスプレイ搭載スイッチIS-C15ANP4をPicoBlazeで制御しよう

先日からピコピコとPicoBlazeを触っていたわけですが、某所で日本開閉器工業社製の有機ELディスプレイ搭載スイッチIS-C15ANP4をPicoBlazeから制御したいと依頼を受けました。


メーカのウェブからダウンロードできる資料には、初期化時に使用するパラメータが列挙されています。このスイッチのディスプレイ・コントローラには、SOLOMON SYSTECH社のSSD1331が搭載されているようです。初期化コードをスイッチに送ってやるだけでディスプレイ・コントローラの初期化は完了です。後は、データを送ればそのまま絵として表示されます。


さて、今回のPicoBlazeのデザインは、先のLEDをピコピコさせたものをそのまま流用しました。
という事はBit Bangで制御するのね、ヒドイ!


ということで、トップのデザインです。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity main is
 Port (
 oled_ss : out std_logic;
 oled_res : out std_logic;
 oled_dc : out std_logic;
 oled_sck : out std_logic;
 oled_sdi : out std_logic;
 clk : in std_logic;
 sw1 : in std_logic);
end main;
architecture RTL of main is
 component kcpsm6
 generic( hwbuild : std_logic_vector(7 downto 0) := X"00";
 interrupt_vector : std_logic_vector(11 downto 0) := X"3FF";
 scratch_pad_memory_size : integer := 64);
 port ( address : out std_logic_vector(11 downto 0);
 instruction : in std_logic_vector(17 downto 0);
 bram_enable : out std_logic;
 in_port : in std_logic_vector(7 downto 0);
 out_port : out std_logic_vector(7 downto 0);
 port_id : out std_logic_vector(7 downto 0);
 write_strobe : out std_logic;
 k_write_strobe : out std_logic;
 read_strobe : out std_logic;
 interrupt : in std_logic;
 interrupt_ack : out std_logic;
 sleep : in std_logic;
 reset : in std_logic;
 clk : in std_logic);
 end component;
 component c15anp4
 generic( C_FAMILY : string := "S6";
 C_RAM_SIZE_KWORDS : integer := 1;
 C_JTAG_LOADER_ENABLE : integer := 0);
 Port ( address : in std_logic_vector(11 downto 0);
 instruction : out std_logic_vector(17 downto 0);
 enable : in std_logic;
 rdl : out std_logic;
 clk : in std_logic);
 end component;
signal address : std_logic_vector(11 downto 0);
signal instruction : std_logic_vector(17 downto 0);
signal port_id : std_logic_vector(7 downto 0);
signal in_port : std_logic_vector(7 downto 0);
signal out_port : std_logic_vector(7 downto 0);
signal read_strobe : std_logic;
signal write_strobe : std_logic;
signal port000 : std_logic_vector(7 downto 0);
begin
 processor: kcpsm6
 generic map ( hwbuild => X"00",
 interrupt_vector => X"3FF",
 scratch_pad_memory_size => 64)
 port map(
 address => address,
 instruction => instruction,
 port_id => port_id,
 interrupt => '0',
 write_strobe => write_strobe,
 out_port => out_port,
 read_strobe => read_strobe,
 in_port => in_port,
 sleep => '0',
 reset => '0',
 clk => clk);
 program: c15anp4
 generic map( C_FAMILY => "S6",
 C_RAM_SIZE_KWORDS => 1,
 C_JTAG_LOADER_ENABLE => 0)
 port map( address => address,
 instruction => instruction,
 enable => '1',
 clk => clk);
 out_ratch : process(clk) is
 begin
 if clk'event and clk='1' then
 if write_strobe='1' then
 if port_id ="00000000" then
 port000 <= out_port;
 end if;
 end if;
 end if;
 end process out_ratch;
 in_ratch : process(clk) is
 begin
 if clk'event and clk='1' then
 if read_strobe='1' then
 if port_id ="00000000" then
 in_port(0) <= not sw1;
 end if;
 end if;
 end if;
 end process in_ratch;
 oled_ss <= port000(0);
 oled_res <= port000(1);
 oled_dc <= port000(2);
 oled_sck <= port000(3);
 oled_sdi <= port000(4);
end RTL;

回路はLX-9 MicroBlazeのPMODのピンに超適当に配線です。

NET "oled_ss" LOC = D18;
NET "oled_res" LOC = D17;
NET "oled_dc" LOC = G14;
NET "oled_sck" LOC = F14;
NET "oled_sdi" LOC = F15;


さて、後はI/Oをバンバン打つだけです。

 ; =========================================================
 ; Port000[0] : SS- : Slave Select (Low Active)
 ; Port000[1] : RES : Reset (Low Active)
 ; Port000[2] : D/C : Data/Command (Data=High, Command=Low)
 ; Port000[3] : SCK : Serial Clock (Up Edge Trigger)
 ; Port000[4] : SDI : Serial Data
 ; =========================================================
 ; ---------------------------------------------------------
 ; Register Name
 ; ---------------------------------------------------------
 ; SPI Data Register
 NAMEREG s0, SPIDATA
 ; Port Data Register
 NAMEREG s1, PORTDAT
 ; Delay Counter No.1
 NAMEREG s2, DLYCNT1
 ; Delay Counter No.2
 NAMEREG s3, DLYCNT2
 ; Delay Counter No.3
 NAMEREG s4, DLYCNT3
 ; Send Counter No.1
 NAMEREG s5, SNDCNT1
 ; Send Counter No.2
 NAMEREG s6, SNDCNT2
 ; Temporary Register No.1
 NAMEREG s7, TEMP_I
 ; Temporary Register No.2
 NAMEREG s8, TEMP_J
 ; ---------------------------------------------------------
 ; Constant Variables
 ; ---------------------------------------------------------
 CONSTANT PORT000, 00
 CONSTANT OLED_SS, 01
 CONSTANT OLED_RES, 02
 CONSTANT OLED_DC, 04
 CONSTANT OLED_SCK, 08
 CONSTANT OLED_SDI, 10
MAIN:
 CALL INIT
TESTLOOP:
 CALL INIT_ADDR
 CALL FILLR
 CALL LONGDELAY
 CALL INIT_ADDR
 CALL FILLG
 CALL LONGDELAY
 CALL INIT_ADDR
 CALL FILLB
 CALL LONGDELAY
 CALL INIT_ADDR
 CALL FILLW
 CALL LONGDELAY
 JUMP TESTLOOP
INIT_ADDR:
 ; ---------------------------------------------------------
 ; Setup Column Address
 ; ---------------------------------------------------------
 LOAD SPIDATA, 15
 CALL SEND_CMD
 LOAD SPIDATA, 10
 CALL SEND_CMD
 LOAD SPIDATA, 4F
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Setup Row Address
 ; ---------------------------------------------------------
 LOAD SPIDATA, 75
 CALL SEND_CMD
 LOAD SPIDATA, 00
 CALL SEND_CMD
 LOAD SPIDATA, 2F
 CALL SEND_CMD
 RETURN
FILLR:
 LOAD TEMP_I, 30
FILLR1:
 LOAD TEMP_J, 40
FILLR2:
 ; ---------------------------------------------------------
 ; Byte0 = B[4:0] + G[5:3]
 ; Byte1 = G[2:0] + R[4:0]
 ; ---------------------------------------------------------
 LOAD SPIDATA, 00
 CALL SEND_DAT
 LOAD SPIDATA, 1F
 CALL SEND_DAT
 SUB TEMP_J, 01
 JUMP NZ, FILLR2
 SUB TEMP_I, 01
 JUMP NZ, FILLR1
 RETURN
FILLG:
 LOAD TEMP_I, 30
FILLG1:
 LOAD TEMP_J, 40
FILLG2:
 ; ---------------------------------------------------------
 ; Byte0 = B[4:0] + G[5:3]
 ; Byte1 = G[2:0] + R[4:0]
 ; ---------------------------------------------------------
 LOAD SPIDATA, 07
 CALL SEND_DAT
 LOAD SPIDATA, C0
 CALL SEND_DAT
 SUB TEMP_J, 01
 JUMP NZ, FILLG2
 SUB TEMP_I, 01
 JUMP NZ, FILLG1
 RETURN
FILLB:
 LOAD TEMP_I, 30
FILLB1:
 LOAD TEMP_J, 40
FILLB2:
 ; ---------------------------------------------------------
 ; Byte0 = B[4:0] + G[5:3]
 ; Byte1 = G[2:0] + R[4:0]
 ; ---------------------------------------------------------
 LOAD SPIDATA, F8
 CALL SEND_DAT
 LOAD SPIDATA, 00
 CALL SEND_DAT
 SUB TEMP_J, 01
 JUMP NZ, FILLB2
 SUB TEMP_I, 01
 JUMP NZ, FILLB1
 RETURN
FILLW:
 LOAD TEMP_I, 30
FILLW1:
 LOAD TEMP_J, 40
FILLW2:
 ; ---------------------------------------------------------
 ; Byte0 = B[4:0] + G[5:3]
 ; Byte1 = G[2:0] + R[4:0]
 ; ---------------------------------------------------------
 LOAD SPIDATA, FF
 CALL SEND_DAT
 LOAD SPIDATA, FF
 CALL SEND_DAT
 SUB TEMP_J, 01
 JUMP NZ, FILLW2
 SUB TEMP_I, 01
 JUMP NZ, FILLW1
 RETURN
INIT:
 ; =========================================================
 ; SS- : Slave Select (Low Active)
 ; RES : Reset (Low Active)
 ; D/C : Data/Command (Data=High, Command=Low)
 ; SCK : Serial Clock (Up Edge Trigger)
 ; SDI : Serial Data
 ; =========================================================
 ; ---------------------------------------------------------
 ; Reset Active
 ; ---------------------------------------------------------
 LOAD PORTDAT, 00
 OUTPUT PORTDAT, PORT000
 CALL DELAY
 ; ---------------------------------------------------------
 ; Reset Inactive
 ; ---------------------------------------------------------
 LOAD PORTDAT, OLED_RES
 OUTPUT PORTDAT, PORT000
 CALL DELAY
 ; ---------------------------------------------------------
 ; Setup Column Address
 ; ---------------------------------------------------------
 LOAD SPIDATA, 15
 CALL SEND_CMD
 LOAD SPIDATA, 10
 CALL SEND_CMD
 LOAD SPIDATA, 4F
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Setup Row Address
 ; ---------------------------------------------------------
 LOAD SPIDATA, 75
 CALL SEND_CMD
 LOAD SPIDATA, 00
 CALL SEND_CMD
 LOAD SPIDATA, 2F
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Setup Contrast Color A
 ; ---------------------------------------------------------
 LOAD SPIDATA, 81
 CALL SEND_CMD
 LOAD SPIDATA, 19
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Setup Contrast Color B
 ; ---------------------------------------------------------
 LOAD SPIDATA, 82
 CALL SEND_CMD
 LOAD SPIDATA, 14
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Setup Contrast Color C
 ; ---------------------------------------------------------
 LOAD SPIDATA, 83
 CALL SEND_CMD
 LOAD SPIDATA, 24
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Master Current Control
 ; ---------------------------------------------------------
 LOAD SPIDATA, 87
 CALL SEND_CMD
 LOAD SPIDATA, 0F
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Set Display Start Line
 ; ---------------------------------------------------------
 LOAD SPIDATA, A1
 CALL SEND_CMD
 LOAD SPIDATA, 00
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Set Display Offset
 ; ---------------------------------------------------------
 LOAD SPIDATA, A2
 CALL SEND_CMD
 LOAD SPIDATA, 10
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Set Display Mode
 ; ---------------------------------------------------------
 LOAD SPIDATA, A4
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Set Multiplex Ratio
 ; ---------------------------------------------------------
 LOAD SPIDATA, A8
 CALL SEND_CMD
 LOAD SPIDATA, 2F
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Dim Mode Setting
 ; ---------------------------------------------------------
 LOAD SPIDATA, AB
 CALL SEND_CMD
 LOAD SPIDATA, 12
 CALL SEND_CMD
 LOAD SPIDATA, 0C
 CALL SEND_CMD
 LOAD SPIDATA, 14
 CALL SEND_CMD
 LOAD SPIDATA, 12
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Set Master Configuration
 ; ---------------------------------------------------------
 LOAD SPIDATA, AD
 CALL SEND_CMD
 LOAD SPIDATA, 8E
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Phase Period Adjustment
 ; ---------------------------------------------------------
 LOAD SPIDATA, B1
 CALL SEND_CMD
 LOAD SPIDATA, 44
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Display Clock Divider
 ; ---------------------------------------------------------
 LOAD SPIDATA, B3
 CALL SEND_CMD
 LOAD SPIDATA, A0
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Enable Linear Gray Scale
 ; ---------------------------------------------------------
 LOAD SPIDATA, B9
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Set Precharge Level
 ; ---------------------------------------------------------
 LOAD SPIDATA, BB
 CALL SEND_CMD
 LOAD SPIDATA, 12
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Set VCOMH
 ; ---------------------------------------------------------
 LOAD SPIDATA, BE
 CALL SEND_CMD
 LOAD SPIDATA, 28
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Color Depth = 64K
 ; ---------------------------------------------------------
 LOAD SPIDATA, A0
 CALL SEND_CMD
 LOAD SPIDATA, 70
 CALL SEND_CMD
 ; ---------------------------------------------------------
 ; Set Display Normal
 ; ---------------------------------------------------------
 LOAD SPIDATA, AF
 CALL SEND_CMD
 RETURN
SEND_DAT:
 ; =========================================================
 ; SS- : Slave Select (Low Active)
 ; RES : Reset (Low Active)
 ; D/C : Data/Command (Data=High, Command=Low)
 ; SCK : Serial Clock (Up Edge Trigger)
 ; SDI : Serial Data
 ; =========================================================
SEND_DAT_SLAVE_ACTIVE:
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OR PORTDAT, OLED_DC
SEND_DAT_SETUP:
 LOAD SNDCNT1, 08
 LOAD SNDCNT2, SPIDATA
SEND_DAT_LOOP:
 SL0 SNDCNT2
 JUMP C, SEND_DAT_H
 JUMP SEND_DAT_L
SEND_DAT_H:
 ; ---------------------------------------------------------
 ; SDI=HIGH, SCK=LOW
 ; ---------------------------------------------------------
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OR PORTDAT, OLED_DC
 OR PORTDAT, OLED_SDI
 OUTPUT PORTDAT, PORT000
 CALL DELAY
 ; ---------------------------------------------------------
 ; SDI=HIGH, SCK=HIGH
 ; ---------------------------------------------------------
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OR PORTDAT, OLED_DC
 OR PORTDAT, OLED_SCK
 OR PORTDAT, OLED_SDI
 OUTPUT PORTDAT, PORT000
 CALL DELAY
 ; ---------------------------------------------------------
 ; NEXT
 ; ---------------------------------------------------------
 JUMP SEND_DAT_NEXT
SEND_DAT_L:
 ; ---------------------------------------------------------
 ; SDI=LOW, SCK=LOW
 ; ---------------------------------------------------------
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OR PORTDAT, OLED_DC
 OUTPUT PORTDAT, PORT000
 CALL DELAY
 ; ---------------------------------------------------------
 ; SDI=LOW, SCK=HIGH
 ; ---------------------------------------------------------
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OR PORTDAT, OLED_DC
 OR PORTDAT, OLED_SCK
 OUTPUT PORTDAT, PORT000
 CALL DELAY
 ; ---------------------------------------------------------
 ; NEXT
 ; ---------------------------------------------------------
 JUMP SEND_DAT_NEXT
SEND_DAT_NEXT:
 SUB SNDCNT1, 01
 JUMP NZ, SEND_DAT_LOOP
SEND_DAT_END:
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OR PORTDAT, OLED_DC
 OR PORTDAT, OLED_SS
 OUTPUT PORTDAT, PORT000
 RETURN
SEND_CMD:
 ; =========================================================
 ; SS- : Slave Select (Low Active)
 ; RES : Reset (Low Active)
 ; D/C : Data/Command (Data=High, Command=Low)
 ; SCK : Serial Clock (Up Edge Trigger)
 ; SDI : Serial Data
 ; =========================================================
SEND_CMD_SLAVE_ACTIVE:
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
SEND_CMD_SETUP:
 LOAD SNDCNT1, 08
 LOAD SNDCNT2, SPIDATA
SEND_CMD_LOOP:
 SL0 SNDCNT2
 JUMP C, SEND_CMD_H
 JUMP SEND_CMD_L
SEND_CMD_H:
 ; ---------------------------------------------------------
 ; SDI=HIGH, SCK=LOW
 ; ---------------------------------------------------------
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OR PORTDAT, OLED_SDI
 OUTPUT PORTDAT, PORT000
 CALL DELAY
 ; ---------------------------------------------------------
 ; SDI=HIGH, SCK=HIGH
 ; ---------------------------------------------------------
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OR PORTDAT, OLED_SCK
 OR PORTDAT, OLED_SDI
 OUTPUT PORTDAT, PORT000
 CALL DELAY
 ; ---------------------------------------------------------
 ; NEXT
 ; ---------------------------------------------------------
 JUMP SEND_CMD_NEXT
SEND_CMD_L:
 ; ---------------------------------------------------------
 ; SDI=LOW, SCK=LOW
 ; ---------------------------------------------------------
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OUTPUT PORTDAT, PORT000
 CALL DELAY
 ; ---------------------------------------------------------
 ; SDI=LOW, SCK=HIGH
 ; ---------------------------------------------------------
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OR PORTDAT, OLED_SCK
 OUTPUT PORTDAT, PORT000
 CALL DELAY
 ; ---------------------------------------------------------
 ; NEXT
 ; ---------------------------------------------------------
 JUMP SEND_CMD_NEXT
SEND_CMD_NEXT:
 SUB SNDCNT1, 01
 JUMP NZ, SEND_CMD_LOOP
SEND_CMD_END:
 LOAD PORTDAT, 00
 OR PORTDAT, OLED_RES
 OR PORTDAT, OLED_SS
 OUTPUT PORTDAT, PORT000
 RETURN
DELAY:
 LOAD DLYCNT1, 01
DELAY1:
 LOAD DLYCNT2, 01
DELAY2:
 SUB DLYCNT2, 01
 JUMP NZ, DELAY2
 SUB DLYCNT1, 01
 JUMP NZ, DELAY1
 RETURN
LONGDELAY:
 LOAD DLYCNT1, 80
LONGDELAY1:
 LOAD DLYCNT2, FF
LONGDELAY2:
 LOAD DLYCNT3, FF
LONGDELAY3:
 SUB DLYCNT3, 01
 JUMP NZ, LONGDELAY3
 SUB DLYCNT2, 01
 JUMP NZ, LONGDELAY2
 SUB DLYCNT1, 01
 JUMP NZ, LONGDELAY1
 RETURN

もう完全にPicoBlazeの使い方としてはおかしいですが、第一段階としては気にしません。
上記のコードで「赤」、「緑」、「青」、「白」と順に表示を繰り返す事ができます。


[フレーム]

リソースの使用率ですが、以下のようになりました。


Bit Bangはあんまりなので、SPIモジュールを作ってやってデータを渡すのが良いでしょう。
データを渡して、転送開始入力信号と転送完了出力信号が出てくるようなモジュールです。

フォントなどを内蔵すればもっと手軽に表示が楽しめそう。
上記を雛型にすればこういった拡張も簡単です。

ちなみに、今回はBit Bangの基本動作を外部のロジック・アナライザで確認した後、セットアップとホールド、クロックサイクルを見ながらアセンブラ・コードをチューニングし、波形が期待通りに出力されている事を確認した後で、最後にIS-C15ANP4を接続するという形で作業しました。(ChipScope使えよという感じです。)


PicoBlazeのアセンブラも、最初のバージョンより気が利くようになっていて、一度立ち上げてプログラム・ファイル名を入力しておけば「R」をタイプするだけで再コンパイルできるようになっています。


なので、アセンブルの後で生成されたVHDLををプロジェクトにコピーするバッチファイルを作っておけば、「アセンブル→再インプリメンテーション」の流れをスムーズにこなす事ができます。


こんな感じで(超適当だけど)半田付けを含めて小1時間ほどでPicoBlazeからIS-C15ANP4に絵が出せるようになりました。


念のために書いておくと、IS-C15ANP4には決められた電源シーケンスがあります。
製品に使用する場合、きちんとシーケンスを守るように設計しましょう。


最後にグリーンな表示。

ちなみに、先ほどの初期化コードの場合、2バイトで1ピクセルを表現するようになっています。
BとRが5ビット、Gが6ビットで、1バイト目がB[4:0] + G[5:3]、2バイト目がG[2:0] + R[4:0]です。


AltStyle によって変換されたページ (->オリジナル) /