lynnen 2011年02月07日 星期一 15:55 | 7015次浏览 | 0条评论
本人这些年也算是做过几个俗话说是嵌入式系统的人,可以说做嵌入试系统其实就是做3大块。第一大块是存储,以NandFlash , SD卡为代表,现在是Emmc Flash(4.4版),做存储加上要考虑boot的问题,要做文件系统。 第二大块是广义的网络连接,包括串口,USB,WiFi, 3G 。 第三大块就是用户I/O, 主要就是显示技术了,对用户来说最直观看得着的就是显示屏了。
这几年我也开发及调试过不少显示屏,其中最有特色,最难调试的就算EInk屏了。为什么? 第一,它要有专门的电源管理配合,其中还有一个VCOM,不仅要用I2C寄存器去控制它的开关,还要用GPIO(GPIO4_21)去控制它是否加载到 EInk上。其二,就是它要有一个Waveform文件,就是波形文件去配合它,它是电子墨水运动轨迹的定义。
在I.MX5的内核中带了一个默认的Waveform文件,以6寸屏为例,文件在 {kernel}/firmware/imx/epdc_E60_V110.fw, 下面分析一下它的结构。
epdc_e60_v110.fw 文件 = 一个48字节的头 + 14字节温度项 + 1字节间隔 + 全部数据
用hexedit 来看
$hexedit epdc_e60_v110.fw
再结合kernel中EInk的驱动来看,kernel中EInk的驱动在 {kernel}/drivers/video/mxc/mxc_epdc_fb.c , 其中读取waveform文件,并加载数据的部分在 mxc_epdc_fb_fw_handler(...)中,waveform头结构的定义在前面 struct waveform_data_header 中
struct waveform_data_header {
unsigned int wi0;
unsigned int wi1;
unsigned int wi2;
unsigned int wi3;
unsigned int wi4;
unsigned int wi5;
unsigned int wi6;
unsigned int xwia:24;
unsigned int cs1:8;
unsigned int wmta:24;
unsigned int fvsn:8;
unsigned int luts:8;
unsigned int mc:8;
unsigned int trc:8;
unsigned int reserved0_0:8;
unsigned int eb:8;
unsigned int sb:8;
unsigned int reserved0_1:8;
unsigned int reserved0_2:8;
unsigned int reserved0_3:8;
unsigned int reserved0_4:8;
unsigned int reserved0_5:8;
unsigned int cs2:8;
};
struct mxcfb_waveform_data_file {
struct waveform_data_header wdh;
u32 *data; /* Temperature Range Table + Waveform Data */
};
static void mxc_epdc_fb_fw_handler(const struct firmware *fw,
void *context)
{
struct mxc_epdc_fb_data *fb_data = context;
int ret;
struct mxcfb_waveform_data_file *wv_file;
int wv_data_offs;
int i;
struct mxcfb_update_data update;
.... //空指针处理,略
wv_file = (struct mxcfb_waveform_data_file *)fw->data;
/* Get size and allocate temperature range table */
fb_data->trt_entries = wv_file->wdh.trc + 1;
//这里wdh.trc就是0Dh, =13 , 所以trt_entries = 14,温度项算14个字节。
fb_data->temp_range_bounds = kzalloc(fb_data->trt_entries, GFP_KERNEL); //这里分配14个字节的空间给温度项保存,即 temp_range_bounds
for (i = 0; i < fb_data->trt_entries; i++)
dev_dbg(fb_data->dev, "trt entry #%d = 0x%x\n", i, *((u8 *)&wv_file->data + i));
//把温度项14个字节打印出来。
/* Copy TRT data */
memcpy(fb_data->temp_range_bounds, &wv_file->data, fb_data->trt_entries);
//把温度项14个字节装到temp_range_bounds内存块中。
/* Set default temperature index using TRT and room temp */
fb_data->temp_index = mxc_epdc_fb_get_temp_index(fb_data, DEFAULT_TEMP);
/* Get offset and size for waveform data */
wv_data_offs = sizeof(wv_file->wdh) + fb_data->trt_entries + 1;
//最后,计算真正的data偏移位置,= 48字节的wdh + 14字节的trt_entries + 1 = 63;
fb_data->waveform_buffer_size = fw->size - wv_data_offs; //data块的大小 = waveform文件的大小 - data偏移 = waveform文件大小 - 63 ;
/* Allocate memory for waveform data */
fb_data->waveform_buffer_virt = dma_alloc_coherent(fb_data->dev,
fb_data->waveform_buffer_size,
&fb_data->waveform_buffer_phys,
GFP_DMA); //给waveform数据分配内存块,大小=waveform文件大小 - 63
// dma内存分配调用完后得到两个地址,一个是虚拟地址,一个是物理地址,两个是对应的,虚拟地址给linux程序用,物理地址用来写入硬件寄存器。
if (fb_data->waveform_buffer_virt == NULL) {
dev_err(fb_data->dev, "Can't allocate mem for waveform!\n");
return;
}
memcpy(fb_data->waveform_buffer_virt, (u8 *)(fw->data) + wv_data_offs,
fb_data->waveform_buffer_size);
//将数据装入分配好的内存块
release_firmware(fw);
//数据已经装入内存块了,释放waveform文件。
/* Enable clocks to access EPDC regs */
clk_enable(fb_data->epdc_clk_axi);
/* Enable pix clk for EPDC */
clk_enable(fb_data->epdc_clk_pix);
clk_set_rate(fb_data->epdc_clk_pix, fb_data->cur_mode->vmode->pixclock);
epdc_init_sequence(fb_data);
/* Disable clocks */
clk_disable(fb_data->epdc_clk_axi);
clk_disable(fb_data->epdc_clk_pix);
fb_data->hw_ready = true;
update.update_region.left = 0;
update.update_region.width = fb_data->info.var.xres;
update.update_region.top = 0;
update.update_region.height = fb_data->info.var.yres;
update.update_mode = UPDATE_MODE_FULL;
update.waveform_mode = WAVEFORM_MODE_AUTO;
update.update_marker = INIT_UPDATE_MARKER;
update.temp = TEMP_USE_AMBIENT;
update.flags = 0;
mxc_epdc_fb_send_update(&update, &fb_data->info);
/* Block on initial update */
ret = mxc_epdc_fb_wait_update_complete(update.update_marker,
&fb_data->info);
if (ret < 0)
dev_err(fb_data->dev,
"Wait for update complete failed. Error = 0x%x", ret);
}
Zeuux © 2024
京ICP备05028076号
暂时没有评论