aitendoのTFT液晶モジュールにCPLDを使って動画を表示する

MAX II CPLD(EPM570T100C5)を使って、SDカードに保存した無圧縮動画を液晶ZY-FGD1442701V1, ST7735に表示しました。CPLD内部クロック5.5 MHzを使って、19 fpsとなりました。SDカードSPIモードのクロックは25 MHzまで上げられますから、fpsをもっと上げることも可能と思われます。(追記 24 MHzで80 fpsでした。)SDカードの読み込み遅延を最小限とするために、SDカードアソシエーション推奨のSD Formatterでフォーマットして、マルチブロックリードで連続して読み込んでいます。液晶の方はパラレルライトなので、この程度の速度では液晶がスピードのボトルネックにはなりません。

マルチブロックリード中にCMD0を送ったところ、リセットされなかったのですが、そういうものなのでしょうか。読み込み終了処理は面倒だったので、CMD0を送る前にリードストップのCMD12を送って、リセットを行うことにしました。

f:id:beiz23:20140215192455j:image:w360
f:id:beiz23:20140215201029j:image:w260f:id:beiz23:20140215200953j:image:w260
カタハネopを表示。公式mpegをVirtualDubModなどを使って連番BMPにした後、スクリプトで無圧縮バイナリに変換。十分ぬめぬめ動きました。一晩中動画再生をさせてみましたが朝でも安定して再生していました。あたりまえか。

f:id:beiz23:20140215215231j:image:w360

verilog HDLコードなどはこちら。500 LE。エラー処理は適当で、とりあえず動くレベルですが。


module mov(
    output CSX, CLK, DI,
    input DO, rstx,
    output LCD_RSTX, LCD_CSX, LCD_D_CX, LCD_WRX,
    output [7:0] DATA
);

//clk
wire clk_5M5;
rc_osc rc_osc( rstx, clk_5M5 );//5.5 MHz

//reg rstx;
wire en;
wire [7:0] data;

wire vs, en_dat, req;
//lcd etc.
lcdzy lcdzy( LCD_RSTX, LCD_CSX, LCD_D_CX, LCD_WRX, DATA, rstx, clk_5M5, req, en_dat, vs, data );

//wire clk;
wire clk;
assign clk = (req ? clk_5M5 : 1'b0);
//sd
sd_cont sd_cont( clk, req, CSX, CLK, DI, DO, en_dat, vs, data );

endmodule

lcdzy.v


module lcdzy(
output reg RESX, //reset
CSX, //chip select low enable
D_CX, //data / command
WRX, //write enable
output reg [7:0] DATA,
input rstx, clk,
output reg req,
input en_data, vs,
input [7:0] data_in
);

//output RDX; //-> always write
reg [3:0] state, next_st; //state reg.
reg [15:0] wait_ms;
reg [5:0] init_addr;
wire [7:0] init_in; //, data_in;
//reg [15:0] data_addr;//16 bit  7+7+1 128*128*2
reg [13:0] wait_cnt;
reg [7:0] write_data;
wire init_dcx;
reg [11:0] frame_cnt;//0xbe8 = 3048//12bit

LCD_INIT_SEQ lcd_init_seq(init_addr, init_in, init_dcx);
//LCD_DATA_SEQ lcd_data_seq(data_addr, data_in);

// BIDIRECTIONAL TRI STATE LCD DATA BUS
//assign DATA_BUS = (RDX? 8'bz: data_value);


`define LCD_IDOL 4'h0
`define LCD_INIT 4'h1
`define RESET1 4'h2
`define RESET2 4'h3
`define SLEEP_OUT 4'h4
`define DISP_ON 4'h5
`define INIT_SEQ 4'h6
`define RAM_WR 4'h7
`define DATA_REQ 4'h8
`define DATA_SEQ 4'h9
`define WRITE 4'ha
`define WRITE_ENA 4'hb
`define LCD_WAIT 4'hc
`define LCD_SOFT_RST 4'hd

`define LCD_MS_CNT 14'd5555 // 1e-3 s * 5.5e6 Hz = 5.5e3
`define FRAME_CNT_MAX 12'hbe8//12'd3048//

//clk gen -> slow enogh at 3.3 MHz
/*always @ posedge clk_3M3 or negede reset)
    if (!rst) begin
        clk_count_
        */


//state reg
/*always @ ( posedge clk or negedge rst ) begin
    if ( !rst )
        cur_st <= INIT;
    else
        cur_st <= next_st;
end*/

//state gen
always @ ( posedge clk or negedge rstx ) begin
    if ( !rstx ) begin
        state <= `LCD_IDOL;
        wait_ms <= 16'h0;
        wait_cnt <= 1'b0;
        init_addr <= 6'h0;
        RESX <= 1'b1;
        CSX <= 1'b1;
        D_CX <= 1'b0;
        WRX <= 1'b0;
        req <= 1'b0;
        frame_cnt <= 1'b0;
    end else begin
        case ( state )
            `LCD_IDOL: begin
                next_st <= `LCD_INIT;
                state <= `LCD_WAIT;
                wait_ms <= 16'h1000;
                wait_cnt <= 1'b0;
                init_addr <= 6'h0;
                req <= 1'b0;
                RESX <= 1'b1;
                CSX <= 1'b1;
                D_CX <= 1'b0;
                WRX <= 1'b0;
                frame_cnt <= 1'b0;
            end
            `LCD_INIT: begin //wait lcd pow on
                RESX <= 1'b1;
                CSX <= 1'b1;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                state <= `LCD_WAIT;
                next_st <= `RESET1;
                wait_ms <= 6'd50;//50ms
            end
            `RESET1: begin
                RESX <= 1'b0;//RESET
                CSX <= 1'b1;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                state <= `LCD_WAIT;
                wait_ms <= 6'd1;//more than 10us
                next_st <= `RESET2;
            end
            `RESET2: begin//WAIT stable
                RESX <= 1'b1;
                CSX <= 1'b1;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                state <= `LCD_WAIT;
                wait_ms <= 7'd120;//120ms
                next_st <= `SLEEP_OUT;
            end
            `SLEEP_OUT: begin//sleep out
                RESX <= 1'b1;
                CSX <= 1'b0;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                write_data <= 8'h11;
                state <= `WRITE;
                next_st <= `DISP_ON;
                wait_ms <= 7'd120;//120ms
            end
            `DISP_ON: begin//disp on
                RESX <= 1'b1;
                CSX <= 1'b0;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                write_data <= 8'h29;
                state <= `WRITE;
                next_st <= `INIT_SEQ;
                wait_ms <= 7'd120;//120ms
            end
            `INIT_SEQ: begin
                if ( init_in == 8'h00
                && init_dcx == 1'b0 ) begin //end init
                    RESX <= 1'b1;
                    CSX <= 1'b1;
                    D_CX <= 1'b0;
                    WRX <= 1'b1;
                    state <= `DATA_REQ;
                    init_addr <= 4'h0;
                    //DATA <= 8'h00;
                end else begin
                    RESX <= 1'b1;
                    CSX <= 1'b0;
                    D_CX <= init_dcx;
                    WRX <= 1'b1;
                    write_data <= init_in;
                    state <= `WRITE;
                    next_st <= `INIT_SEQ;
                    init_addr <= init_addr + 1'b1;
                end
            end
            `DATA_REQ: begin
                req <= 1'b1;
                RESX <= 1'b1;
                CSX <= 1'b0;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                if ( en_data )
                    if ( vs ) begin
                        if ( frame_cnt >= `FRAME_CNT_MAX ) begin
                            state <= `LCD_IDOL;
                            frame_cnt <= 1'b0;
                        end else begin
                            state <= `RAM_WR;
                            frame_cnt <= frame_cnt + 1'b1;
                        end
                    end else
                        state <= `DATA_SEQ;
                else
                    state <= `DATA_REQ;
            end
            `RAM_WR: begin
                RESX <= 1'b1;
                CSX <= 1'b0;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                write_data <= 8'h2c;
                state <= `WRITE;
                next_st <= `DATA_SEQ;
                wait_ms <= 1'b0;//0 ms
            end
            `DATA_SEQ: begin
                RESX <= 1'b1;
                CSX <= 1'b0;
                D_CX <= 1'b1;
                WRX <= 1'b1;
                write_data <= data_in;
                state <= `WRITE;
                next_st <= `DATA_REQ;
            end
            `WRITE: begin
                WRX <= 1'b0;//wait 30 ns
                DATA <= write_data;
                state <= `WRITE_ENA;
            end
            `WRITE_ENA: begin
                WRX <= 1'b1;//wait 30 ns
                if (wait_ms == 0)
                    state <= next_st;
                else
                    state <= `LCD_WAIT;
            end
            `LCD_WAIT: begin
                if ( wait_ms > 1'b0 ) begin
                    state <= `LCD_WAIT;
                    if ( wait_cnt < `LCD_MS_CNT ) begin
                        wait_cnt <= wait_cnt + 1'b1;
                    end else begin
                        wait_cnt <= 1'b0;
                        wait_ms <= wait_ms - 1'b1;
                    end
                end else begin
                    state <= next_st;
                    wait_cnt <= 1'b0;
                end
            end
            `LCD_SOFT_RST: begin //software reset
                RESX <= 1'b1;
                CSX <= 1'b0;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                write_data <= 8'h01;
                state <= `WRITE;
                next_st <= `SLEEP_OUT;
                wait_ms <= 7'd120;
            end
            default: begin
                RESX <= 1'b1;
                CSX <= 1'b1;
                D_CX <= 1'b1;
                WRX <= 1'b1;
                DATA <= 8'h00;
                state = `LCD_IDOL;
            end
        endcase
    end
end

endmodule


module LCD_INIT_SEQ ( addr, out, dcx );
input [5:0] addr;
output reg [7:0] out;
output reg dcx;

always
    case ( addr )// after soft_reset, sleep_out
        6'h00: begin out <= 8'h36; dcx <= 1'b0; end//Memory data acc
        6'h01: begin out <= 8'h88; dcx <= 1'b1; end//mirror xy BGR
        6'h02: begin out <= 8'h3a; dcx <= 1'b0; end//interface
        6'h03: begin out <= 8'h05; dcx <= 1'b1; end//16bit mode
        6'h04: begin out <= 8'h2a; dcx <= 1'b0; end//column addr set
        6'h05: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h06: begin out <= 8'h02; dcx <= 1'b1; end//02h
        6'h07: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h08: begin out <= 8'h81; dcx <= 1'b1; end//81h
        6'h09: begin out <= 8'h2b; dcx <= 1'b0; end//row addr set
        6'h0a: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h0b: begin out <= 8'h03; dcx <= 1'b1; end//03h
        6'h0c: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h0d: begin out <= 8'h82; dcx <= 1'b1; end//82h
        6'h0e: begin out <= 8'hc1; dcx <= 1'b0; end//POW CTL 2 VGHH VCLL
        6'h0f: begin out <= 8'h07; dcx <= 1'b1; end//14.7V, -12.25V
        6'h10: begin out <= 8'hc5; dcx <= 1'b0; end//VCOM CTL1
        6'h11: begin out <= 8'h3c; dcx <= 1'b1; end//VCOMH
        6'h12: begin out <= 8'h4f; dcx <= 1'b1; end//VCOML
        6'h13: begin out <= 8'he0; dcx <= 1'b0; end//gamma  +
        6'h14: begin out <= 8'h06; dcx <= 1'b1; end//
        6'h15: begin out <= 8'h0e; dcx <= 1'b1; end//
        6'h16: begin out <= 8'h05; dcx <= 1'b1; end//
        6'h17: begin out <= 8'h20; dcx <= 1'b1; end//
        6'h18: begin out <= 8'h27; dcx <= 1'b1; end//
        6'h19: begin out <= 8'h23; dcx <= 1'b1; end//
        6'h1a: begin out <= 8'h1c; dcx <= 1'b1; end//
        6'h1b: begin out <= 8'h21; dcx <= 1'b1; end//
        6'h1c: begin out <= 8'h20; dcx <= 1'b1; end//
        6'h1d: begin out <= 8'h1c; dcx <= 1'b1; end//
        6'h1e: begin out <= 8'h26; dcx <= 1'b1; end//
        6'h1f: begin out <= 8'h2f; dcx <= 1'b1; end//
        6'h20: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h21: begin out <= 8'h03; dcx <= 1'b1; end//
        6'h22: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h23: begin out <= 8'h24; dcx <= 1'b1; end//
        6'h24: begin out <= 8'he1; dcx <= 1'b0; end//gamma -
        6'h25: begin out <= 8'h06; dcx <= 1'b1; end//
        6'h26: begin out <= 8'h10; dcx <= 1'b1; end//
        6'h27: begin out <= 8'h05; dcx <= 1'b1; end//
        6'h28: begin out <= 8'h21; dcx <= 1'b1; end//
        6'h29: begin out <= 8'h27; dcx <= 1'b1; end//
        6'h2a: begin out <= 8'h22; dcx <= 1'b1; end//
        6'h2b: begin out <= 8'h1c; dcx <= 1'b1; end//
        6'h2c: begin out <= 8'h21; dcx <= 1'b1; end//
        6'h2d: begin out <= 8'h1f; dcx <= 1'b1; end//
        6'h2e: begin out <= 8'h1d; dcx <= 1'b1; end//
        6'h2f: begin out <= 8'h27; dcx <= 1'b1; end//
        6'h30: begin out <= 8'h2f; dcx <= 1'b1; end//
        6'h31: begin out <= 8'h05; dcx <= 1'b1; end//
        6'h32: begin out <= 8'h03; dcx <= 1'b1; end//
        6'h33: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h34: begin out <= 8'h3f; dcx <= 1'b1; end//

        default: begin out <= 8'h00; dcx <= 1'b0; end//nop -> end
    endcase
endmodule

sd_cont.v


module sd_cont(
    input clk_5M5, rstx,
    output reg CSX,
    output CLK, DI,
    input DO,
    output reg en, // enable
    output vs, // vertical sync
    output reg [7:0] out_data
);

wire [7:0] read_byte;
reg [7:0] cmd, cmd_crc, cmd_res, write_byte, req_res;
reg [31:0] cmd_addr;
wire spi_en_wr, spi_en_rd;
reg clk_400k;
reg [3:0] clk_cnt_400k;
reg [7:0] dummy_cnt;
wire clk_slow;
reg [4:0] state, state_aft_w;
reg [2:0] write_state;
reg [15:0] wait_ms, wait_cnt;
reg [4:0] ws_time_out;
reg csx, crc_cnt;
reg [8:0] rd_cnt; //9bit
reg [14:0] data_cnt;//128*128 *2 = 0h4000 *2 -> 12+2+1 = 15 bit
//assign en = 1'b0;

spi spi(csx, CLK, DO, DI, write_byte, read_byte, spi_en_wr, spi_en_rd);

`define MS_CNT ( clk_slow ? 14'd0400 : 14'd5555 ) // 1e-3 s * 5.5e6 Hz = 5.5e3
`define PON 5'h0
`define DUMMY_CLK 5'h1
`define STOP_RD 5'h2
`define SOFT_RST 5'h3
`define SOFT_RST_RES 5'h4
`define INIT 5'h5
`define INIT_RES 5'h6
`define MULTI_READ 5'h7
`define MULTI_READ_RES 5'h8
`define SINGLE_READ 5'h9
`define SINGLE_READ_RES 5'ha
`define READ_DATA_PACKET_HD 5'hb
`define READ_DATA_PACKET_BD 5'hc
`define READ_DATA_PACKET_CRC 5'hd
`define SD_IDOL 5'he
`define CMD_WRITE 5'hf
`define SD_WAIT 5'h10

`define CMD_BIT 8'b01000000
/*cmd write state*/
`define WS_CMD 3'h0
`define WS_ADDR1 3'h1
`define WS_ADDR2 3'h2
`define WS_ADDR3 3'h3
`define WS_ADDR4 3'h4
`define WS_CRC 3'h5
`define WS_FF 3'h6
`define WS_RES 3'h7


`define WS_TIME_OUT 5'h1f
`define BLOCK_SIZE 9'h1ff

//400 kHz in init 5.5e6/400e3 ~ 14
always @ ( posedge clk_5M5 or negedge rstx ) begin
    if ( !rstx ) begin
        clk_cnt_400k <= 4'h0;
        clk_400k <= 1'b0;
    end else if ( clk_cnt_400k < 4'he ) begin
        clk_cnt_400k <= clk_cnt_400k + 1'b1;
        clk_400k <= clk_400k;
    end else begin
        clk_cnt_400k <= 4'h0;
      clk_400k <= ~clk_400k;
    end
end

//clk supply to SD
assign CLK = ( state_aft_w <= `INIT ) ? clk_400k : clk_5M5;
assign clk_slow = ( state_aft_w <= `INIT );

always @ ( negedge CLK )
    CSX <= csx;

always @ ( negedge en or negedge rstx ) begin
    if ( !rstx )
        data_cnt <= 1'b0;
    else
        data_cnt <= data_cnt + 1'b1;
end

assign vs = ( data_cnt == 0 );
//jtag_probe jtag_probe({spi_en_wr, state, state_aft_w, write_state, ws_time_out, CLK});

// state, CSX, write_byte, read_byte, spi_en_wr
always @ ( posedge CLK or negedge rstx ) begin
    if ( !rstx ) begin
        state <= `PON;
        write_byte <= 8'hff;
        en <= 0;
        csx <= 1'b1;
    end else begin
        case ( state )
            `PON: begin
                csx <= 1'b1;
                state_aft_w <= `DUMMY_CLK;
                state <= `SD_WAIT;
                wait_ms <= 16'h1; // power on and wait > 1ms
                write_byte <= 8'hff;
                dummy_cnt <= 1'b0;
                en <= 0;
                rd_cnt <= 1'b0;
                wait_cnt <= 1'b0;
                write_state <= `WS_CMD;
                crc_cnt <= 1'b0;
            end
            `DUMMY_CLK: begin //dummy clock > 74 with CSX = 1, 400kHz
                csx <= 1'b1;
                if ( dummy_cnt > 8'd74 ) begin
                    state <= `STOP_RD;
                    dummy_cnt <= 1'b0;
                end else begin
                    dummy_cnt <= dummy_cnt + 1'b1;
                end
            end
            `STOP_RD: begin// CMD12
                csx <= 1'b1;
                cmd <= 6'd12;
                cmd_addr <= 32'd0;
                cmd_crc <= 7'b0;
                state <= `CMD_WRITE;
                state_aft_w <= `SOFT_RST;
            end
            `SOFT_RST: begin// CMD0 with CSX = 0
                csx <= 1'b1;
                cmd <= 6'd0;
                cmd_addr <= 32'd0;
                cmd_crc <= 7'b1001010;
                state <= `CMD_WRITE;
                state_aft_w <= `SOFT_RST_RES;
            end
            `SOFT_RST_RES: begin
                csx <= 1'b1;
                if ( cmd_res == 8'h01 )
                    state <= `INIT;
                else
                    state <= `PON;
            end
            `CMD_WRITE: begin
                csx <= 1'b0;
                if ( spi_en_wr ) begin
                    case ( write_state )
                        `WS_CMD: begin
                            write_byte <= ( cmd | `CMD_BIT );
                            write_state <= `WS_ADDR1;
                        end
                        `WS_ADDR1: begin
                            write_byte <= ( cmd_addr >> 24 );//truncate upper bits
                            write_state <= `WS_ADDR2;
                        end
                        `WS_ADDR2: begin
                            write_byte <= ( cmd_addr >> 16 );//truncate upper bits
                            write_state <= `WS_ADDR3;
                        end
                        `WS_ADDR3: begin
                            write_byte <= ( cmd_addr >> 8 );//truncate upper bits
                            write_state <= `WS_ADDR4;
                        end
                        `WS_ADDR4: begin
                            write_byte <= cmd_addr;//truncate upper bits
                            write_state <= `WS_CRC;
                        end
                        `WS_CRC: begin
                            write_byte <= (( {1'b0, cmd_crc} << 1 ) | 1'b1 );
                            write_state <= `WS_FF;
                        end
                        `WS_FF: begin
                            write_byte <= 8'hff;
                            write_state <= `WS_RES;
                        end
                    endcase
                end else if ( spi_en_rd & ( write_state == `WS_RES ) ) begin
                    if ( read_byte != 8'hff ) begin
                        write_state <= `WS_CMD;
                        state <= state_aft_w;
                        cmd_res <= read_byte;
                        ws_time_out <= 1'b0;
                    end else if ( ws_time_out > `WS_TIME_OUT ) begin
                        state <= `PON; //restart
                        write_state <= `WS_CMD;
                        ws_time_out <= 1'b0;
                    end else begin
                        ws_time_out <= ws_time_out + 1'b1;
                        write_state <= `WS_RES;
                    end
                end
            end
            `INIT: begin //cmd1
                cmd <= 6'd1;
                cmd_addr <= 32'b0;
                cmd_crc <= 7'h0;
                state <= `CMD_WRITE;
                state_aft_w <= `INIT_RES;
                csx <= 1'b1;
            end
            `INIT_RES: begin
                csx <= 1'b1;
                if ( cmd_res == 8'h00 )//ok
                    state <= `MULTI_READ;
                else if ( cmd_res == 8'h01 ) //in idol state
                    state <= `CMD_WRITE; //retry
                else
                    state <= `PON;//restart
            end
            `MULTI_READ: begin
                csx <= 1'b1;
                cmd <= 6'd18;
                //cmd_addr <= 32'h00000000;
                cmd_addr <= 32'h00060000;//768*512
                cmd_crc <= 7'h0;
                state <= `CMD_WRITE;
                state_aft_w <= `MULTI_READ_RES;
            end
            `MULTI_READ_RES: begin
                if ( cmd_res == 8'h00 ) begin //ok
                    state <= `READ_DATA_PACKET_HD;
                    state_aft_w <= `READ_DATA_PACKET_HD;
                end else if ( cmd_res == 8'h01 ) //in idol state
                    state <= `CMD_WRITE; //retry
                else
                    state <= `PON;//restart
            end
            `SINGLE_READ: begin
                cmd <= 6'd17;
                cmd_addr <= 32'h00000000;
                cmd_crc <= 7'h0;
                state <= `CMD_WRITE;
                state_aft_w <= `SINGLE_READ_RES;
            end
            `SINGLE_READ_RES: begin
                if ( cmd_res == 8'h00 ) begin //ok
                    state <= `READ_DATA_PACKET_HD;
                    state_aft_w <= `SD_IDOL;
                end else if ( cmd_res == 8'h01 ) //in idol state
                    state <= `CMD_WRITE; //retry
                else
                    state <= `PON;//restart
            end
            `READ_DATA_PACKET_HD: begin//read 1 block = 512 bytes
                if ( spi_en_rd ) begin
                    if ( read_byte == 8'hfe ) begin
                        ws_time_out <= 1'b0;
                        state <= `READ_DATA_PACKET_BD;
                    end else if ( ws_time_out > `WS_TIME_OUT ) begin
                        state <= `PON; //restart
                        ws_time_out <= 1'b0;
                    end else begin
                        ws_time_out <= ws_time_out + 1'b1;
                    end
                end
            end
            `READ_DATA_PACKET_BD: begin
                if ( spi_en_rd ) begin
                    out_data <= read_byte;
                    en <= 1'b1;
                    rd_cnt <= rd_cnt + 1'b1;
                    if ( rd_cnt == `BLOCK_SIZE ) begin
                        state <= `READ_DATA_PACKET_CRC;
                        rd_cnt <= 1'b0;
                    end
                end else
                    en <= 1'b0;
            end
            `READ_DATA_PACKET_CRC: begin
                en <= 1'b0;
                if ( spi_en_rd ) begin
                    crc_cnt <= crc_cnt + 1'b1;
                    if ( crc_cnt == 1'b1 )
                        state <= state_aft_w;
                end
            end
            `SD_IDOL: begin
                state_aft_w <= `PON;
                state <= `SD_WAIT;
                wait_ms <= 16'd1000;
                csx <= 1'b1;
            end
            `SD_WAIT: begin
                if ( wait_ms > 1'b0 ) begin
                    state <= `SD_WAIT;
                    if ( wait_cnt < `MS_CNT ) begin
                        wait_cnt <= wait_cnt + 1'b1;
                    end else begin
                        wait_cnt <= 1'b0;
                        wait_ms <= wait_ms - 1'b1;
                    end
                end else begin
                    state <= state_aft_w;
                    wait_cnt <= 1'b0;
                end
            end
            default: begin
                state <= `SD_IDOL;
            end
        endcase
    end
end
endmodule

module spi(
input csx, CLK, MISO,
output reg MOSI,
input [7:0] inbyte,
output reg [7:0] outbyte,
output en_wr, en_rd
);

reg [2:0] cnt;
assign en_wr = ( cnt == 3'b111 ) | csx;
assign en_rd = ( cnt == 3'b000 );
//reg [7:0] data_wr;

always @ ( posedge CLK ) begin
    //if ( CSX )
    //outbyte <= 8'hff;
    //else
    outbyte <= ( outbyte << 1 ) | MISO;
    //outbyte[7-cnt] <= MISO;
end

/*always @ ( negedge en_wr ) begin //polling inbyte
    data_wr <= inbyte;
end*/

always @ ( negedge CLK ) begin
    //{MOSI, data_wr} <= ( {1'b0, data_wr} << 1 );
    MOSI <= inbyte[7-cnt];
end

always @ ( posedge CLK ) begin
    if ( csx )
        cnt <= 3'h0;
    else
        cnt <= cnt + 1'b1;

end


endmodule

連番BMP(24 bit)を無圧縮RGB = 5-6-5 bitファイルにまとめるpythonスクリプト。


#!/usr/bin/env python

datapos = 0x36
lastnum = 3038
outfile = "./mov.bin"
fo = open(outfile, 'wb')

for i in range(lastnum):
    filename = "../bmp/katahane_movie %07d.bmp" % ( i + 1 )
    fi = open(filename, 'rb')
    fi.seek(datapos)

    for j in range(128*128):
        b = ord(fi.read(1))
        g = ord(fi.read(1))
        r = ord(fi.read(1))
        b1 = ( r & 0b11111000 ) | ( ( g & 0b11100000 ) >> 5 ) #R5 G3
        b2 = ( ( g & 0b00011100 ) << 3 ) | ( ( b & 0b11111000 ) >> 3 )  #G3 B5
        fo.write( bytearray( [b1, b2] ) )
    fi.close

fo.close