本篇文章介紹使用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內容為:
PIO程式碼設定約為22ns。如下圖所示:
.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;
}
沒有留言:
張貼留言