prettyprint

2023年3月17日 星期五

[Raspberry Pi Pico (c-sdk)] Display: Ep 5 :TFT LCD 4-lines Serial(SPI) Driver -- A single Frame(128x160) takes only 11~12ms

本篇文章介紹使用RP2040 PIO(Raspberry Pi Pico開發板)功能,撰寫一個TFT LCD 4-line Serial Interface(SPI)驅動程式。有關8-bit parallel請參閱上篇文章[Raspberry Pi Pico (c-sdk)] Display: Ep 2 : PIO TFT LCD ILI9341 8-bit parallel C-code Driver

下圖示ST7735 datasheet中有關4-line interface的clock cycle。

SCL "H" and "L" pulse width MIN 為30ns。
另外跟據ILI9486 Datasheet內容為:
SCL "H" and "L" pulse width MIN 為15ns。

PIO程式碼設定約為22ns。如下圖所示:


以此設定輸出單一個128x160大小的frame 約需只要11~12ms,frame rate可達到80fps以上。

成果影片


程式碼:
pico_tft.pio
.program tft_pio_parallel
; CSX, D/CX, WRX, RDX --> gpio 15, 14, 13, 12  (set pins)
.wrap_target
start:
pull
set pins, 0b0011
mov x, osr             ;command code, if 0x0, command nop, only data
jmp !x param
set pins, 0b0001
out pins, 8      ;[1]
set pins, 0b0011 ;[1]
param:
set pins, 0b0111
pull
mov x, osr              ;how many parameters
jmp !x, start            ;no parameter return start
jmp x--, param_data         
param_data:
pull                    ; write data
set pins, 0b0101 
out pins, 8      ;[1] 
set pins, 0b0111 ;[1]
jmp x--, param_data
set pins, 0b1111
jmp start

.program tft_pio_serial
; CSX, D/CX(A0), SCL --> gpio 15, 14, 13  (side-set pins)
.side_set 3
.wrap_target
start:
pull                        side 0b100
mov x, osr                  side 0b000           ;command code, if 0x0, command nop, only data
jmp !x param                side 0b000
set y,7                     side 0b000
cmd_bit_loop:
out pins, 1                 side 0b000  [1];[2]
jmp y--, cmd_bit_loop       side 0b001  [1];[2]

param:
pull                        side 0b010
mov x, osr                  side 0b010            ;how many parameters
jmp !x, start               side 0b010           ;no parameter return start
jmp x--, param_data         side 0b010        
param_data:
pull                        side 0b010                ; write data
set y,7                     side 0b010
data_bit_loop:
out pins, 1                 side 0b010  [1];[2]     
jmp y--, data_bit_loop      side 0b011  [1];[2]
jmp x--, param_data         side 0b010
jmp start                   side 0b100
pico_tft.c
#include "stdio.h"
#include "stdlib.h"
#include "pico/stdlib.h"
#include "hardware/clocks.h"
#include "string.h"

#include "registers.h"
#include "pico_tft.pio.h"
#include "pico_tft.h"
#include "fonts/font_ubuntu_mono_24.h"
#include "hardware/dma.h"

#define MAX_BYTE_TRANS (TFT_WIDTH*TFT_HEIGHT*2)

#define PICO_TFT_SERIAL
//#define PICO_TFT_DMA

PIO tft_pio = pio1;
uint tft_sm=0;
uint in_out_base_pin=4;
uint set_base_pin=12;
uint sideset_base_pin=11;
uint s_in_out_base_pin=10;

int tft_dma_channel;

/*
\param frame_buff: frame buffer
\param src: source image
\param x: start x of source image
\param y: start y of source image
\param fx: start x of drawing in frame buffer
\param fy: start y of drawing in frame buffer
\param ow: source image width
param oh: source image height
*/
void fb_draw_image(uint8_t* frame_buffer, uint8_t *src, uint16_t x, uint16_t y, uint16_t fx, uint16_t fy, uint32_t ow, uint32_t oh, bool wrapx, bool wrapy, bool enable_transparent, uint16_t transparent_color) {
    uint16_t width = (ow > TFT_WIDTH)? TFT_WIDTH : ow;
    uint16_t height = (oh > TFT_HEIGHT) ? TFT_HEIGHT: oh;

    if (!wrapx && (fx+width > TFT_WIDTH)) width = TFT_WIDTH-fx; 
    if (!wrapy && (fy+height) > TFT_HEIGHT) height = TFT_HEIGHT-fy;
    uint32_t src_loc;
    
    for (int j=0; j < height; j++) {
        for (int i=0; i < width; i++) {
            src_loc=((x+i)%ow + ((y+j)%oh)*ow)*2;
            if (!enable_transparent || src[src_loc]!=transparent_color>>8 || src[src_loc+1] != transparent_color&0xff) { 
                frame_buffer[((i+fx)+(j+fy)*TFT_WIDTH)*2] = src[src_loc];
                frame_buffer[((i+fx)+(j+fy)*TFT_WIDTH)*2+1] = src[src_loc+1];
            }
        }
    }
}

/*
\param src: source image
\param dest: dest image buffer
\param x: source image x, coordinates
\param y: source image y coordinates
\param ow: source image width
param oh: source image height
\param width: dest image width
\param height: dest image height
*/
void tft_fill_partial_image(uint8_t *src, uint8_t *dest,uint16_t x, uint16_t y, uint32_t ow, uint32_t oh,uint16_t width, uint16_t height) {
    uint32_t src_loc;
    for (int j=0; j < height; j++) {
        for (int i=0; i < width; i++) {
            src_loc=((x+i)%ow + ((y+j)%oh)*ow)*2;
            dest[(i+j*width)*2] = src[src_loc];
            dest[(i+j*width)*2+1] = src[src_loc+1];
        }
    }
}

/*
\param src: source image
\param x: start x position
\param y: start y position
\param ow: source image width
\param oy: source image height
\param wrapx: warp x 
\param warpy: warp y
*/
void tft_draw_frame(uint8_t *src, uint16_t x, uint16_t y, uint16_t tx, uint16_t ty, uint32_t ow, uint32_t oh) {
    uint16_t width = (tx+ow > TFT_WIDTH)? TFT_WIDTH-tx : ow;
    uint16_t height = (ty+oh > TFT_HEIGHT) ? TFT_HEIGHT-ty: oh;

    uint32_t src_loc;
    uint32_t count = width*height*2;

    tft_set_address_window (tx, ty, tx+width-1, ty+height-1);
    pio_sm_restart(tft_pio, tft_sm);
    #ifdef PICO_TFT_SERIAL
    pio_sm_put_blocking(tft_pio, tft_sm, TFT_MEMORYWRITE << 24);
    #endif
    #ifdef PICO_TFT_PARALLEL
    pio_sm_put_blocking(tft_pio, tft_sm, TFT_MEMORYWRITE);
    #endif
    
    pio_sm_put_blocking(tft_pio, tft_sm, count);
    
    for (int j=0; j < height; j++) {
        for (int i=0; i < width; i++) {
            src_loc=((x+i)%ow + ((y+j)%oh)*ow)*2;
            #ifdef PICO_TFT_SERIAL
            pio_sm_put_blocking(tft_pio, tft_sm, src[src_loc]<<24);
            pio_sm_put_blocking(tft_pio, tft_sm, src[src_loc+1]<<24);
            #endif
            #ifdef PICO_TFT_PARALLEL
            pio_sm_put_blocking(tft_pio, tft_sm, src[src_loc]);
            pio_sm_put_blocking(tft_pio, tft_sm, src[src_loc+1]);
            #endif
        }
    }
}

void tft_draw_image_with_trasnparent_color(uint16_t x, uint16_t y, const tImage *bitmap, uint32_t transparent_color) {
    uint16_t width, height;
    if (x+bitmap->width > TFT_WIDTH) width = TFT_WIDTH-x; else width = bitmap->width;
    if (y+bitmap->height > TFT_HEIGHT) height = TFT_HEIGHT-y; else height = bitmap->height;

    uint16_t *color=(uint16_t*)bitmap->data;
    for (int j=0; j < height;j++) {
        for (int i=0; i < width;i++) {
            if (color[i+j*bitmap->width] != transparent_color) {
                
                tft_draw_pixel(x+i,y+j,color[i+j*(bitmap->width)]);
            }
        }
    }
    
}

void tft_cmd(uint32_t cmd, uint32_t count, uint8_t *param)
{
    pio_sm_restart(tft_pio, tft_sm);
    #ifdef PICO_TFT_SERIAL
    pio_sm_put_blocking(tft_pio, tft_sm, cmd << 24);
    #endif
    #ifdef PICO_TFT_PARALLEL
    pio_sm_put_blocking(tft_pio, tft_sm, cmd);
    #endif
    
    pio_sm_put_blocking(tft_pio, tft_sm, count);
    for (int i = 0; i < count; i++)
    {
        #ifdef PICO_TFT_SERIAL
        pio_sm_put_blocking(tft_pio, tft_sm, param[i]<<24);
        #endif
        #ifdef PICO_TFT_PARALLEL
        pio_sm_put_blocking(tft_pio, tft_sm, param[i]);
        #endif
    }
}
#ifdef PICO_TFT_DMA
void tft_cmd_dma(uint32_t cmd, uint32_t count, uint8_t *param)
{
    #ifdef PICO_TFT_SERIAL
    tft_cmd(cmd, count, param);
    return;
    #endif 
    pio_sm_restart(tft_pio, tft_sm);
    pio_sm_put_blocking(tft_pio, tft_sm, cmd);
    pio_sm_put_blocking(tft_pio, tft_sm, count);
    dma_channel_set_trans_count(tft_dma_channel, count >> DMA_SIZE_8, false);
    dma_channel_set_read_addr(tft_dma_channel, param, false);
    dma_channel_start(tft_dma_channel);
    dma_channel_wait_for_finish_blocking(tft_dma_channel);
    
}
#endif
void tft_pio_cmd_init(PIO pio, uint sm, uint in_out_base,  uint set_sideset, uint32_t freq) {
    uint offset=0;
    pio_sm_config c;
    #ifdef PICO_TFT_PARALLEL
    offset = pio_add_program(pio, &tft_pio_parallel_program);
    c = tft_pio_parallel_program_get_default_config(offset);
    for (int i=0; i < 8; i++) pio_gpio_init(pio, in_out_base+i);
    for (int i=0; i < 4; i++) pio_gpio_init(pio, set_sideset+i);
    pio_sm_set_consecutive_pindirs(pio, sm, in_out_base, 8, true);
    pio_sm_set_consecutive_pindirs(pio, sm, set_base, 4, true);
    sm_config_set_in_pins(&c, in_out_base);
    sm_config_set_out_pins(&c, in_out_base, 8);
    sm_config_set_set_pins(&c, set_sideset, 4);
    sm_config_set_out_shift(&c, true, false, 8);
    sm_config_set_in_shift(&c, false, false, 8);
    #endif
    #ifdef PICO_TFT_SERIAL
    offset = pio_add_program(pio, &tft_pio_serial_program);
    c = tft_pio_serial_program_get_default_config(offset);
    pio_gpio_init(pio, in_out_base);
    for (int i=0; i < 3; i++) pio_gpio_init(pio, set_sideset+i);
    pio_sm_set_consecutive_pindirs(pio, sm, in_out_base, 1, true);
    pio_sm_set_consecutive_pindirs(pio, sm, set_sideset, 3, true);
    sm_config_set_in_pins(&c, in_out_base);
    sm_config_set_out_pins(&c, in_out_base, 1);
    sm_config_set_sideset_pins(&c, set_sideset);
    sm_config_set_out_shift(&c, false, false, 8);
    sm_config_set_in_shift(&c, true, false, 8);
    #endif
       
    //sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
    
    float div = clock_get_hz(clk_sys)/freq;
    sm_config_set_clkdiv(&c, div);
    
    #ifdef PICO_TFT_DMA
    /*   DMA  */
    tft_dma_channel = dma_claim_unused_channel(true);
    dma_channel_config dc = dma_channel_get_default_config(tft_dma_channel);
    channel_config_set_write_increment(&dc, false);
    channel_config_set_read_increment(&dc, true);
    channel_config_set_dreq(&dc, pio_get_dreq(pio, sm, true));
    channel_config_set_transfer_data_size(&dc, DMA_SIZE_8); //DMA_SIZE_8,16,32
    
    dma_channel_configure(tft_dma_channel, &dc, (void*) (PIO1_BASE+PIO_TXF0_OFFSET), 
             NULL, MAX_BYTE_TRANS>> DMA_SIZE_8, false); //DMA_SIZE_8 or 16 or 32
    /*  DMA */
    #endif 
    pio_sm_init(pio, sm, offset, &c);
    pio_sm_set_enabled(pio, sm, true);
}

/* ili3941 draw functions*/
uint16_t tft_color_565RGB(uint8_t R, uint8_t G, uint8_t B) {
    uint16_t c;
    c = (((uint16_t)R)>>3)<<11 | (((uint16_t)G)>>2) << 5 | ((uint16_t)B)>>3;
    return c;
}
void tft_memory_write_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
	uint8_t addr[4];
    addr[0]=(uint8_t)(x1 >> 8);
    addr[1]= (uint8_t)(x1 & 0xff);
    addr[2]= (uint8_t)(x2 >> 8);
    addr[3]= (uint8_t)(x2 & 0xff);
    tft_cmd(TFT_COLADDRSET, 4,   addr);

    addr[0]=(uint8_t)(y1 >> 8);
    addr[1]= (uint8_t)(y1 & 0xff);
    addr[2]= (uint8_t)(y2 >> 8);
    addr[3]= (uint8_t)(y2 & 0xff);
	tft_cmd(TFT_PAGEADDRSET, 4,   addr );

    tft_cmd(TFT_MEMORYWRITE, 0, NULL);
}

void tft_set_address_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
	uint8_t addr[4];
    addr[0]=(uint8_t)(x1 >> 8);
    addr[1]= (uint8_t)(x1 & 0xff);
    addr[2]= (uint8_t)(x2 >> 8);
    addr[3]= (uint8_t)(x2 & 0xff);
    tft_cmd(TFT_COLADDRSET, 4,  addr);

    addr[0]=(uint8_t)(y1 >> 8);
    addr[1]= (uint8_t)(y1 & 0xff);
    addr[2]= (uint8_t)(y2 >> 8);
    addr[3]= (uint8_t)(y2 & 0xff);
	tft_cmd(TFT_PAGEADDRSET, 4,  addr );
}

/* put color at point*/
void tft_draw_pixel(uint16_t x, uint16_t y, uint16_t color)
{
  if ( x < 0 || x > TFT_WIDTH-1 || y < 0 || y > TFT_HEIGHT-1) return;
	tft_set_address_window(x,y,x,y);
    tft_cmd(TFT_MEMORYWRITE, 2,  (uint8_t[2]){(uint8_t)(color >> 8), (uint8_t)color});
}

void tft_fill_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) {
  if (x < 0) x=0;
  if (y < 0) y=0;
  if (x+width > TFT_WIDTH) width = TFT_WIDTH-x;
  if (y+height > TFT_HEIGHT) height = TFT_HEIGHT-y;
  tft_memory_write_window(x,y, x+width-1, y+height-1);
  for (int j = y; j < y+height; j++) 
    for (int i = x; i< x+width;i++)
      tft_cmd(TFT_NOP, 2,  (uint8_t[2]){(uint8_t)(color >> 8), (uint8_t)(color&0xff)});
}


void tft_draw_bitmap(uint16_t x, uint16_t y, const tImage *bitmap)
{
 
	uint32_t width = 0, height = 0;
	width = bitmap->width;
	height = bitmap->height;

	uint32_t total_pixels = width * height*2;

	tft_set_address_window (x, y, x + width-1, y + height-1);
    tft_cmd_dma(TFT_MEMORYWRITE, total_pixels,  (uint8_t*)(bitmap->data));
   
}
void tft_init_config() {
	tft_cmd(TFT_SOFTRESET, 0,  NULL);
    sleep_ms(150);
    tft_cmd(TFT_DISPLAYOFF, 0,  NULL);
    sleep_ms(150);
    tft_cmd(TFT_PIXELFORMAT, 1,  (uint8_t[1]){0x55}); //0x55
    tft_cmd(TFT_POWERCONTROL1, 1,  (uint8_t[1]){0x05}); // 0x05 :3.3V
    tft_cmd(TFT_POWERCONTROL2, 1,  (uint8_t[1]){0x10});
    tft_cmd(TFT_VCOMCONTROL1, 2,  (uint8_t[2]){0x3E, 0x28});
    tft_cmd(TFT_VCOMCONTROL2, 1,  (uint8_t[1]){0x86});
    tft_cmd(TFT_MADCTL, 1,  (uint8_t[1]){0x08}); //MY,MX,MV,ML,BRG,MH,0,0(40)
    tft_cmd(TFT_FRAMECONTROL, 2,  (uint8_t[2]){0b00, 0x1B}); // Default 70Hz:0x1B
    tft_cmd(TFT_DISPLAYFUNC, 4,  (uint8_t[4]){0x0A, 0x82, 0x27, 0x04}); //0a,a2,27,04
    tft_cmd(TFT_GAMMASET, 1,  (uint8_t[1]){0x01});
  
  	//tft_cmd(tft_PGAMCOR, 15, 0xFF, (uint8_t[15]){ 0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1, 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00 });
    //tft_cmd(tft_NGAMCOR,  15,0xFF, (uint8_t[15]){ 0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1, 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f }); 
    
    tft_cmd(TFT_SLEEPOUT, 0,  NULL);
    sleep_ms(150);
    tft_cmd(TFT_DISPLAYON, 0,  NULL);
    sleep_ms(500);
    
}
void tft_init() {
    #ifdef PICO_TFT_PARALLEL
        tft_pio_cmd_init(tft_pio, tft_sm, in_out_base_pin, set_base_pin, 70000000);  //pio freq
    
    #endif
    #ifdef PICO_TFT_SERIAL
        tft_pio_cmd_init(tft_pio, tft_sm, s_in_out_base_pin, sideset_base_pin, 90000000);  //pio freq
	#endif 
    tft_init_config();
    
}

void tft_rotate_image(const uint16_t *src, uint16_t *dest, uint16_t width, uint16_t height, uint16_t deg) {
    
    double sinx = sin((deg)/180.0 * M_PI);  
    double cosx = cos((deg)/180.0 * M_PI);

    int xCenter = height/2;        // Rotate image by its center.
    int yCenter = width/2;
    int xt,yt,xRotate,yRotate;

    for(int x=0; x<height; x++) {
        xt = x - xCenter;
        double xt_cosx = xt*cosx;
        double xt_sinx = xt*sinx;
        for(int y=0; y<width; y++) {
            yt = y - yCenter;
            xRotate = (int)(lround(xt_cosx - (yt*sinx)) + xCenter);
            yRotate = lround((yt*cosx) + xt_sinx) + yCenter;  
            if( (xRotate >= 0) && (xRotate < height) && (yRotate >= 0) && (yRotate < width) ) {
                dest[x*width+y] = src[xRotate*width+yRotate];
            } else {
                dest[x*width+y]=0xffff;
            }
        }
    }

}
pico_tft.h
#ifndef  _TFT_H_
#define _TFT_H_

#define TFT_WIDTH   128
#define TFT_HEIGHT   160

#include "pico/stdlib.h"

#include "fonts/bitmap_typedefs.h"
#include "hardware/pio.h"
#include "math.h"


void tft_init();
void tft_init_config();
void tft_draw_pixel(uint16_t x, uint16_t y, uint16_t color);
void tft_set_address_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void tft_cmd(uint32_t cmd, uint32_t count,  uint8_t *param);
void tft_cmd_dma(uint32_t cmd, uint32_t count,  uint8_t *param);
uint16_t tft_color_565RGB(uint8_t R, uint8_t G, uint8_t B);
void tft_fill_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color);
void tft_draw_bitmap(uint16_t x, uint16_t y, const tImage *bitmap);
void tft_pio_cmd_init(PIO pio, uint sm, uint out_base,  uint set_base, uint32_t freq);
void tft_rotate_image(const uint16_t *src, uint16_t *dest, uint16_t width, uint16_t height, uint16_t deg);
void tft_fill_partial_image(uint8_t *src, uint8_t *dest,uint16_t x, uint16_t y, uint32_t ow, uint32_t oh,uint16_t width, uint16_t height);
void tft_draw_frame(uint8_t *src, uint16_t x, uint16_t y, uint16_t tx, uint16_t ty, uint32_t ow, uint32_t oh);
void tft_draw_image_with_trasnparent_color(uint16_t x, uint16_t y, const tImage *bitmap, uint32_t transparent_color);
void fb_draw_image(uint8_t* frame_buffer, uint8_t *src, uint16_t x, uint16_t y, uint16_t fx, uint16_t fy, uint32_t ow, uint32_t oh, bool wrapx, bool wrapy, bool enable_transparent, uint16_t transparent_color);
#endif
測試主程式
 #include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/dma.h"
#include "hardware/pio.h"

#include "pico_tft.h"
#include "tft_string.h"
#include "fonts/font_ubuntu_mono_24.h"
#include "registers.h"
#include "time.h"
#include "stdlib.h"
#include "string.h"
#include "fonts/img1.h"
#include "fonts/img2.h"
#include "fonts/gear.h"
#include "pico/multicore.h"
#include "fonts/bg.h"
#include "fonts/w1.h"
#include "fonts/w2.h"
#include "fonts/w3.h"

typedef struct _rotate_obj_t {
    uint8_t *srcimg;
    uint8_t *destimg;
    uint16_t width;
    uint16_t height;
    uint16_t angle;
} rotate_obj_t;

void core1_rotate() {
    while(1) { 
        rotate_obj_t *rimg = (rotate_obj_t*)multicore_fifo_pop_blocking();
        tft_rotate_image((uint16_t*)rimg->srcimg,(uint16_t*)rimg->destimg, rimg->width, rimg->height, rimg->angle);
        multicore_fifo_push_blocking(1);
    }
    
}

int main()
{

    stdio_init_all();
    tft_init();
    
    multicore_launch_core1(core1_rotate);

    rotate_obj_t *rotate_img = (rotate_obj_t*) calloc(1, sizeof(rotate_obj_t));
    uint8_t *read_buff = (uint8_t*) calloc(TFT_WIDTH*TFT_HEIGHT*2, sizeof(uint8_t));  //frame buffer
    if (!read_buff) {
        printf("alloc memory error\n");
        return 0;
    }
     uint8_t *write_buff = (uint8_t*) calloc(TFT_WIDTH*TFT_HEIGHT*2, sizeof(uint8_t));  //frame buffer
    if (!write_buff) {
        printf("alloc memory error\n");
        return 0;
    }

    uint8_t *tmp_buff;
    absolute_time_t t1, t2;

/* start testing */
// single frame =============================
    tft_fill_rect(0,0, TFT_WIDTH, TFT_HEIGHT, 0xffff);
    tft_draw_string(20,20,"Starting", 0x001f, &font_ubuntu_mono_24);
    printf("\n=== Start testing ===\n");
    sleep_ms(1000);
    printf("   single frame...\n");
    t1 = get_absolute_time();
    tft_set_address_window (0, 0, TFT_WIDTH-1, TFT_HEIGHT-1);
    tft_cmd(TFT_MEMORYWRITE, TFT_WIDTH*TFT_HEIGHT*2,  (uint8_t*)img1.data);
    t2=get_absolute_time();
    printf("single frame: image1 store in XIP flash (%f fps)        --time:%"PRIu64"us\n",(1000000.0)/absolute_time_diff_us(t1, t2),absolute_time_diff_us(t1, t2));
    sleep_ms(1000);
    t1 = get_absolute_time();
    tft_set_address_window (0, 0, TFT_WIDTH-1, TFT_HEIGHT-1);
    tft_cmd(TFT_MEMORYWRITE, TFT_WIDTH*TFT_HEIGHT*2,  (uint8_t*)img2.data);
    t2=get_absolute_time();
    printf("single frame: image2 store in XIP flash (%f fps)        --time:%"PRIu64"us\n",(1000000.0)/absolute_time_diff_us(t1, t2),absolute_time_diff_us(t1, t2));
    sleep_ms(1000);

    //   Animation shift background ========
    printf("\n   Animation shift background...\n");
    t1 = get_absolute_time();
    for (int i =0; i < bg.width; i+=2) {
        fb_draw_image(read_buff, (uint8_t*)bg.data, i,60, 0,0,bg.width, bg.height, false, false, false, 0x0000);
        tft_set_address_window (0, 0, TFT_WIDTH-1, TFT_HEIGHT-1);
        tft_cmd(TFT_MEMORYWRITE, TFT_WIDTH*TFT_HEIGHT*2,  read_buff);
    }
    t2=get_absolute_time();
    printf("shift %u frames (%f fps)                                --time:%"PRIu64"us\n", bg.width/2, (float)bg.width/2*1000000/absolute_time_diff_us(t1, t2),absolute_time_diff_us(t1, t2));

    //   animation shift background and man walk ========
    printf("\n   Animation shift background and man walk...\n");
    //for (int j=0; j < bg.height-TFT_HEIGHT; j+=60){ 
        t1= get_absolute_time();
        for (int i =0; i < bg.width; i++) {
            fb_draw_image(read_buff, (uint8_t*)bg.data, i,0, 0,0,bg.width, bg.height, false, false, false, 0x0000);
            if (i%18< 6) fb_draw_image(read_buff, (uint8_t*)w1.data, 0,0,30,30, w1.width, w1.height, false, false, true, 0x0000);
            if (i%18>=6  && i%18 <12) fb_draw_image(read_buff, (uint8_t*)w2.data, 0,0,30,30, w2.width, w2.height, false, false, true, 0x0000);
            if (i%18>=12) fb_draw_image(read_buff, (uint8_t*)w3.data, 0,0,30,30, w3.width, w3.height, false, false, true, 0x0000);
            tft_set_address_window (0, 0, TFT_WIDTH-1, TFT_HEIGHT-1);
            tft_cmd(TFT_MEMORYWRITE, TFT_WIDTH*TFT_HEIGHT*2,  read_buff);
        }
        t2=get_absolute_time();
        printf("shift %u frames (%f fps)                         --time:%"PRIu64"us\n", bg.width, (float)bg.width*1000000/absolute_time_diff_us(t1, t2),absolute_time_diff_us(t1, t2));

        t1= get_absolute_time();
        for (int i =0; i < bg.width; i++) {
            fb_draw_image(read_buff, (uint8_t*)bg.data, i,i, 0,0,bg.width, bg.height, true, true, false, 0x0000);
            if (i%18< 6) fb_draw_image(read_buff, (uint8_t*)w1.data, 0,0,30,30, w1.width, w1.height, false, false, true, 0x0000);
            if (i%18>=6  && i%18 <12) fb_draw_image(read_buff, (uint8_t*)w2.data, 0,0,30,30, w2.width, w2.height, false, false, true, 0x0000);
            if (i%18>=12) fb_draw_image(read_buff, (uint8_t*)w3.data, 0,0,30,30, w3.width, w3.height, false, false, true, 0x0000);
            tft_set_address_window (0, 0, TFT_WIDTH-1, TFT_HEIGHT-1);
            tft_cmd(TFT_MEMORYWRITE, TFT_WIDTH*TFT_HEIGHT*2,  read_buff);
        }
        t2=get_absolute_time();
        printf("shift %u frames (%f fps)                         --time:%"PRIu64"us\n", bg.width, (float)bg.width*1000000/absolute_time_diff_us(t1, t2),absolute_time_diff_us(t1, t2));
    
    //}
    //  random 50 rectangles in a frame================ 
    printf("\n   Random 50 rectangles in a frame\n");
    time_t t;
    srand((unsigned) time(&t));
    char src_buf[100*100*2];
    uint8_t *spt;
    int x,y,width,color;
    int boxs[100][4]; //(x,y,width, color-h, cololr-l)
    //==== 100 random rectangles
    for (int i=0; i < 100; i++) {
        y=rand()%TFT_HEIGHT;
        x=rand()%TFT_WIDTH;
        width=rand()%40;
        if (y+width >=TFT_HEIGHT) y=TFT_HEIGHT-y;
        if (x+width >=TFT_WIDTH) x=TFT_WIDTH-x;
        boxs[i][0]=x;
        boxs[i][1]=y;
        boxs[i][2]=width;
        boxs[i][3]=rand()%0xff;
    } 
    int p;
    
    int i, j, b; // repeat test times

    for (int rep=0; rep < 2; rep++) { 
    t1= get_absolute_time();
    for (i=0; i < 100; i++) {  
        memset(write_buff, 0, TFT_WIDTH*TFT_HEIGHT*2);
        for (j=0; j < 50; j++) { 
            p = rand()%100;
            spt= (write_buff+(boxs[p][0]+boxs[p][1]*TFT_WIDTH)*2);
            for (int k =0; k < boxs[p][2]; k++){
                memset((spt+k*TFT_WIDTH*2), boxs[p][3], boxs[p][2]*2); 
            }
        }
        b=j;
        tft_set_address_window (0, 0, TFT_WIDTH-1, TFT_HEIGHT-1);
        tft_cmd(TFT_MEMORYWRITE, TFT_WIDTH*TFT_HEIGHT*2,  write_buff);
    }
    t2=get_absolute_time();
    printf("%d frames(%d Boxs) in RAM)                              --time:%"PRIu64"us\n",i, j, absolute_time_diff_us(t1, t2));
    printf("Frame Rate: %ffps, pause 1 second to start next test\n\n", (float)i/(absolute_time_diff_us(t1, t2))*1000000);
    sleep_ms(1000);
    }
    //   coror frame test
    printf("\n   Color frame test...\n");
    t1 = get_absolute_time();
    tft_fill_rect(0,0, TFT_WIDTH, TFT_HEIGHT, 0xf800);
    tft_draw_string(20,20,"Red", 0xffff,&font_ubuntu_mono_24);
    t2=get_absolute_time();
    printf("1 color frame(with text)                                  --time:%"PRIu64"us\n",absolute_time_diff_us(t1, t2));
    printf("Frame Rate: %ffps\n\n", 1000000.0/(absolute_time_diff_us(t1, t2)));
    sleep_ms(1000);

    t1 = get_absolute_time();
    tft_set_address_window (0, 0, TFT_WIDTH-1, TFT_HEIGHT-1);
    tft_cmd(TFT_MEMORYWRITE, TFT_WIDTH*TFT_HEIGHT*2,  (uint8_t*)image_data_img1);
    t2=get_absolute_time();
    printf("1 image frame                                           --time:%"PRIu64"us\n",absolute_time_diff_us(t1, t2));
    printf("Frame Rate: %ffps\n\n", 1000000.0/(absolute_time_diff_us(t1, t2)));
    sleep_ms(1000);

    t1 = get_absolute_time();
    tft_fill_rect(0,0, TFT_WIDTH, TFT_HEIGHT, 0x7E0);
    tft_draw_string(20,20,"Green", 0xf800, &font_ubuntu_mono_24);
    t2=get_absolute_time();
    printf("1 color frame(with text)                                  --time:%"PRIu64"us\n",absolute_time_diff_us(t1, t2));
    
    printf("Frame Rate: %ffps\n\n", 1000000.0/(absolute_time_diff_us(t1, t2)));sleep_ms(1000);

    t1 = get_absolute_time();
    tft_set_address_window (0, 0, TFT_WIDTH-1, TFT_HEIGHT-1);
    tft_cmd(TFT_MEMORYWRITE, TFT_WIDTH*TFT_HEIGHT*2,  (uint8_t*)image_data_img2);
    t2=get_absolute_time();
    printf("1 image frame                                           --time:%"PRIu64"us\n",absolute_time_diff_us(t1, t2));
    printf("Frame Rate: %ffps\n\n", 1000000.0/(absolute_time_diff_us(t1, t2)));
    sleep_ms(1000);

    t1 = get_absolute_time();
    tft_fill_rect(0,0, TFT_WIDTH, TFT_HEIGHT, 0x001f);
    tft_draw_string(20,20,"Blue", 0xffff, &font_ubuntu_mono_24);
    t2=get_absolute_time();
    printf("1 color frame(with text)                                  --time:%"PRIu64"us\n",absolute_time_diff_us(t1, t2));
    printf("Frame Rate: %ffps\n\n", 1000000.0/(absolute_time_diff_us(t1, t2)));
    sleep_ms(1000);

    tft_fill_rect(0,0, TFT_WIDTH, TFT_HEIGHT, 0xffff);

   // image rotation test
   printf("\n   Image rotation test...\n");
    t1 = get_absolute_time();
    for (int i =0; i < 360; i+=2) {
        tft_rotate_image((uint16_t*)image_data_gear, (uint16_t*)write_buff, 100, 100, i);
        tft_set_address_window (13, 29, 112, 128);
        tft_cmd(TFT_MEMORYWRITE, 100*100*2,  (uint8_t*)write_buff);
    }
    t2=get_absolute_time();
    printf("rotation 360 degrees step 2 degree(100*100 image in flash)    --time:%"PRIu64"us\n",absolute_time_diff_us(t1, t2));
    printf("Frame Rate: %ffps\n\n", 180.0/(absolute_time_diff_us(t1, t2))*1000000);

    memcpy(src_buf, image_data_gear, 100*100*2);
    t1 = get_absolute_time();
    for (int i =360; i>0; i-=2) {
        tft_rotate_image((uint16_t*)src_buf, (uint16_t*)write_buff, 100, 100, i);
        tft_set_address_window (13, 29, 112, 128);
        tft_cmd(TFT_MEMORYWRITE, 100*100*2,  (uint8_t*)write_buff);
    }
    t2=get_absolute_time();
    printf("rotation 360 degree step 2 degree(100*100 source image in RAM)--time:%"PRIu64"us\n",absolute_time_diff_us(t1, t2));
    printf("Frame Rate: %ffps\n\n", 180.0/(absolute_time_diff_us(t1, t2))*1000000);

     /* core1 rotate*/
     rotate_img->srcimg = (uint8_t*)image_data_gear;
    rotate_img->width=100;
    rotate_img->height=100;
    memcpy(write_buff, image_data_gear, 100*100*2);
    
    t1 = get_absolute_time();
    for (int i =0; i < 360; i+=2) {
        rotate_img->angle=i;
        rotate_img->destimg = read_buff;
        multicore_fifo_push_blocking((uint32_t)rotate_img);

        tft_set_address_window (13, 29, 112, 128);
        tft_cmd(TFT_MEMORYWRITE, 100*100*2,  (uint8_t*)write_buff);

        uint32_t r = multicore_fifo_pop_blocking();


        tmp_buff = read_buff;
        read_buff= write_buff;
        write_buff=tmp_buff;
    }
    t2=get_absolute_time();
    printf("rotation 360 degree step 2 degree(100*100) multicore          --time:%"PRIu64"us\n",absolute_time_diff_us(t1, t2));
    printf("Frame Rate: %ffps\n\n", 180.0/(absolute_time_diff_us(t1, t2))*1000000);

    memcpy(src_buf, image_data_gear, 100*100*2);
    tft_rotate_image((uint16_t*)src_buf, (uint16_t*)write_buff, 100, 100, 10);
    t1 = get_absolute_time();
    for (int i =0; i < 360; i++) {
        tft_set_address_window (13, 29, 112, 128);
        tft_cmd(TFT_MEMORYWRITE, 100*100*2,  (uint8_t*)write_buff);
        //tft_set_address_window (13, 29, 112, 128);
        tft_cmd(TFT_MEMORYWRITE, 100*100*2,  (uint8_t*)src_buf);
    }
    t2=get_absolute_time();
    float factor = (100.0*100.0)/(128*160);
    printf("rotation forward and backward 10 degree(double buffers in RAM)--time:%"PRIu64"us\n",absolute_time_diff_us(t1, t2));
    printf("Frame Rate: %ffps\n\n", 360.0*2*factor/(absolute_time_diff_us(t1, t2))*1000000);
   
    printf("The End\n");
    tft_fill_rect(0,0, TFT_WIDTH, TFT_HEIGHT, 0xffff);
    tft_draw_string(20,20,"The End", 0x001f, &font_ubuntu_mono_24);
    

    while(1) {
        tight_loop_contents();
    }
    puts("Hello, world!");

    return 0;
}

沒有留言:

張貼留言