0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于MM32F5和MindSDK使用轻量级图像解码器TJpgDec

冬至子 来源:灵动MM32 MCU 作者:灵动MM32 MCU 2023-11-03 15:27 次阅读

TJpgDec简介

TJpgDec是一个为小型嵌入式系统高度优化的创建JPEG图像的解码软件。它工作时占用的内存非常低,以便它可以集成到微控芯片,如AVR, 8051, PIC, Z80, Cortex-M0等。不依赖于具体的硬件平台,使用ANSI-C编写,易于使用的操作模式,完全可重入的体系结构,非常小的内存占用(独立于图像尺寸的3KB SRAM。3.5-8.5KB的代码空间)。输出格式可以是缩放比例为1/1、1/2、1/4或1/8可选,像素格式可以是RGB888或RGB565。

TJpgDec组件是一个免费开放的软件,可用于教育、科研和商业开发。用户可以在包含TJpgDec的个人项目和商业产品中改写和重新发布该组件。

TJpgDec组件在用户的应用中仅需要调用2个API。

jd_prepare() - 准备解码JPEG图像

jd_prepare 分析JPEG数据并创建一个解码对象用于随后的解码过程。

jd_prepare函数是JPEG解码过程的第一阶段。它接收用户传入的数据流(需要通过传入的回调函数操作数据流),分析JPEG图像和创建解码参数表。函数成功后,会话准备好在jd_decomp函数解码JPEG图像。应用程序可以参考JPEG解码对象中存储的尺寸大小。这个信息将用于在后续的解码阶段配置输出设备和参数。

JRESULT jd_prepare (
            JDEC* jdec,            /* Pointer to blank decompression object */
            UINT(*infunc)(JDEC*,BYTE*,UINT), /* Pointer to input function */
            void* work,            /* Pointer to work area */
            UINT sz_work,          /* Size of the work area */
            void* device           /* Device identifier for the session */
            );

输入参数:

  • jdec - 输出,一个空的JDEC结构体对象,初始化一个解码对象。需要用户先创建JPEC对象的内存,然后本函数在执行过程中会向其中填充有效信息,这个解码对象也将用于后续的解码操作。
  • infunc - 输入,指定一个为解码算法提供输入数据的回调函数。实际上,这个方法也是关联具体平台的,不仅仅是提供一个读数的方法,更确切是提供一个具体的数据流。这个infunc函数也是需要在具体平台适配过程中需要用户自行实现的。具体写法可以看原作者给的应用说明,也可以参见本文中的基于具体微控制器平台的实现。
  • work - 输入,指定一个内存块,给解码器内部运行算法的工作空间。
  • sz_work - 输入,指定work参数指定工作空间的 size,以字节为单位。TJpgDec至多需要3092字节的工作区域,这依赖于JPEG图像的内置参数表。通常情况下是3092字节工作区域。
  • device - 输入,指定用户自定义的会话设备标识。它保存在解码对象jdec的字段device中。它可以用于I/O函数去识别当前会话。当I/O device固定在project或者不需要这个功能,设置为NULL并忽略它。device参数可以作为回调函数中访问绑定硬件的传参。

返回值:

  • JDR_OK - 函数执行成功,且编码对象是有效的。
  • JDR_INP - 一个错误发生在input函数,由于硬件错误或者流终止。
  • JDR_MEM1 - 工作空间不足解码这个JPEG图像。
  • JDR_MEM2 - 工作空间不足解码这个JPEG图像。可能更小。
  • JDR_PAR - 参数错误。传入工作空间的指针为NULL。
  • JDR_FMT1 - 数据格式错误。JPEG数据损坏。
  • JDR_FMT2 - 格式正确,但不支持。也许是一个灰度图像。
  • JDR_FMT3 - 不支持JPEG标准,也许是一个后续版本的JPEG图像。

jd_decomp() - 执行解码JPEG图像

jd_decomp()函数解码JPEG图像并输出RGB数据。

jd_decomp()是JPEG解码过程的第二阶段。它进一步执行解码JPEG图像的过程,并通过用户定义的输出函数输出数据,但同时也继续使用在jd_prepare()传入的输入数据流的函数。在它之后,解码对象将不在有效。

在解码时指定的比例因子,它将JPEG图像按1/2、1/4或1/8比例缩放尺寸。例如,当解码一个1024x768大小JPEG图像在1/4比例,它将输出256x192大小。相比不缩放,1/2和1/4的缩放由于求均值,解码速度略有下降。但是1/8缩放相比不缩放是2-3倍的速度输出,因为每个块IDCT和求均值可以跳过,这一特点适合创建缩略图。

JRESULT jd_decomp (
            JDEC* jdec,             /* Pointer to valid decompressor object */
            UINT(*outfunc)(JDEC*,void*,JRECT*), /* Pointer to output function */
            BYTE scale              /* Scaling factor */
            );

输入参数:

  • jdec - 输入,指定有效的解码对象。其实就是之前在jd_prepare()函数中准备好的JDEC对象。
  • outfunc - 输入,指定用户定义的JPEG解码过程输出数据流的回调函数。jd_decomp()调用这个函数去输出解码JPEG图像的RGB形式数据流。具体写法可以看原作者给的应用说明,也可以参见本文中的基于具体微控制器平台的实现。
  • scale - 输入,指定输出缩放值N。输出图像的缩小比例为1/2^N(N = 0 to 3)。当不使用缩放功能时(JD_USE_SCALE == 0),可以指定为0。

返回值

  • JDR_OK - 函数执行成功。
  • JDR_INTR - 解码过程在输出函数中断。
  • JDR_INP - 一个错误发生在input函数,由于硬件错误或者流终止。
  • JDR_PAR - 参数错误。给定的缩放值无效。
  • JDR_FMT1 - 数据格式错误。JPEG数据损坏。

tjpgdcnf.h - 配置文件

早期版本的TjpgDec源码中并没有tjpgdcnf.h文件。我试着找了一下tjpgdec项目的changelog,没有直接找到关于版本更新的详情内容,但是遍历了到目前为止tjpgd所有发布版本的软件包,确定了tjpgdcnf.h首次出现的版本是2021年5月8日发布的R0.02版本。在这个文件中,更细化地提取了一些对TJpgDec软件配置和裁剪的一些选项,在当前最新的R0.03版本中源码如下(原作者非常贴心地注释了可用的选项和对应的解释):

/*----------------------------------------------*/
/* TJpgDec System Configurations R0.03          */
/*----------------------------------------------*/

#define    JD_SZBUF        512
/* 指定在输入数据流中每次读取的字节数,512、1024、2048等等均可。*/

#define JD_FORMAT        0
/* Specifies output pixel format.
/  0: RGB888 (24-bit/pix)
/  1: RGB565 (16-bit/pix)
/  2: Grayscale (8-bit/pix)
*/

#define    JD_USE_SCALE    1
/* Switches output descaling feature.
/  0: Disable
/  1: Enable
*/

#define JD_TBLCLIP        1
/* Use table conversion for saturation arithmetic. A bit faster, but increases 1 KB of code size.
/  0: Disable
/  1: Enable
*/

#define JD_FASTDECODE    0
/* Optimization level
/  0: Basic optimization. Suitable for 8/16-bit MCUs.
/  1: + 32-bit barrel shifter. Suitable for 32-bit MCUs.
/  2: + Table conversion for huffman decoding (wants 6 < < HUFF_BIT bytes of RAM)
*/

针对使用ARM Cortex-MC1处理器内核和FSMC驱动的16位并口屏幕的MM32F5微控制器,这里需要改写:

#define JD_FORMAT     1 /* 1: RGB565 (16-bit/pix) */
#define JD_FASTDECODE 1 /* 1: + 32-bit barrel shifter. Suitable for 32-bit MCUs. */

注意,这里似乎还藏了一个彩蛋。同时支持RGB888、RGB565和灰度图像,这意味着TJpgDec软件内部的源码内部包含了原始RGB888转RGB565和灰度图像的算式,这个在纯输出的GUI应用开发中讲会用到,届时可以直接复制验证过的代码片段,而不用我们再自行编写调试啦。

关于TJpgDec的软件许可证

这是一份包含在源代码TJpgDec中的许可声明。

/*----------------------------------------------------------------------------/
/ TJpgDec - Tiny JPEG Decompressor R0.xx                       (C)ChaN, 20xx
/-----------------------------------------------------------------------------/
/ The TJpgDec is a generic JPEG decompressor module for tiny embedded systems.
/ This is a free software that opened for education, research and commercial
/  developments under license policy of following terms.
/
/  Copyright (C) 20xx, ChaN, all right reserved.
/
/ * The TJpgDec module is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/----------------------------------------------------------------------------*/

TJpgDec许可是BSD风格的,但存在一些差异。因为TJpgDec是嵌入式项目,对以二进制形式的分发,如嵌入式代码,hex文件或二进制库,未指定以增加其可用性。分发的文档不强制包含关于tjpgdec及其授权文件。TJpgDec是基于GNU GPL兼容的项目。当有任何修改下重新分发,许可证也可以改为GNU GPL或BSD许可证。

应用接口解析

TJpgDec组件的移植过程仅需要实现两个函数,输入数据和输出数据。但从严格意义上讲,这两个函数都只是以约定的方式将数据流传入到TJpgDec组件,或者从TJpgDec组件中传出到指定存储空间,因为完全是内存到内存的操作,不涉及到任何与具体硬件平台相关绑定关系,所以也算不上移植。甚至在原作者的用户使用文档中,也是以应用笔记(TJpgDec Application Note)作为文档的名字,而不是移植指南。

原作者在《TJpgDec Module Application Note》中讲述了在应用中使用TJpgDec组件的操作步骤。建议用户先试着构建和运行原作者提供的示例程序。

解码会话分为两个阶段。第一阶段是分析JPEG图像,第二阶段是解码。

  1. 初始化输入流。(例如打开一个文件)
  2. 分配JPEG解码对象和工作区域。
  3. 调用jd_prepare()指定输入数据流,并执行分析和准备压缩的JPEG图像。
  4. 使用解码对象中的图像信息初始化输出设备。
  5. 调用jd_decomp()指定输出数据流,解码JPEG图像并输出。

image.png

图x 在应用中使用TJpgDec组件的调用关系图

这是原作者提供的一段参考源码,描述了如何使用TJpgDec模块。

/*------------------------------------------------*/
/* TJpgDec Quick Evaluation Program for PCs       */
/*------------------------------------------------*/
#include < stdio.h >
#include < string.h >
#include "tjpgd.h"

/* 用户定义设备标识 */
typedefstruct {
    FILE *fp;      /* 用于输入函数的文件指针 */
    BYTE *fbuf;    /* 用于输出函数的帧缓冲区的指针 */
    UINT wfbuf;    /* 帧缓冲区的图像宽度[像素] */
} IODEV;

/*------------------------------*/
/*      用户定义input funciton  */
/*------------------------------*/
UINT in_func (JDEC* jd, BYTE* buff, UINT nbyte)
{
    IODEV *dev = (IODEV*)jd- >device; /* Device identifier for the session (5th argument of jd_prepare function) */

    if (buff) {
        /* 从输入流读取一字节 */
        return (UINT)fread(buff, 1, nbyte, dev- >fp);
    } else {
        /* 从输入流移除一字节 */
        return fseek(dev- >fp, nbyte, SEEK_CUR) ? 0 : nbyte;
    }
}

/*------------------------------*/
/*      用户定义output funciton */
/*------------------------------*/
UINT out_func (JDEC* jd, void* bitmap, JRECT* rect)
{
    IODEV *dev = (IODEV*)jd- >device;
    BYTE *src, *dst;
    UINT y, bws, bwd;

    /* 输出进度 */
    if (rect- >left == 0) {
        printf("r%lu%%", (rect- >top < < jd- >scale) * 100UL / jd- >height);
    }

    /* 拷贝解码的RGB矩形范围到帧缓冲区(假设RGB888配置) */
    src = (BYTE*)bitmap;
    dst = dev- >fbuf + 3 * (rect- >top * dev- >wfbuf + rect- >left);  /* 目标矩形的左上 */
    bws = 3 * (rect- >right - rect- >left + 1);     /* 源矩形的宽度[字节] */
    bwd = 3 * dev- >wfbuf;                         /* 帧缓冲区宽度[字节] */
    for (y = rect- >top; y <= rect- >bottom; y++) {
        memcpy(dst, src, bws);   /* 拷贝一行 */
        src += bws; dst += bwd;  /* 定位下一行 */
    }

    return1;    /* 继续解码 */
}

/*------------------------------*/
/*        主程序                */
/*------------------------------*/
int main (int argc, char* argv[])
{
    void *work;       /* 指向解码工作区域 */
    JDEC jdec;        /* 解码对象 */
    JRESULT res;      /* TJpgDec API的返回值 */
    IODEV devid;      /* 用户定义设备标识 */

    /* 打开一个JPEG文件 */
    if (argc < 2) return-1;
    devid.fp = fopen(argv[1], "rb");
    if (!devid.fp) return-1;

    /* 分配一个用于TJpgDec的工作区域 */
    work = malloc(3500);

    /* 准备解码 */
    res = jd_prepare(&jdec, in_func, work, 3500, &devid);
    if (res == JDR_OK) {
        /* 准备好解码。图像信息有效 */
        printf("Image dimensions: %u by %u. %u bytes used.n", jdec.width, jdec.height, 3100 - jdec.sz_pool);

        devid.fbuf = malloc(3 * jdec.width * jdec.height); /* 输出图像的帧缓冲区(假设RGB888配置) */
        devid.wfbuf = jdec.width;

        res = jd_decomp(&jdec, out_func, 0);   /* 开始1/1缩放解码 */
        if (res == JDR_OK) {
            /* 解码成功。你在这里已经解码图像到帧缓冲区 */
            printf("rOK  n");
        } else {
            printf("Failed to decompress: rc=%dn", res);
        }
        free(devid.fbuf);    /* 释放帧缓冲区 */
    } else {
        printf("Failed to prepare: rc=%dn", res);
    }

    free(work);             /* 释放工作区域 */
    fclose(devid.fp);       /* 关闭JPEG文件 */

    return res;
}

这里详细说明两个回调函数的写法。

in_func() - 输入数据流回调函数

用户需要在输入数据流的回调函数in_func()中读取JPEG数据存入传参指针buff中。在jd_prepare()函数中传入数据流到TJpgDec模块。

UINT in_func (
            JDEC* jdec,    /* Pointer to the decompression object */
            BYTE* buff,    /* Pointer to buffer to store the read data */
            UINT ndata     /* Number of bytes to read */
            );

输入参数:

  • jdec - 输入,当前服务的jdec对象的handler。通过这个handler可以访问到当前服务的jdec对象的所有资源。
  • buff - 输出,一块内存区,从介质中读取指定数量的字节数据后,存放到这块内存区,交给调用者。但如果buff的值为NULL,就表示跳过ndata参数指定数量的数据。
  • ndata - 输入,调用者希望从输入数据流中读到的字节数量,即buff的大小。或者当buff的值为NULL时,此处参数指定为需要在输入数据流中跳过读取的字节数量。

实际上,这里还有一个隐形的参数,即出现在tjpgdcnf.h文件中的JD_SZBUF,它约定的应该是每次从输入流读取的最大字节数量,即ndata的最大值。

返回值:

  • 返回实际读取或移除的字节数。若返回0,jd_prepare()jd_decomp()函数将终止并返回JDR_INP

out_func() - 输出数据流回调函数

用户可指定解码出来的像素输出到具体的存储区,这个存储区可以是一块内存,或者映射到显存的地址空间。用户需要在out_func()函数内部,在rect参数执行的矩形区域中填充bitmap参数指定的像素信息。

UINT out_func (
            JDEC* jdec,    /* Pointer to the decompression object */
            void* bitmap,  /* RGB bitmap to be output */
            JRECT* rect    /* Rectangular region to output */
            );

输入参数:

  • jdec - 输入,当前服务的jdec对象的handler。通过这个handler可以访问到当前服务的jdec对象的所有资源。
  • bitmap - 像素数据流。是按照tjpgdcnf.h文件中JD_FORMAT选项指定的格式组织,可以是3字节表示的一个像素的RGB888格式,也可以是2字节表示一个像素的RGB565格式等。第一个像素是rect指定矩形区域的左上角,从左到右,从上到下,最后一个像素是右下角的位置。
  • rect - 输入,执行显示像素区域的矩形。JRECT类型的结构体中,有LeftRightTopBottom四个字段,指示当前解码输出的矩形区域。实际上,这个矩形的大小从1x1到16x16不等,取决于图像的裁剪、缩放和采样因子(JPEG信息)。

返回值:

  • 通常返回1,以便TJpgDec继续解码过程。当它返回0,jd_decomp函数终止并返回JDR_INTR

输入数据流可能时常发生变化,因为要读取不同的jpg图像文件。输出数据流也是在应用中根据需要变化的,只不过因为在大多数微控制器应用中,显示设备通常只有一个,所以统一输出到这个显示设备对应的显存中。有一些对于输出体验有要求的场景,需要输出到特定的存储空间,为了进行二次渲染,或者多缓冲区的应用,此时就需要在应用根据程序执行的情况动态切换输出了区域了。

关于工作区和帧缓冲区

在应用程序中调用jd_prepare()函数时,需要为TJpgDec指定一块工作区,作为TJpgDec在内部运行解码算法的临时空间。TJpgDec至少需要3100字节用于JPEG图像,这取决于解码JPEG图像使用怎样的参数。3100字节是在默认输入缓存(JD_SZBUF == 512)下的最大内存需求,并随JD_SZBUFJD_FASTDECODE的配置值变化。JD_SZBUF定义每次从输入流中读取多少字节。TJpgDec对齐每个读请求缓冲区大小,512, 1024, 2048... 字节是从存储设备读取的理想大小。

在样例代码中,原作者使用了动态分配的内存作为工作区,这对于拥有海量存储资源和完善内存管理机制的PC环境是合适的。但在资源受限的嵌入式系统平台上,使用静态内存会是更稳妥的选择。

另外,样例代码中使用了帧缓冲区(devid结构体变量中的fbuf指定内存区,wfbuf指定宽度),在应用程序和out_func回调函数之间传递像素数据,但实际看起来有点莫名其妙。此处了解到以矩形方式传送像素矩阵的模式之后,用户也可以自行简化代码。

在MM32F5微控制器上应用

在MM32F5微控制器上适配TJpgDec时,我使用了FatFs文件系统作为JPEG图像文件的来源,使用静态内存作为工作区,简化了对“帧缓冲区”的使用,并使用LCD模块作为输出设备。最终实现在微控制器系统中启用JPEG图像解码器的功能。

在包含TJpgDec组件的plus-f5270_image_fatfs_tjpgdec_basic_mdk工程中,我将打开图像文件并解码的过程封装成bool app_fs_display_jpg_file(char * filepath)函数,如此,在主循环中遍历到文件系统中的jpg文件后,可以直接使用其文件路径打开文件并显示像素信息到LCD屏上。这个函数中,就使用到了静态内存分配的工具区域app_tjpgdec_work_buff。从代码中可以看出,代码的内容被简化了不少。

#define APP_TJPGDEC_WORK_BUFF_SIZE 3500
uint8_t app_tjpgdec_work_buff[APP_TJPGDEC_WORK_BUFF_SIZE];

/* display a jpg file with its full filepath. */
bool app_fs_display_jpg_file(char * filepath)
{
    JRESULT res;      /* Result code of TJpgDec API */
    JDEC jdec;        /* Decompression object */
    //void *work;       /* Pointer to the work area */
    //size_t sz_work = 3500; /* Size of work area */
    IODEV devid;      /* Session identifier */
    FRESULT fres;
    
    /* Initialize input stream */
    devid.fp = &app_fs_file;
    fres = f_open(devid.fp, filepath, FA_READ);
    if (fres != FR_OK)
    {
        return-1;
    }
    
    /* Prepare to decompress */
    //work = (void*)malloc(sz_work);
    //res = jd_prepare(&jdec, in_func, work, sz_work, &devid);
    res = jd_prepare(&jdec, in_func, app_tjpgdec_work_buff, APP_TJPGDEC_WORK_BUFF_SIZE, &devid);
    if (res == JDR_OK)
    {
        /* It is ready to dcompress and image info is available here */
        //printf("Image size is %u x %u.n%u bytes of work ares is used.n", jdec.width, jdec.height, sz_work - jdec.sz_pool);

        /* Initialize output device */
        //devid.fbuf = (uint8_t*)malloc(N_BPP * jdec.width * jdec.height); /* Create frame buffer for output image */
        //devid.wfbuf = jdec.width;

        res = jd_decomp(&jdec, out_func, 0);   /* Start to decompress with 1/1 scaling */
        if (res == JDR_OK)
        {
            /* Decompression succeeded. You have the decompressed image in the frame buffer here. */
            printf("rDecompression succeeded.n");
        } else {
            printf("jd_decomp() failed (rc=%d)n", res);
        }
        //free(devid.fbuf);    /* Discard frame buffer */
    }
    else
    {
        printf("jd_prepare() failed (rc=%d)n", res);
    }
    //free(work);             /* Discard work area */
    f_close(devid.fp);       /* Close the JPEG file */
    returntrue;
}

同时,在实现输入输出数据流的回调函数时,也有一些考究。

在实现输入数据流的回调函数的过程中,由于使用了FatFs文件系统,其中很多类POSIX的接口同样例代码的行为并不完全一致,需要做一些转接的工作。特别FatFs文件系统中的f_lseek()函数是从文件开始计算偏移,而不是像通用的f_seek()函数从当前位置算偏移,因此需要使用f_tell()函数做一个适配。

size_t in_func (    /* Returns number of bytes read (zero on error) */
    JDEC* jd,       /* Decompression object */
    uint8_t* buff,  /* Pointer to the read buffer (null to remove data) */
    size_t nbyte    /* Number of bytes to read/remove */
)
{
    IODEV *dev = (IODEV*)jd- >device;   /* Session identifier (5th argument of jd_prepare function) */
    UINT br;

    if (buff) /* Read data from imput stream */
    {
        //return fread(dev- >fp, buff, 1, nbyte, dev- >fp);
        return (FR_OK == f_read(dev- >fp, buff, nbyte, &br)) ? br : 0;
    }
    else/* Remove data from input stream */
    {
        //return f_seek(dev- >fp, nbyte, SEEK_CUR) ? 0 : nbyte;
        return (FR_OK == f_lseek(dev- >fp, f_tell(dev- >fp) + nbyte)) ? nbyte : 0;
    }
}

在实现输出数据流的回调函数的过程中,可以直接对接到开发板上LCD屏的显存中,直接显示像素。

int out_func (      /* Returns 1 to continue, 0 to abort */
    JDEC* jd,       /* Decompression object */
    void* bitmap,   /* Bitmap data to be output */
    JRECT* rect     /* Rectangular region of output image */
)
{
    /* Progress indicator */
    if (rect- >left == 0)
    {
        printf("r%lu%%", (rect- >top < < jd- >scale) * 100UL / jd- >height);
    }
    
    /* 在LCD屏幕上显示图像信息. */
    LCD_FillWindow(rect- >left, rect- >top, rect- >right, rect- >bottom, (uint16_t *)bitmap);

    return1;    /* Continue to decompress */
}

Keil工程中编译可执行文件,下载到plus-f5270开发板上,实物演示如图x所示。

640.gif

图x 在plus-f5270开发板上运行TJpgDec

Code Size (-0):

==============================================================================

    Total RO  Size (Code + RO Data)                45096 (  44.04kB)
    Total RW  Size (RW Data + ZI Data)             13032 (  12.73kB)
    Total ROM Size (Code + RO Data + RW Data)      45104 (  44.05kB)

==============================================================================

其中,SRAM占用量是比较少的,总共13032字节,其中系统栈占用4KB,系统堆占用4KB,工作空间占用3500字节,还带了个FatFs文件系统,这已经算是非常经济的用量了。

一点思考

从实际演示效果来看,移植的样例工程能够完成JPEG解码功能,验证了TJpgDec组件能够正常工作,这是非常不错的。但由于从SD卡读数、解码、刷屏这些个步骤都是一小段一小段执行的,因此实际显示图像刷屏的速度不是很快(估计受读取SD卡过程的影响较大)。一种改进的策略,是将解码得到的图像片段搜集到一块大内存中,然后集中刷屏,这样视觉效果会好很多。解码完之后纯刷屏的速度很快,解码之前虽然有等待,但当前屏幕上还在放映之前解码的图片,参观者不会感到无趣。

plus-f5270开发板上的MM32F5270微控制器仅有128KB的SRAM,不够存放一整张图(480x320),但是可以存放1/4个屏幕的图片数据(75KB),可以考虑将屏幕分成四块小屏来用,每次刷一块。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 微控制器
    +关注

    关注

    48

    文章

    6811

    浏览量

    147646
  • 解码器
    +关注

    关注

    9

    文章

    1073

    浏览量

    40158
  • RGB
    RGB
    +关注

    关注

    4

    文章

    763

    浏览量

    57412
  • 回调函数
    +关注

    关注

    0

    文章

    87

    浏览量

    11455
  • SRAM存储器
    +关注

    关注

    0

    文章

    86

    浏览量

    13146
收藏 人收藏

    评论

    相关推荐

    创建51轻量级操作系统

    创建51轻量级操作系统
    发表于 09-29 09:58

    应用AM3358,请问怎样在硬件设计上外部连接解码器芯片,实现对图像数据的解码

    本帖最后由 一只耳朵怪 于 2018-6-5 14:46 编辑 图像数据由网口发送给AM3358,需要解码,现在想通过外部连接解码器芯片来实现,可是看了下手册,不太清楚ARM由哪
    发表于 06-04 15:35

    10个轻量级框架

    这些轻量级框架使用HTML5和CSS3标准来帮助您快速开发跨平台的Web移动应用和网站。
    发表于 07-17 08:25

    轻量级深度学习网络是什么

    轻量级深度学习网络概览
    发表于 04-23 14:53

    解码器常见故障及解决方法

    220v供电端口电压是否输出正常;  3、直接给云台的up、down、与PTCom线进行供电,检查云台是否能正常工作;  4、检查供电接口是否接错;  5、检查电路是否接错(老解码器为up、down等线
    发表于 12-11 14:12

    轻量级的ui框架如何去制作

    原创分享:自制轻量级单片机UI框架框架元素用户接口代码开源平时常看csdn,但是从来没有自己写过。正好这几天需要用单片机做一个简易的ui界面,于是自己写了一个轻量级的ui框架。发个csdn分享给大家
    发表于 07-14 07:39

    介绍一款轻量级ARM AI智能网关产品

    、SATA3.0、CAN-FD、USB3.0等高速接口,2路千兆以太网和最多10路UART接口,同时支持有线网络、4G/5G、双频WiFi等通讯方式,可满足常规工业网关的数据采集和通讯功能。轻量级人工智能
    发表于 06-06 16:39

    基于MindSDK测试MM32F5270开发板IIC简析

    1、通过调用MindSDK例程查看内部集成电路接口IICMM32F5270 是基于安谋科技的 Armv-8 架构的“星辰”STAR-MC1 处理开发的 32位微控制产品。本篇文章通
    发表于 08-26 15:05

    基于MM32F5270开发板对MindSDK进行使用测评

    1、MindSDK使用测评步骤  Plus-F5270,据灵动微电子市场总监王维介绍,MM32F5系列采用Armv8-M Mainline架构,全系配置安谋科技“星辰”STAR-MC1处理
    发表于 09-01 17:05

    如何将imx8mm的h.264编解码器与FreeRTOS一起使用?

    我有一个需要 h.264 编解码器的简单应用程序,不需要所有其他花哨的东西。我正在尝试在不运行 Linux 的情况下使用 imx8mm 的 h.264 编解码器(Linux 对我的特定应用程序来说
    发表于 03-14 09:54

    DTMF解码器原理是什么?

    DTMF 解码器原理
    发表于 10-27 08:29

    基于C语言的轻量级高效XML编解码器

    将树形数据结构用于最小化DOM 模型XML 编解码器的开发。在解析XML 文本时,基于Expat 解释器将XML 字符串构造成树状结构;编码时构造DOM 树结构,采用非递归深度优先法遍历树,将其
    发表于 03-21 15:49 33次下载

    高清解码器的作用

    高清解码器(xunwei)的主要作用在于接收前端高清编码图像或网络摄像头信号并解码,然后通过自身的各种视频输出接口,如HDMI、DVI、SDI、VGA、BNC输出显示到显示设备上。编码器和解码
    的头像 发表于 12-10 15:47 1.2w次阅读
    高清<b class='flag-5'>解码器</b>的作用

    解码器该怎么选?

    当一个监控项目中是有多台录像机的时候,每台录像机是可以接显示器来显示图像,但是!它只能显示自己添加的摄像机图像! * **解码器** **是可以把任意一台录像机的图像的任意一个摄像机
    的头像 发表于 05-06 11:07 2543次阅读

    MindSDKMM32实现了一组TIM样例工程

    MindSDKMM32使用星辰处理器内核的系列微控制器,实现了一组TIM样例工程,MindSDK中的TIM模块对应硬件定时器TIM外设。
    的头像 发表于 06-30 17:32 663次阅读