470 likes | 711 Views
嵌入式系统与结构 第 10 课 数码相机实例. 概述. 简单数码相机实现介绍 设计者的观点 需求说明 设计方案 4 种实现. Introduction. 几种技术相结合进行简单数码相机的设计 通用目的处理器 单目的处理器 定制 标准 存储器 接口设计. 简单数码相机功能 - 从用户观点. 捕获图像 以数字的形式保存图像 非胶片形式 在相机内保存多幅图像 图像的数量依赖每幅图像使用的位数和内存大小 可以把图像下载到 PC 数码相机的重要技术支持 片上系统的出现 Systems-on-a-chip 高容量的闪存存储器
E N D
嵌入式系统与结构 第10课 数码相机实例
概述 • 简单数码相机实现介绍 • 设计者的观点 • 需求说明 • 设计方案 • 4种实现
Introduction • 几种技术相结合进行简单数码相机的设计 • 通用目的处理器 • 单目的处理器 • 定制 • 标准 • 存储器 • 接口设计
简单数码相机功能-从用户观点 • 捕获图像 • 以数字的形式保存图像 • 非胶片形式 • 在相机内保存多幅图像 • 图像的数量依赖每幅图像使用的位数和内存大小 • 可以把图像下载到PC • 数码相机的重要技术支持 • 片上系统的出现 Systems-on-a-chip • 高容量的闪存存储器 • 本例采用一个非常简单的描述 • 实际相机会有更多的特性 • 可变尺寸图像,图像删除,图像放大与缩小等
设计者的观点 • 需要完成两个主要任务 • 处理图像并在存储器种保存 • 当快门按下: • 捕获图像 • 通过电荷耦合器件(CCD)转化成数字格式 • 在内存种完成压缩和保存 • 上传图像到PC • 数码相机连接到PC • 用专用软件串行的传送图像
当暴露在光下,每个单元带电荷,被转换成8bit数值, 0 表示没有曝光255表示最强的曝光 . 几列单元被遮挡,作为对所有其它单元的零偏校正. 电子机械快门使得CCD单元被曝光一个短时间段 电路获得命令后把单元放电,激活电子机械快门,读入每个单元的8bit值。这些数据通过并行总线接口读入。 Lens area Covered columns Electro-mechanical shutter Electronic circuitry Pixel rows Pixel columns 电荷耦合器件 (CCD) • 用来捕获图像的专用传感器 • 许多单元的光敏硅固态器件
Covered cells Zero-bias adjustment Before zero-bias adjustment After zero-bias adjustment 零-偏差误差 • 单元的制造误差会引起测量值比实际值偏高或偏低 • 误差每一列相同,当每一行不同 • 最左的几列被用于进行零偏差校正
压缩 • 能够保存更多的图像 • 图像象PC传送更快 • JPEG (Joint Photographic Experts Group) • 数字图像压缩形式的最流行的标准 • 提供许多运算模式 • 本章采用模式使用离散余弦变换提供高压缩率 • 图像分成 8 x 8 的象素块 • 每个块执行3个运算步骤 • DCT变换 • 量化 • Huffman 编码
DCT 步骤 • 将原始的8 x 8 block 转换到余弦频域 • 左上角表示图像的基本要素 • 右下角代表图像的细节 • 可以减小这些值的精度并保留可接受的图像质量 • FDCT (前向 DCT) 公式 • C(h) = if (h == 0) then 1/sqrt(2) else 1.0 • 辅助函数,主公式为 F(u,v) • F(u,v) = ¼ x C(u) x C(v) Σx=0..7 Σy=0..7 Dxy x cos(π(2u + 1)u/16) x cos(π(2y + 1)v/16) • 给出了第u行,第v列的编码象素值 • Dxy is是第x行第y列的原始象素值 • IDCT (反向DCT) • 为得到原始数据块而做的一个方向过程(本例中不使用)
量化 • 通过降低图像质量完成一个高压缩率 • 降低编码数据位精度 • 更少的位被编码 • 将所有值除2的指数倍 • 解量化是一个相反的过程 每个单元同除8 After being decoded using DCT After quantization
Huffman编码 • 串行化 8 x 8 象素块 • 按照Z字形图形将这些数值转换成串行列表,然后再转成Huffman编码。 • 执行Huffman 编码 • 最经常出现的象素值分配最短二进制码 • 更长的二进制码留给更少使用的象素值 • 串行数列中的每个象素转换成Huffman 编码值 • 短的多的列表值,然后压缩
Huffman codes Pixel frequencies Huffman tree 64 35 29 17 18 14 15 -1 11 10 9 6 8 5 -2 0 1 6 5 4 5 5 5 2 3 5 2 2 2 4 3 2 -5 -3 -10 1 1 1 1 1 1 -9 144 -4 -8 14 6 Huffman 编码举例 • 计算象素出现的频率 • 从低向上建立Huffman 树 • 遍历树得到叶子节点的二进制编码 • Huffman 编码是可逆的 • 任何节点不会是另一个节点的首部分
保存步骤 • 记录开始地址和图像大小 • 用链表数据结构来表示这些信息 • 保存图像的一种方案 • 若被保存的图像最大数目为N: • 为 N 个地址和 N 个图像尺寸变量保留存储器空间 • 用计数器来记录存储器下一个可用地址的位置 • 初始地址和图像尺寸变量设置成0 • 设置全局内存地址为N x 4 • 地址,图像尺寸变量占用 N x 4 bytes • 第一个保存的图像从地址N x 4开始 • 全局存储器地址更新到N x 4 + (compressed image size) • Memory 需求取决于N, 图像大小,编码得到的平均压缩比
上传到 PC • 当连接到PC 并且收到上传命令 • 从存储器中度图像 • 用UART串行发送 • 发送过程中 • 数据指针,图像尺寸变量和全局内存指针进行相应的改变
需求规范 • 系统需求 –系统应该干什么 • 非功能需求 • 设计指标约束 (e.g., “应不大于 0.001 watt”) • 功能需求 • 系统行为 (e.g., “输出 X 应为输入Y 乘以 2”) • 开始的规范可以非常笼统,可以来自市场部门 • E.g., 短文档描述低端数码相机的市场需求: • 捕获并保存至少 50幅低分辨图像,并且能上传到 PC, • 成本在$100左右,使用一个中等大小,成本低于$25的IC • 电池寿命越长越好 • 如果6个月内上市,则预期销售量为200,000 • 如果6到12个月上市,预期销售量为100,000 • 上市时间超过12个月,则销量很有限
非功能需求 • 基于初始规范确定重要设计指标 • Performance: 处理图像所需要的时间 • Size: IC 基本逻辑门的数量 (2-input NAND gate) • Power: 在处理图像时消耗的平均电能 • Energy: 电池寿命(power x time) • 约束性指标 • 值必须在某一门限值之下 • 最优化指标 • 为提高品质需要尽可能提高的指标 • 指标可以同时是约束指标和最优化指标
非功能需求 (cont.) • Performance • 必须处理图像足够快才又用 • 1 sec 是一个合理的约束 • 超过1s会觉得讨厌 • 远小于1s则在低端市场没有必要 • 因此这时一个约束指标 • Size • 必须使用IC才能得到合理尺寸的相机 • 是约束性和最优化指标 • 约束可以是 200,000 门, 但IC越小越便宜 • Power • IC必须运行在某一温度之下 (风冷不实际) • 是一个约束性指标(假设200mW) • Energy • 降低功耗或时间来降低能耗 • 优化指标: 希望电池能持续时间越长越好
零偏置调整 CCD input DCT Quantize yes Done? no 保存到内存 More 8×8 blocks? yes no 串行传输 serial output e.g., 011010... 非正式的功能规范 • 流程图将功能分成更简单的功能 • 每个功能可用文字详细描述 • 低质量图像采用分辨力64 x 64 • 没有映射每一个功能块一定要对应不同的处理器,只是对功能进行分解
CCD.C 101011010110101010010101101... CODEC.C CCDPP.C image file CNTRL.C 1010101010101010101010101010... UART.C output file 精确的功能规范 • 将非正式规范细化成一个可执行的规范 • 可采用 C/C++ code to 描述每个功能 • 称为系统级模型,原型 • 是第一个可实现模型 • 能提供系统运行的深入理解 • Profiling can find computationally intensive functions • 能得到样本输出用于验证最终实现的正确性 Executable model of digital camera
CCD module void CcdInitialize(const char *imageFileName) { imageFileHandle = fopen(imageFileName, "r"); rowIndex = -1; colIndex = -1; } • Simulates real CCD • CcdInitialize is passed name of image file • CcdCapture reads “image” from file • CcdPopPixel outputs pixels one at a time #include <stdio.h> #define SZ_ROW 64 #define SZ_COL (64 + 2) static FILE *imageFileHandle; static char buffer[SZ_ROW][SZ_COL]; static unsigned rowIndex, colIndex; void CcdCapture(void) { int pixel; rewind(imageFileHandle); for(rowIndex=0; rowIndex<SZ_ROW; rowIndex++) { for(colIndex=0; colIndex<SZ_COL; colIndex++) { if( fscanf(imageFileHandle, "%i", &pixel) == 1 ) { buffer[rowIndex][colIndex] = (char)pixel; } } } rowIndex = 0; colIndex = 0; } char CcdPopPixel(void) { char pixel; pixel = buffer[rowIndex][colIndex]; if( ++colIndex == SZ_COL ) { colIndex = 0; if( ++rowIndex == SZ_ROW ) { colIndex = -1; rowIndex = -1; } } return pixel; }
CCDPP (CCD PreProcessing) module #define SZ_ROW 64 #define SZ_COL 64 static char buffer[SZ_ROW][SZ_COL]; static unsigned rowIndex, colIndex; • 完成 zero-bias 调整 • CcdppCapture调用 CcdCapture and CcdPopPixel获得图像 • 读入每一行后进行 zero-bias adjustment void CcdppInitialize() { rowIndex = -1; colIndex = -1; } void CcdppCapture(void) { char bias; CcdCapture(); for(rowIndex=0; rowIndex<SZ_ROW; rowIndex++) { for(colIndex=0; colIndex<SZ_COL; colIndex++) { buffer[rowIndex][colIndex] = CcdPopPixel(); } bias = (CcdPopPixel() + CcdPopPixel()) / 2; for(colIndex=0; colIndex<SZ_COL; colIndex++) { buffer[rowIndex][colIndex] -= bias; } } rowIndex = 0; colIndex = 0; } char CcdppPopPixel(void) { char pixel; pixel = buffer[rowIndex][colIndex]; if( ++colIndex == SZ_COL ) { colIndex = 0; if( ++rowIndex == SZ_ROW ) { colIndex = -1; rowIndex = -1; } } return pixel; }
UART module • 实际完成了一半功能的 UART • Only transmits, does not receive • UartInitialize传送一个要输出的文件名 • UartSend一次发送一个字节 #include <stdio.h> static FILE *outputFileHandle; void UartInitialize(const char *outputFileName) { outputFileHandle = fopen(outputFileName, "w"); } void UartSend(char d) { fprintf(outputFileHandle, "%i\n", (int)d); }
static short ibuffer[8][8], obuffer[8][8], idx; void CodecInitialize(void) { idx = 0; } void CodecPushPixel(short p) { if( idx == 64 ) idx = 0; ibuffer[idx / 8][idx % 8] = p; idx++; } void CodecDoFdct(void) { int x, y; for(x=0; x<8; x++) { for(y=0; y<8; y++) obuffer[x][y] = FDCT(x, y, ibuffer); } idx = 0; } short CodecPopPixel(void) { short p; if( idx == 64 ) idx = 0; p = obuffer[idx / 8][idx % 8]; idx++; return p; } CODEC module • 建模 FDCT编码 • ibuffer holds original 8 x 8 block • obuffer holds encoded 8 x 8 block • CodecPushPixel 被调用 64 times 用初始块填满 ibuffer • CodecDoFdct调用1次转换 8 x 8 block • CodecPopPixel 调用64 次从obuffer得到象素
CODEC (cont.) static const short COS_TABLE[8][8] = { { 32768, 32138, 30273, 27245, 23170, 18204, 12539, 6392 }, { 32768, 27245, 12539, -6392, -23170, -32138, -30273, -18204 }, { 32768, 18204, -12539, -32138, -23170, 6392, 30273, 27245 }, { 32768, 6392, -30273, -18204, 23170, 27245, -12539, -32138 }, { 32768, -6392, -30273, 18204, 23170, -27245, -12539, 32138 }, { 32768, -18204, -12539, 32138, -23170, -6392, 30273, -27245 }, { 32768, -27245, 12539, 6392, -23170, 32138, -30273, 18204 }, { 32768, -32138, 30273, -27245, 23170, -18204, 12539, -6392 } }; • 实现 FDCT的公式 C(h) = if (h == 0) then 1/sqrt(2) else 1.0 F(u,v) = ¼ x C(u) x C(v) Σx=0..7 Σy=0..7 Dxy x cos(π(2u + 1)u/16) x cos(π(2y + 1)v/16) • 仅 64个可能输入值到COS, 因此可使用一个表来提高性能 • Floating-point values multiplied by 32,678 and rounded to nearest integer • 32,678 chosen in order to store each value in 2 bytes of memory • Fixed-point representation explained more later static short ONE_OVER_SQRT_TWO = 23170; static double COS(int xy, int uv) { return COS_TABLE[xy][uv] / 32768.0; } static double C(int h) { return h ? 1.0 : ONE_OVER_SQRT_TWO / 32768.0; } static int FDCT(int u, int v, short img[8][8]) { double s[8], r = 0; int x; for(x=0; x<8; x++) { s[x] = img[x][0] * COS(0, v) + img[x][1] * COS(1, v) + img[x][2] * COS(2, v) + img[x][3] * COS(3, v) + img[x][4] * COS(4, v) + img[x][5] * COS(5, v) + img[x][6] * COS(6, v) + img[x][7] * COS(7, v); } for(x=0; x<8; x++) r += s[x] * COS(x, u); return (short)(r * .25 * C(u) * C(v)); }
void CntrlSendImage(void) { for(i=0; i<SZ_ROW; i++) for(j=0; j<SZ_COL; j++) { temp = buffer[i][j]; UartSend(((char*)&temp)[0]); /* send upper byte */ UartSend(((char*)&temp)[1]); /* send lower byte */ } } } void CntrlCompressImage(void) { for(i=0; i<NUM_ROW_BLOCKS; i++) for(j=0; j<NUM_COL_BLOCKS; j++) { for(k=0; k<8; k++) for(l=0; l<8; l++) CodecPushPixel( (char)buffer[i * 8 + k][j * 8 + l]); CodecDoFdct();/* part 1 - FDCT */ for(k=0; k<8; k++) for(l=0; l<8; l++) { buffer[i * 8 + k][j * 8 + l] = CodecPopPixel(); /* part 2 - quantization */ buffer[i*8+k][j*8+l] >>= 6; } } } void CntrlCaptureImage(void) { CcdppCapture(); for(i=0; i<SZ_ROW; i++) for(j=0; j<SZ_COL; j++) buffer[i][j] = CcdppPopPixel(); } #define SZ_ROW 64 #define SZ_COL 64 #define NUM_ROW_BLOCKS (SZ_ROW / 8) #define NUM_COL_BLOCKS (SZ_COL / 8) static short buffer[SZ_ROW][SZ_COL], i, j, k, l, temp; void CntrlInitialize(void) {} CNTRL (controller) module • 系统核心 • CntrlInitialize与其它模块一致 • CntrlCaptureImage利用 CCDPP 模块输入图像并放置到缓冲区 • CntrlCompressImage将 64 x 64 缓冲分成8 x 8 块并调用CODEC模块对每个块执行FDCT • 同时对每个块进行量化 • CntrlSendImage用UART模块发送编码图像
将模块放到一起 • Main 初始化所有的模块,然后使用CNTRL模块进行捕获,压缩和发送一个图像 • 这个系统级模型能够用于大量的实验, • 在这里进行Bugs 的纠正要比在后期模型进行纠正要容易的多 int main(int argc, char *argv[]) { char *uartOutputFileName = argc > 1 ? argv[1] : "uart_out.txt"; char *imageFileName = argc > 2 ? argv[2] : "image.txt"; /* initialize the modules */ UartInitialize(uartOutputFileName); CcdInitialize(imageFileName); CcdppInitialize(); CodecInitialize(); CntrlInitialize(); /* simulate functionality */ CntrlCaptureImage(); CntrlCompressImage(); CntrlSendImage(); }
设计过程 • 决定系统的结构 • 处理器 • 单目的与通用目的处理器的某一种结合 • 存储器,总线的选用 • 映射功能到这些结构上 • 多个功能到一个处理器上 • 一个功能到一个或多个处理器 • 实现 • 一种特定的结构和映射 • 解决方案空间是所有实现的集合 • 设计开始点 • 低端通用处理器连接到一个 • 全部功能映射到软件,在一个处理器上运行 • 一般能满足功耗,尺寸,上市时间的约束 • 如果性能约束不能满足,后续实现能够: • 利用单目的处理器设计时间约束严格的功能 • 重写功能规范
实现 1: 只使用微控制器 • 采用Intel 8051 microcontroller • 总的 IC 成本包括NRE大约$5 • 功耗远低于200 mW • 上市时间大约 3 months • 但每秒处理一幅图像不可能 • 时钟12 MHz,每条指令12 cycles • 每秒钟执行1百万指令 • CcdppCapture有嵌套循环进行4096 (64 x 64) 次遍历 • 每次遍历大约~100 汇编指令 • 每幅图像409,000 (4096 x 100) 指令 • 一半的预算用于读图像 • 加上计算密集型的DCT and Huffman encoding运算将大大超出预算
EEPROM RAM 8051 UART CCDPP SOC 实现 2: 微控制器与CCDPP • CCDPP 功能利用单用途处理器实现 • 改进性能–更少的微控制器周期 • 增加了 NRE 成本和上市时间 • 易实现 • 简单的数据通道 • 控制器很少的状态 • 简单的 UART易于用单用途处理器实现 • 利用EEPROM 用于程序存储器, RAM用于数据存储器
4K ROM Instruction Decoder Controller 128 RAM ALU To External Memory Bus 微控制器 • Intel 8051 可综合版本能够获得 • VHDL编写 • 获得RTL级代码register transfer level (RTL) • 从ROM 取指令 • 译码 • ALU 执行算术运算 • 源和目的寄存器放在RAM中 • 通过外部存储器总线,用特殊的数据移动指令从外部存储器输入和存储数据 • ROM有特殊程序产生,可以读取C链接程序的输出,以产生ROM的VHDL描述 Block diagram of Intel 8051 processor core
FSMD description of UART Start: Transmit LOW invoked Idle: I = 0 I < 8 Data: Transmit data(I), then I++ Stop: Transmit HIGH I = 8 UART • UART 处于空闲状态,直到被唤醒 • 当 8051用UART’s 使能寄存器作为目标地址执行存储指令时, UART被唤醒 • 内存映射的通信在8051 和全部单用途处理器之间进行 • 内存地址空间低8-bits地址分给RAM • 内存地址空间高 8-bits分给内存映射的 I/O设备 • 起始状态Start 发送 0表示数据字节发送开始,然后进入 Data 状态 • Data状态串行发送 8 bits ,然后迁移到Stop状态 • Stop state 发送1 表示发送结束,然后回到 idle mode
FSMD description of CCDPP C < 66 GetRow: B[R][C]=Pxl C=C+1 Idle: R=0 C=0 invoked C = 66 R = 64 ComputeBias: Bias=(B[R][11] + B[R][10]) / 2 C=0 R < 64 NextRow: R++ C=0 C < 64 FixBias: B[R][C]=B[R][C]-Bias C = 64 CCDPP • 零偏置操作的硬件实现 • 与外部的 CCD 芯片交互 • 内部缓冲区B, 内存映射到8051 • 变量 R, C缓冲行,列索引 • GetRow 状态从CCD读一行到B • 66 bytes: 64 pixels + 2 blacked-out pixels • ComputeBias 状态计算行、列的偏移,并保存在变量 Bias • FixBias 状态遍历相同行,从每个单元减掉Bias • NextRow 迁移到 GetRow 并重复,当64行完成后转到 Idle state
连接 SOC 组件 • 内存映射 • 所有的单目的处理器核RAM都连接到 8051的 内存总线 • 读 • 处理器在16位地址总线上放置地址; • 确保1个时钟周期的读控制信号; • 1个时钟后从8bit数据总线上读数据 • 外部设备探测到读控制信号 • 检查地址 • 将被请求数据在数据总线上保持1个时钟; • 写 • 处理器在地址和数据总线上放置地址和数据; • 1个时钟周期的写控制信号 • 外部设备探测到写控制信号 • 检查地址总线 • 从数据总线上读入并保存数据。
Original code from system-level model Rewritten UART module #include <stdio.h> static FILE *outputFileHandle; void UartInitialize(const char *outputFileName) { outputFileHandle = fopen(outputFileName, "w"); } void UartSend(char d) { fprintf(outputFileHandle, "%i\n", (int)d); } static unsigned char xdata U_TX_REG _at_ 65535; static unsigned char xdata U_STAT_REG _at_ 65534; void UARTInitialize(void) {} void UARTSend(unsigned char d) { while( U_STAT_REG == 1 ) { /* busy wait */ } U_TX_REG = d; } 软件的修改 • 系统级模型提供核心代码System-level model provides majority of code • 模块层次,程序名字和主程序不需要改变 • UART 和 CCDPP 模块的代码要进行重新设计 • 用内存赋值来代替 • xdata用来在外部内存总线上载入或保存变量 • _at_确定内存地址(端口地址) • 处理器发送字节到 U_TX_REG 将会调用 UART模块 • U_STAT_REG用来指示 UART 已准备好接收下一字节 • UART 会比处理器慢很多 • 类似的修改 CCDPP 代码 • 其它的模块不该变。
VHDL VHDL VHDL Power equation VHDL simulator Synthesis tool Gate level simulator gates gates gates Sum gates Execution time Chip area 分析 • Entire SOC tested on VHDL simulator • Interprets VHDL descriptions and functionally simulates execution of system • Recall program code translated to VHDL description of ROM • Tests for correct functionality • Measures clock cycles to process one image (performance) • Gate-level description obtained through synthesis • Synthesis tool like compiler for SPPs • Simulate gate-level models to obtain data for power analysis • Number of times gates switch from 1 to 0 or 0 to 1 • Count number of gates for chip area Obtaining design metrics of interest Power
实现 2: 微控制器和CCDPP • 实现2的分析 • 一幅图像的总执行时间: • 9.1 seconds • 功耗: • 0.033 watt • 能耗: • 0.30 joule (9.1 s x 0.033 watt) • 总芯片面积: • 98,000 gates
实现 3: 微控制器和CCDPP/Fixed-Point DCT • 9.1 秒仍然不能满足1秒的性能约束 • DCT 操作时间作为主要的改进候选 • 实现2的执行过程显示微控制器的执行DCT操作的时间太长; • 考虑设计专用硬件完成DCT操作 • 更加复杂,需要更多的设计努力 • 同时通过修改行为来加速DCT功能。
DCT 浮点运算的代价 • 浮点运算代价 • 每个象素变换中,DCT 使用~260 浮点操作 • 每个图像有4096 (64 x 64) pixels • 每个图像约执行1 million 浮点操作 • Intel 8051不支持浮点 • 编译器必须仿真浮点运算 • 每个浮点运算都要产生乘加操作 • 使用几十个整数操作 • 因此, 每个图像> 10 million 整数操作 • 增加了代码尺寸 • 浮点算法可以进行改进
固定点算法 • Integer used to represent a real number • Constant number of integer’s bits represents fractional portion of real number • More bits, more accurate the representation • Remaining bits represent portion of real number before decimal point • Translating a real constant to a fixed-point representation • Multiply real value by 2 ^ (# of bits used for fractional part) • Round to nearest integer • E.g., represent 3.14 as 8-bit integer with 4 bits for fraction • 2^4 = 16 • 3.14 x 16 = 50.24 ≈ 50 = 00110010 • 16 (2^4) possible values for fraction, each represents 0.0625 (1/16) • Last 4 bits (0010) = 2 • 2 x 0.0625 = 0.125 • 3(0011) + 0.125 = 3.125 ≈ 3.14 (more bits for fraction would increase accuracy)
固定点算法操作 • Addition • Simply add integer representations • E.g., 3.14 + 2.71 = 5.85 • 3.14 → 50 = 00110010 • 2.71 → 43 = 00101011 • 50 + 43 = 93 = 01011101 • 5(0101) + 13(1101) x 0.0625 = 5.8125 ≈ 5.85 • Multiply • Multiply integer representations • Shift result right by # of bits in fractional part • E.g., 3.14 * 2.71 = 8.5094 • 50 * 43 = 2150 = 100001100110 • >> 4 = 10000110 • 8(1000) + 6(0110) x 0.0625 = 8.375 ≈ 8.5094 • Range of real values used limited by bit widths of possible resulting values
实现CODEC的固定点运算 static const char code COS_TABLE[8][8] = { { 64, 62, 59, 53, 45, 35, 24, 12 }, { 64, 53, 24, -12, -45, -62, -59, -35 }, { 64, 35, -24, -62, -45, 12, 59, 53 }, { 64, 12, -59, -35, 45, 53, -24, -62 }, { 64, -12, -59, 35, 45, -53, -24, 62 }, { 64, -35, -24, 62, -45, -12, 59, -53 }, { 64, -53, 24, 12, -45, 62, -59, 35 }, { 64, -62, 59, -53, 45, -35, 24, -12 } }; • COS_TABLE gives 8-bit fixed-point representation of cosine values • 6 bits used for fractional portion • Result of multiplications shifted right by 6 static const char ONE_OVER_SQRT_TWO = 5; static short xdata inBuffer[8][8], outBuffer[8][8], idx; void CodecInitialize(void) { idx = 0; } static unsigned char C(int h) { return h ? 64 : ONE_OVER_SQRT_TWO;} static int F(int u, int v, short img[8][8]) { long s[8], r = 0; unsigned char x, j; for(x=0; x<8; x++) { s[x] = 0; for(j=0; j<8; j++) s[x] += (img[x][j] * COS_TABLE[j][v] ) >> 6; } for(x=0; x<8; x++) r += (s[x] * COS_TABLE[x][u]) >> 6; return (short)((((r * (((16*C(u)) >> 6) *C(v)) >> 6)) >> 6) >> 6); } void CodecPushPixel(short p) { if( idx == 64 ) idx = 0; inBuffer[idx / 8][idx % 8] = p << 6; idx++; } void CodecDoFdct(void) { unsigned short x, y; for(x=0; x<8; x++) for(y=0; y<8; y++) outBuffer[x][y] = F(x, y, inBuffer); idx = 0; }
实现 3: 微控制器和CCDPP/固定点DCT • 实现3的分析 • 使用类似实现2中的分析技术 • 一幅图像的总执行时间: • 1.5 seconds • 功耗: • 0.033 watt (same as 2) • 能耗: • 0.050 joule (1.5 s x 0.033 watt) • Battery life 6x longer!! • 总芯片面积: • 90,000 gates • 8,000 less gates (less memory needed for code)
EEPROM RAM 8051 CODEC UART CCDPP SOC 实现 4: 微控制器和 CCDPP/DCT • 性能还不够好; • 必须重新用硬件来实现 CODEC • 单目的处理器执行 8 x 8 block的 DCT运算
Rewritten CODEC software static unsigned char xdata C_STAT_REG _at_ 65527; static unsigned char xdata C_CMND_REG _at_ 65528; static unsigned char xdata C_DATAI_REG _at_ 65529; static unsigned char xdata C_DATAO_REG _at_ 65530; void CodecInitialize(void) {} void CodecPushPixel(short p) { C_DATAO_REG = (char)p; } short CodecPopPixel(void) { return ((C_DATAI_REG << 8) | C_DATAI_REG); } void CodecDoFdct(void) { C_CMND_REG = 1; while( C_STAT_REG == 1 ) { /* busy wait */ } } CODEC design • 4 个内存映射寄存器 • C_DATAI_REG/C_DATAO_REG用于 push/pop 8 x 8 block从/到 into and CODEC • C_CMND_REG向 CODEC发送命令 • 写1 调用 CODEC • C_STAT_REG 指示CODEC 已完成并准备下一块图像 • 用软件进行轮询 • 直接将 C code 翻译成HDL硬件实现 • 使用固定点版本 • 软件中的CODEC 模块响应的进行修改。
实现4: 微控制器和 CCDPP/DCT • 实现4的分析 • 单幅图像总执行时间: • 0.099 seconds (well under 1 sec) • 功耗: • 0.040 watt • 能耗: • 0.00040 joule (0.099 s x 0.040 watt) • Battery life 12x longer than previous implementation!! • 总芯片面积: • 128,000 gates • 比前面的实现有显著增加;
小结 • 数码相机实例 • 规范说明用自然语言和可执行语言 • 设计特性:性能,功率和面积 • 几种实现方式 • 微控制器: 太慢! • 微控制器和协处理器:有改进,但还是慢; • 固定点算法:1.5s,几乎能满足要求; • 额外的压缩协处理器:足够快,但是设计难度大 • 软、硬件之间的权衡 –本们课程的主要内容