本文章介紹使用Raspberry Pi Pico PIO(Programmable IO)功能來寫作ILI3941 8-bit parallel模式的驅動程式。並且試著只改變StateMachine執行的Frequency,來比較LCD TLF ILI9341的顯示效能。
一、接腳:
- GPIO 11,10,9,8,7,6,5,4分別接DB7,DB6,DB5,DB4,DB3,DB2,DB1,DB0。並設定成StateMachine的out pins。
- GPIO 15,14,13,12分別接CS(CSX), RS(D/CX),WR(WRX),RD(RDX)。並設定成StateMachine的set pins。
二、ILI9341 Datasheet write sequence 與 PIO程式碼比對。
.program ili9341_pio_cmd
; 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
- ili9341.c
#include "stdio.h"
#include "stdlib.h"
#include "ili9341_pio.h"
#include "pico/stdlib.h"
#include "hardware/clocks.h"
#include "string.h"
#include "registers.h"
#include "ili9341.h"
PIO ili9341_pio = pio1;
uint ili9341_sm = 0;
uint out_base_pin = 4;
uint in_base_pin = 4;
uint set_base_pin = 12;
static uint8_t p_count = 0;
static uint8_t d_count = 0;
static uint8_t data_recv = 0;
static uint8_t params[8];
static uint32_t data[8];
void ili9341_cmd(uint32_t cmd, uint32_t count, uint8_t *param)
{
pio_sm_restart(ili9341_pio, ili9341_sm);
pio_sm_put_blocking(ili9341_pio, ili9341_sm, cmd);
pio_sm_put_blocking(ili9341_pio, ili9341_sm, count);
for (int i = 0; i < count; i++)
{
pio_sm_put_blocking(ili9341_pio, ili9341_sm, param[i]);
}
}
void ili9431_pio_cmd_init(PIO pio, uint sm, uint out_base, uint set_base, uint32_t freq)
{
uint offset = 0;
pio_sm_config c;
offset = pio_add_program(pio, &ili9341_pio_cmd_program);
c = ili9341_pio_cmd_program_get_default_config(offset);
for (int i = 0; i < 8; i++)
pio_gpio_init(pio, out_base + i);
for (int i = 0; i < 4; i++)
pio_gpio_init(pio, set_base + i);
pio_sm_set_consecutive_pindirs(pio, sm, out_base, 8, true);
pio_sm_set_consecutive_pindirs(pio, sm, set_base, 4, true);
sm_config_set_out_pins(&c, out_base, 8);
sm_config_set_set_pins(&c, set_base, 4);
sm_config_set_out_shift(&c, true, false, 32);
float div = clock_get_hz(clk_sys) / freq;
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
/* ili3941 draw functions*/
uint16_t ili9341_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 ili9341_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);
ili9341_cmd(ILI9341_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);
ili9341_cmd(ILI9341_PAGEADDRSET, 4, addr);
ili9341_cmd(ILI9341_MEMORYWRITE, 0, NULL);
}
void ili9341_draw_pixel(uint16_t x, uint16_t y, uint16_t color)
{
if (x < 0 || x > SCREEN_WIDTH || y < 0 || y > SCREEN_HEIGHT)
return;
ili9341_set_address_window(x, y, x, y);
ili9341_cmd(ILI9341_NOP, 2, (uint8_t[2]){(uint8_t)(color >> 8), (uint8_t)color});
}
void ili9341_invert_display(bool invert)
{
if (invert)
ili9341_cmd(ILI9341_INVERTON, 0, NULL);
else
ili9341_cmd(ILI9341_INVERTOFF, 0, NULL);
}
void ili9341_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 > SCREEN_WIDTH)
width = SCREEN_WIDTH - x;
if (y + height > SCREEN_HEIGHT)
height = SCREEN_HEIGHT - y;
ili9341_set_address_window(x, y, x + width, y + height);
for (int j = y; j < y + height; j++)
for (int i = x; i < x + width; i++)
ili9341_cmd(ILI9341_NOP, 2, (uint8_t[2]){(uint8_t)(color >> 8), (uint8_t)(color & 0x00ff)});
}
void ili9341_draw_line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color)
{
/* algorithm from https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm */
int dx = abs(x1 - x0);
int sx = x0 < x1 ? 1 : -1;
int dy = -abs(y1 - y0);
int sy = y0 < y1 ? 1 : -1;
int error = dx + dy;
int e2;
while (1)
{
// plot(x0, y0)
ili9341_draw_pixel(x0, y0, color);
if (x0 == x1 && y0 == y1)
break;
e2 = 2 * error;
if (e2 >= dy)
{
if (x0 == x1)
break;
error = error + dy;
x0 = x0 + sx;
}
if (e2 <= dx)
{
if (y0 == y1)
break;
error = error + dx;
y0 = y0 + sy;
}
}
}
void ili9341_draw_bitmap(uint16_t x, uint16_t y, const tImage *bitmap)
{
uint16_t width = 0, height = 0;
width = bitmap->width;
height = bitmap->height;
uint16_t total_pixels = width * height;
ili9341_set_address_window(x, y, x + width - 1, y + height - 1);
for (uint16_t pixels = 0; pixels < total_pixels; pixels++)
{
ili9341_cmd(ILI9341_NOP, 1, (uint8_t[1]){(uint8_t)(bitmap->data[2 * pixels])});
ili9341_cmd(ILI9341_NOP, 1, (uint8_t[1]){(uint8_t)(bitmap->data[2 * pixels + 1])});
}
}
void ili9431_init_config()
{
ili9341_cmd(ILI9341_SOFTRESET, 0, NULL);
sleep_ms(150);
ili9341_cmd(ILI9341_DISPLAYOFF, 0, NULL);
sleep_ms(150);
ili9341_cmd(ILI9341_PIXELFORMAT, 1, (uint8_t[1]){0x55});
ili9341_cmd(ILI9341_POWERCONTROL1, 1, (uint8_t[1]){0x05}); // 0x05 :3.3V
ili9341_cmd(ILI9341_POWERCONTROL2, 1, (uint8_t[1]){0x10});
ili9341_cmd(ILI9341_VCOMCONTROL1, 2, (uint8_t[2]){0x3E, 0x28});
ili9341_cmd(ILI9341_VCOMCONTROL2, 1, (uint8_t[1]){0x86});
ili9341_cmd(ILI9341_MADCTL, 1, (uint8_t[1]){0x40}); // MY,MX,MV,ML,BRG,MH,0,0
ili9341_cmd(ILI9341_FRAMECONTROL, 2, (uint8_t[2]){0x00, 0x1B}); // Default 70Hz
ili9341_cmd(ILI9341_DISPLAYFUNC, 4, (uint8_t[4]){0x0A, 0xA2, 0x27, 0x04});
ili9341_cmd(ILI9341_GAMMASET, 1, (uint8_t[1]){0x01});
ili9341_cmd(ILI9341_PGAMCOR, 15, (uint8_t[15]){0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1, 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00});
ili9341_cmd(ILI9341_NGAMCOR, 15, (uint8_t[15]){0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1, 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f});
ili9341_cmd(ILI9341_SLEEPOUT, 0, NULL);
sleep_ms(150);
ili9341_cmd(ILI9341_DISPLAYON, 0, NULL);
sleep_ms(500);
}
void ili9341_init()
{
ili9431_pio_cmd_init(ili9341_pio, ili9341_sm, out_base_pin, set_base_pin, 70 * 1000000); // 70*
ili9431_init_config();
}
- ili9341.h
#ifndef _ILI9431_H_
#define _ILI9431_H_
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320
#include "pico/stdlib.h"
#include "tft_string_lib/ili_string.h"
void ili9341_init();
void ili9431_init_config();
void ili9341_draw_pixel(uint16_t x, uint16_t y, uint16_t color);
void ili9341_set_address_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void ili9341_cmd(uint32_t cmd, uint32_t count, uint8_t *param);
uint16_t ili9341_color_565RGB(uint8_t R, uint8_t G, uint8_t B);
void ili9341_fill_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color);
void ili9341_invert_display(bool invert);
void ili9341_draw_line(uint16_t start_x, uint16_t start_y, uint16_t end_x, uint16_t end_y, uint16_t color);
void ili9341_draw_fill_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
void ili9341_draw_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
void ili9341_draw_string(uint16_t x, uint16_t y, uint8_t* str, uint16_t color, const tFont *font);
void ili9341_draw_string_withbg(uint16_t x, uint16_t y, char *str, uint16_t fore_color, uint16_t back_color, const tFont *font);
void ili9341_draw_bitmap(uint16_t x, uint16_t y, const tImage *bitmap);
void pio_sm_reinit(uint32_t freq);
#endif
- main.c
#include <stdio.h>
#include "stdlib.h"
#include "pico/stdlib.h"
#include "hardware/dma.h"
#include "hardware/pio.h"
#include "ili9341.h"
#include "pico_img.h"
#include "string.h"
void demo() {
ili9341_fill_rect(0,0, SCREEN_WIDTH, SCREEN_HEIGHT, 0x0000);
for (int j = 0; j < 320; j+=5) ili9341_draw_line(0, 0, 239, j, 0xffff);
for (int i = 0; i < 240; i+=5) ili9341_draw_line(0, 0, i, 319, 0xffff);
for (int i = 10;i < 150; i+=10) {
ili9341_fill_rect(i, i, 100, 100, ili9341_color_565RGB(0x60+i, 0x70+i*2, 0x30+i));
}
ili9341_draw_bitmap(50,0, &pico_img);
ili9341_invert_display(true);
ili9341_invert_display(false);
}
int main()
{
stdio_init_all();
ili9341_init();
ili9341_fill_rect(0,0, SCREEN_WIDTH, SCREEN_HEIGHT, 0x0000);
for (int j = 0; j < 320; j+=5) ili9341_draw_line(0, 0, 239, j, 0xffff);
sleep_ms(2000);
for (int i = 0; i < 240; i+=5) ili9341_draw_line(0, 0, i, 319, 0xffff);
sleep_ms(2000);
for (int i = 10;i < 150; i+=10) {
ili9341_fill_rect(i, i, 100, 100, ili9341_color_565RGB(0x60+i, 0x70+i*2, 0x30+i));
}
sleep_ms(2000);
ili9341_draw_bitmap(50,0, &pico_img);
sleep_ms(2000);
ili9341_invert_display(true);
sleep_ms(2000);
ili9341_invert_display(false);
sleep_ms(2000);
char buf[60];
uint32_t freqs[4] = {1000000,2500000, 50000000, 70000000};
for (int i = 0 ; i < 4; i++) {
float div =125000000/freqs[i];
//
pio_sm_set_clkdiv(pio1, 0, div);
pio_sm_clkdiv_restart(pio1, 0);
ili9341_fill_rect(0,0, SCREEN_WIDTH, SCREEN_HEIGHT, 0x0000);
absolute_time_t t1 = get_absolute_time();
demo();
absolute_time_t t2 = get_absolute_time();
printf("Freq=%d\n",freqs[i]);
printf("%d ms", absolute_time_diff_us(t1,t2)/1000);
sleep_ms(5000);
}
}
沒有留言:
張貼留言