本节主要介绍LCD触摸屏控制芯片TSC2046驱动的移植,同时展示一个简单的应用示例。
TSC2046为SPI接口触摸屏控制芯片,因此本质上讲,它是个SPI设备驱动。eCos中,编写SPI设备驱动是非常方便的,一般情况下只需要按照datasheet实现其SPI读写时序即可。
eCos源码中没有现成的触摸屏芯片驱动,但令人高兴的是,在一个开源的eCos工程中,有现成的TSC2046驱动,我们可以把它移植过来。
拷贝目录和修改文件
这个开源工程详见eCos论坛中的精华帖子:[开源工程] 在MINI STM32开发板上运行eCos系统
把这个开源工程源码目录:“devs/touch/”下的cortexm和spi拷贝到我们工程的对应目录中。如下图所示。
如果你介意,再把其中的一些文件名、CDL文件中的板名称、包名称、选项名称等等改为你想要的名称。但一个别忘记的是,记得修改触摸屏支持的LCD尺寸值。
配置
修改好后,在你的target中添加相应包:
配置SPI
注意:别忘记了添加FILE IO包。
修改驱动
TSC2046的驱动分为平台部分和芯片驱动部分。具体的架构,应该比较容易看得懂。这里讲个TSC2046驱动的修改。
虽然是同样型号的芯片,但不知道为什么,拿过来直接使用却不行,虽然点击触摸屏,应用程序中读取到的x,y值有反应,但却有问题。后面仔细调试了下,发觉SPI读取上有点出入,然后x,y值的计算也有点差异。
下面是调整后的代码(read_ts()函数):
static short
read_ts(int axis)
{
// short res;
cyg_spi_device *spi_device = (cyg_spi_device *) ts_dev.priv;
// const cyg_uint8 tx_buf[1] = { axis | TSC_START | TSC_MODE_12_BIT | TSC_PD0 | TSC_DFR};
// cyg_uint8 rx_buf[2];
// Implement the read operation as a multistage SPI transaction.
cyg_spi_transaction_begin(spi_device);
/*
cyg_spi_transaction_transfer(spi_device, true,
1, tx_buf, NULL, false);
cyg_spi_transaction_transfer(spi_device, true, 2, NULL,
rx_buf, false);
*/
cyg_uint8 tx[8] = {0};
cyg_uint8 rx[8] = {0};
tx[0] = (axis | TSC_START | TSC_MODE_12_BIT | TSC_PD0 | TSC_DFR);
cyg_spi_transaction_transfer(spi_device, true, 4, tx, rx, false);
cyg_spi_transaction_end(spi_device);
// res = ( rx_buf[0] << 4 ) + (( rx_buf[1] & 0xF0 ) >> 4);
cyg_uint16 r = 0;
r = rx[1];
r <<= 8;
r += rx[2];
r >>= 3;/* 注意这里的处理 */
/*
diag_printf("--- %d, %03d, %03d, %d : %d, %d, %d, %d --- r = %d ---\n",
rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7], r);
*/
return (short)r;
// return res;
}
调整的地方:
- 原来,x,y值计算采用spi的读取值0和1,但通过打印读取到的SPI值发现,在我的板子上,x,y值计算应采用1和2的值;
- 本来,TSC2046是12bit采用,计算的时候原应右移4big,但在安富莱的触摸屏例子程序上发现右移的是3bit,所以计算x,y值有点差异;
上面都是在我的板子实际调试过的。
应用示例
这个应用示例是结合前面2节介绍的LCD应用示例的。
#define STRING1(_a_) # _a_
#define STRING(_a_) STRING1(_a_)
// The colours used by this test code. Default to the standard palette
// but if running on a true colour display then adjust.
static cyg_ucount32 colours[16] = {
CYG_FB_DEFAULT_PALETTE_BLACK,
CYG_FB_DEFAULT_PALETTE_BLUE,
CYG_FB_DEFAULT_PALETTE_GREEN,
CYG_FB_DEFAULT_PALETTE_CYAN,
CYG_FB_DEFAULT_PALETTE_RED,
CYG_FB_DEFAULT_PALETTE_MAGENTA,
CYG_FB_DEFAULT_PALETTE_BROWN,
CYG_FB_DEFAULT_PALETTE_LIGHTGREY,
CYG_FB_DEFAULT_PALETTE_DARKGREY,
CYG_FB_DEFAULT_PALETTE_LIGHTBLUE,
CYG_FB_DEFAULT_PALETTE_LIGHTGREEN,
CYG_FB_DEFAULT_PALETTE_LIGHTCYAN,
CYG_FB_DEFAULT_PALETTE_LIGHTRED,
CYG_FB_DEFAULT_PALETTE_LIGHTMAGENTA,
CYG_FB_DEFAULT_PALETTE_YELLOW,
CYG_FB_DEFAULT_PALETTE_WHITE
};
#define BLACK colours[0x00]
#define BLUE colours[0x01]
#define GREEN colours[0x02]
#define CYAN colours[0x03]
#define RED colours[0x04]
#define MAGENTA colours[0x05]
#define BROWN colours[0x06]
#define LIGHTGREY colours[0x07]
#define DARKGREY colours[0x08]
#define LIGHTBLUE colours[0x09]
#define LIGHTGREEN colours[0x0A]
#define LIGHTCYAN colours[0x0B]
#define LIGHTRED colours[0x0C]
#define LIGHTMAGENTA colours[0x0D]
#define YELLOW colours[0x0E]
#define WHITE colours[0x0F]
#define FRAMEBUF fb0
#define DEPTH CYG_FB_DEPTH(FRAMEBUF)
#define WIDTH CYG_FB_WIDTH(FRAMEBUF)
#define HEIGHT CYG_FB_HEIGHT(FRAMEBUF)
#define GRID_X_SIZE 400
#define GRID_Y_SIZE 240
#define GRID_ABSOLUTE_X_POS 1
#define GRID_ABSOLUTE_Y_POS 19
#define GRID_STEP 25
#define MAX_X (GRID_X_SIZE + GRID_ABSOLUTE_X_POS)
#define MAX_Y (GRID_Y_SIZE + GRID_ABSOLUTE_Y_POS)
static void
reset_colours_to_true(void)
{
#if (CYG_FB_FLAGS0_TRUE_COLOUR & CYG_FB_FLAGS0(FRAMEBUF))
int i;
for (i = 0; i < 16; i++) {
colours[i] = CYG_FB_MAKE_COLOUR(FRAMEBUF,
cyg_fb_palette_vga[i + i + i], cyg_fb_palette_vga[i + i + i + 1],cyg_fb_palette_vga[i + i + i + 2]);
// diag_printf("colours[%02d] = 0x%06X\n", i, colours[i]);
}
#endif
}
#include <unistd.h>
#include <fcntl.h>
static int touch_screen_read(short *px, short *py, int *pb, int pd_fd)
{
/* read a data point */
short data[4];
int bytes_read;
bytes_read = read(pd_fd, data, sizeof(data));
if (bytes_read != sizeof(data)) {
return 0;
}
*px = data[1];
*py = data[2];
*pb = (data[0] ? 0x01 : 0);
if(! *pb ) {
return 3; /* only have button data */
} else {
return 2; /* have full set of data */
}
return 0;
}
static void touch_screen_thread(cyg_addrword_t data)
{
int pd_fd;
short px = 0, py = 0;
int pb;
int ipx = 0, ipy = 0;
int cnt = 0;
pd_fd = open("/dev/ts", O_RDONLY | O_NONBLOCK);
if (pd_fd < 0) {
return;
}
while (1) {
// Read all and average
while (touch_screen_read(&px, &py, &pb, pd_fd)) {
cnt++;
ipx += px;
ipy += py;
}
if (cnt) {
px = ipx / cnt;
py = ipy / cnt;
// Draw square from the pencil position
if (pd_fd) {
CYG_FB_FILL_BLOCK(FRAMEBUF, px, py, 4, 4, RED);
diag_printf("=== Pen is down, px = %d, py = %d\n", px, py);
}
}
APPL_OS_MSLEEP(500);
cnt = 0; ipx = 0; ipy = 0;
}
}
void lcd_init(void * data)
{
int i;
if (CYG_FB_ON(FRAMEBUF)) {
diag_printf("Open frambuf %s failed!\n", STRING(FRAMEBUF));
return;
}
diag_printf("Frame buffer %s, ", STRING(FRAMEBUF));
diag_printf("Depth %d, width %d\n", DEPTH, WIDTH);
// 打开背光
cyg_fb_ioctl_backlight backlight;
backlight.fbbl_current = 1;
i = sizeof(backlight);
CYG_FB_IOCTL(FRAMEBUF, CYG_FB_IOCTL_BACKLIGHT_SET, &backlight, &i);
if (CYG_FB_FLAGS0(FRAMEBUF) & CYG_FB_FLAGS0_TRUE_COLOUR) {
reset_colours_to_true();
}
// 白色背景
CYG_FB_FILL_BLOCK(FRAMEBUF, 0, 0, WIDTH, HEIGHT, WHITE);
// 画一条横线
CYG_FB_WRITE_HLINE(FRAMEBUF, 5, 20, 100, RED);
// 填充一个区域
CYG_FB_FILL_BLOCK(FRAMEBUF, 5, 30, 100, 20, YELLOW);
// 一条竖线
CYG_FB_WRITE_VLINE(FRAMEBUF, 1, 1, 100, BLUE);
// 一条竖线
CYG_FB_WRITE_VLINE(FRAMEBUF, 120, 1, 100, GREEN);
static bool init = false;
if (init == false) {
/* Create touch screen thread */
cyg_thread_create(6, /* Priority */
touch_screen_thread,
0,
"Touch screen thread",
LCD_TS_thread_stack,
sizeof(LCD_TS_thread_stack),
&LCD_TS_thread_handle,
&LCD_TS_thread_block);
cyg_thread_resume(LCD_TS_thread_handle);/* Starting thread */
init = true;
}
}
存在问题
- 当前的TSC2046驱动,触摸LCD屏时,虽然可以在LCD上显示一个红色的小方块,但触摸的位置与红色方块的显示位置不一致。这个还需要调整。
- 驱动没有做滤波处理,应用示例中,稍微做了个平均值处理,在实际中显示是不够的。
» 文章出处:
reille博客—http://velep.com
, 如果没有特别声明,文章均为reille博客原创作品
» 郑重声明:
原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)
推荐阅读相关文章:
- stm32移植ecos系列文章归档
- stm32移植ecos #13,redboot引导启动flash中的应用程序映像文件(下)
- stm32移植ecos #12,redboot引导启动flash中的应用程序映像文件(上)
- stm32移植ecos #11,使用自己的模板(Template)
- stm32移植ecos #10,移植ecos并成功运行helloworld程序,烧写到内部flash直接运行helloworld程序
- stm32移植ecos #9,移植ecos并成功运行helloworld程序,使用redboot引导运行内存中的helloworld程序
- stm32移植ecos #8,移植ecos并成功运行helloworld程序,编译链接生成helloworld程序
- stm32移植ecos #7,移植ecos并成功运行helloworld程序,配置编译生成静态链接库文件


串口打印效率很低,GDB调起来也不是太爽,主要还是没个好的IDE,不人性化
你挺速度的。我最近在弄uboot,GCC开发的东西还是挺难用的
现在是想把一些驱动弄好,然后想把这个stm32平台做稳定,不知道可实现否,呵呵!
u-boot我有移植啊,挺容易的。其实,GCC开发并不像你想得这么难用
有好的工具推荐吗,特别是在调试这块
我主要的调试方法的就是打印调试,据说GDB调试不错哦