原创 EInk显示屏 waveform文件的分析

2011-2-4 10:52 4700 6 8 分类: 消费电子

        本人这些年也算是做过几个俗话说是嵌入式系统的人,可以说做嵌入试系统其实就是做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


758adf0c-952f-4bdf-9d4b-7ccf77526c56.jpg




       再结合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);
}


PARTNER CONTENT

文章评论2条评论)

登录后参与讨论

用户377235 2016-6-2 11:17

e-ink 是用.fb_fillrect = cfb_fillrect,实现局部刷新的吗

用户377235 2015-9-11 21:41

搞这个的都变成了练屠龙刀了
相关推荐阅读
用户308740 2011-02-28 20:57
MEMS之重力加速器mma7660,与陀螺仪
         这两天调好了3轴g-sensor ,mma7660, 可以用了. 倾斜晃动或改变板子的方向, mma7660就会产生中断, 并给出当前板子的姿态(水平/垂直, 上下,左右等).   ...
用户308740 2011-02-17 09:03
tps65180 , EInk 屏的电源管理芯片
         Eink屏不同于普通的LCD屏,它需要+20V,-22V,+15V,-15V,+3.3V,-1.25V 等不同级别的电压,而且EInk屏是一种非常省电的屏幕,它只有在刷新(翻页)时需...
用户308740 2011-02-11 11:26
mc13892,电源管理芯片分析
        I.MX5x 系列配合使用Freescale的MC13892做为PMIC 。 此处粘贴的原理图以I.MX51 EVK板为例。 Features   特点1) Battery charg...
用户308740 2011-02-10 17:13
I.MX515, 大众化的平板电脑方案
    决定今后要做基于I.MX的方案     平板电脑还会火吗?上网本如何? ChromeOS如何?     MX515的资料全部公开了,515很适合平板电脑,做的人多,买的人也多.    MX51...
用户308740 2011-02-07 16:24
回顾过去,展望未来
        春节,难得有一点点的清闲. 早上醒来,忽然很怀念过去的时光, 记得那时候住在出租屋里, 可那时候没觉得自己不成功, 也没想到过要买房投资挣快钱这类事, 那时候很单纯, 就觉得技术这东西...
用户308740 2011-02-04 10:54
i.mx508 最强电子书方案
         i.mx508是专用于电子书的方案,特点是I.MX508主芯片内集成了EInk屏控制器,而以往的方案中EInk屏控制器是独立的。不过该方案还是必须外加EInk屏电源管理芯片(PMIC...
我要评论
2
6
关闭 站长推荐上一条 /3 下一条