为SRAM添加校验

产品的SRAM中的数据出现莫名奇妙的乱,碰到过不少。一直未确定是何种原因引起,其中一个原因是由于备用电池没电,电压过低引起的数据丢失,堵住这个原因后,后续仍有零零星星的问题出现,一直未有一个有效的方法可以解决。

       终于忍受不了,准备大动一下程序,给SRAM的数据增加纠错码,如同NAND FLASH的校验,至少可以检测到是否为人为造成的数据紊乱,如果非人为造成数据紊乱,程序会给出提示数据出现了错误。使用的是128K-WORD by 16bit的SRAM。由于SRAM空间比较紧张,所以只就抠出了1K WORD的空间用于放置冗余位(校验码)。

       研究了一下nand flash的ECC校验算法,最终确定按照256word/page将整个SRAM空间分成512个页面,每个页面三个校验字节,所有页面的校验字节加起来大小为1.5KBYTE。方案可行,付诸实施。

       首先,改算法。由于nand flash的ECC算法大都采用256byte/page进行校验,所以根据我们采用的256wrod/page的实际情况,必须要修改算法。对于原ECC校验算法,由于网上有很多,这里就不在赘述,仅贴上我改过的算法代码。

#include "sramecc.h"

static inline int countbits(INT16U byte)
{
int res = 0;


for (;byte; byte >>= 1)
res += byte & 0x01;
return res;
}


static INT32S sram_calculate_ecc(const INT16U *data, INT8U *ecc_code, INT16U ecc_code_num)
{
    INT16U i, idx;
    INT8U  reg1, reg2, reg3, tmp_ecc0, tmp_ecc1;


    reg1 = 0;
    reg2 = 0;
    reg3 = 0;
    tmp_ecc0 = 0;
    tmp_ecc1 = 0;
 
    for (i = 0; i < 256; i++)
    {
        //Get CP0 ~ CP7 from table
        if (i < ecc_code_num)
            idx = ecc_precalc_table[*data++];
        else
            idx = ecc_precalc_table[0];
        
        reg1 ^= (idx & 0xff); 


        //Row bit xor is 1
        if (idx & 0x100)
        {
            reg3 ^= i;
            reg2 ^= ~i;
        }
    }
    //printf("reg2 : %x reg3 : %x\n", reg2, reg3);
    //---------------------------------------------------------
    //|reg2| RP14 | RP12 | RP10 | RP8 | RP6 | RP4 | RP2 | RP0 |
    //|--------------------------------------------------------
    //|reg3| RP15 | RP13 | RP11 | RP9 | RP7 | RP5 | RP3 | RP1 |
    //---------------------------------------------------------


    //adjust 
    tmp_ecc1 |= (reg3 & 0x80) >> 0;  // RP15
    tmp_ecc1 |= (reg2 & 0x80) >> 1;  // RP14
    tmp_ecc1 |= (reg3 & 0x40) >> 1;  // RP13
    tmp_ecc1 |= (reg2 & 0x40) >> 2;  // RP12
    tmp_ecc1 |= (reg3 & 0x20) >> 2;  // RP11
    tmp_ecc1 |= (reg2 & 0x20) >> 3;  // RP10
    tmp_ecc1 |= (reg3 & 0x10) >> 3;  // RP9
    tmp_ecc1 |= (reg2 & 0x10) >> 4;  // RP8


    tmp_ecc0 |= (reg3 & 0x08) << 4;  // RP7
    tmp_ecc0 |= (reg2 & 0x08) << 3;  // RP6
    tmp_ecc0 |= (reg3 & 0x04) << 3;  // RP5
    tmp_ecc0 |= (reg2 & 0x04) << 2;  // RP4
    tmp_ecc0 |= (reg3 & 0x02) << 2;  // RP3
    tmp_ecc0 |= (reg2 & 0x02) << 1;  // RP2
    tmp_ecc0 |= (reg3 & 0x01) << 1;  // RP1
    tmp_ecc0 |= (reg3 & 0x01) << 0;  // RP0


    ecc_code[0] = tmp_ecc0;
    ecc_code[1] = tmp_ecc1;
    ecc_code[2] = reg1;
    //printf("tmp_ecc0 : %x %x %x\n", tmp_ecc0, tmp_ecc1, reg1);
    return 0;
}


static INT32S sram_correct_data(INT16U *data, INT8U *read_ecc, INT8U *calc_ecc)
{
    INT8U s0, s1, s2;

    s0 = calc_ecc[0] ^ read_ecc[0];
    s1 = calc_ecc[1] ^ read_ecc[1];
    s2 = calc_ecc[2] ^ read_ecc[2];
#ifdef ECC_DEBUG       
    //printf("sram_correct_data!\n");
    //printf("calc_ecc : 0x%x 0x%x 0x%x\n", calc_ecc[0], calc_ecc[1], calc_ecc[2]);
    //printf("read_ecc : 0x%x 0x%x 0x%x\n", read_ecc[0], read_ecc[1], read_ecc[2]);
    printf(" %2x %2x %2x,  ", s0, s1, s2);
#endif
    if ((s0 | s1 | s2) == 0)
    {
        return 0;
    }


    if (((s0 ^ (s0 >> 1)) & 0x55) == 0x54 &&
   ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
   ((s2 ^ (s2 >> 1)) & 0x55) == 0x55)
    {
        INT32U byteoffs = 0, bitnum = 0;
byteoffs |= (s1 << 0) & 0x80;  //RP15
byteoffs |= (s1 << 1) & 0x40;  //RP13
byteoffs |= (s1 << 2) & 0x20;  //RP11
byteoffs |= (s1 << 3) & 0x10;  //RP9


byteoffs |= (s0 >> 4) & 0x08;  //RP7
byteoffs |= (s0 >> 3) & 0x04;  //RP5
byteoffs |= (s0 >> 2) & 0x02;  //RP3
byteoffs |= (s0 >> 1) & 0x01;  //RP1


        //The value of bitnum is the bit which error
        bitnum   |= (s2 >> 4) & 0x08;
        bitnum   |= (s2 >> 3) & 0x04;
        bitnum   |= (s2 >> 2) & 0x02;
        bitnum   |= (s2 >> 1) & 0x01;


        //correct data
        data[byteoffs] ^= (1 << bitnum);
        
#ifdef ECC_DEBUG   
        printf("data[%2x] = %4x %x,  ", byteoffs, data[byteoffs], bitnum);
#endif
        return 1;
    }
    else if (countbits(s0 | ((INT16U)s1 << 8) | ((INT16U)s2 <<16)) == 1)
    {
        return 1;
    }
    else
    {
        printf("page : %d\n", (data - pVirtualAddress) / 256);
        printf("calc_ecc : 0x%x 0x%x 0x%x\n", calc_ecc[0], calc_ecc[1], calc_ecc[2]);
        printf("read_ecc : 0x%x 0x%x 0x%x\n", read_ecc[0], read_ecc[1], read_ecc[2]);
        return 2;
    }
}

    与256byte/page的算法相比,改动的地方并不多,不过说实话,就这仅有不多的改动,花费了我整整一天的时间,不全面弄清楚原算法不敢动刀啊~  sramecc.h存放了ecc_precalc_table,该表式预先计算好的65536个校验码,其中低8位为列校验位,第8位为行校验位,数据很多,知晓算法就可以生成,这里便不列出了,下面是其生成算法的代码:

#define     BIT0(X)     (((X) & 0X0001) >> 0)
#define     BIT1(x)     (((x) & 0x0002) >> 1)
#define     BIT2(x)     (((x) & 0x0004) >> 2)
#define     BIT3(x)     (((x) & 0x0008) >> 3)
#define     BIT4(x)     (((x) & 0x0010) >> 4)
#define     BIT5(x)     (((x) & 0x0020) >> 5)
#define     BIT6(x)     (((x) & 0x0040) >> 6)
#define     BIT7(x)     (((x) & 0x0080) >> 7)
#define     BIT8(x)     (((x) & 0x0100) >> 8)
#define     BIT9(x)     (((x) & 0x0200) >> 9)
#define     BIT10(x)    (((x) & 0x0400) >> 10)
#define     BIT11(x)    (((x) & 0x0800) >> 11)
#define     BIT12(x)    (((x) & 0x1000) >> 12)
#define     BIT13(x)    (((x) & 0x2000) >> 13)
#define     BIT14(x)    (((x) & 0x4000) >> 14)
#define     BIT15(x)    (((x) & 0x8000) >> 15)

#include <stdio.h>

int main(void)
{
int i, j = 0;
unsigned short xByte;
for (i = 0; i < 65536; i++)
{
xByte = 0;
if (BIT0(i) ^ BIT2(i) ^ BIT4(i) ^ BIT6(i) ^ BIT8(i) ^ BIT10(i) ^ BIT12(i) ^ BIT14(i))
xByte |= 0x0001;
if (BIT1(i) ^ BIT3(i) ^ BIT5(i) ^ BIT7(i) ^ BIT9(i) ^ BIT11(i) ^ BIT13(i) ^ BIT15(i))  
xByte |= 0x0002;
 if (BIT0(i) ^ BIT1(i) ^ BIT4(i) ^ BIT5(i) ^ BIT8(i) ^ BIT9(i) ^ BIT12(i) ^ BIT13(i))
  xByte |= 0x0004;
 if (BIT2(i) ^ BIT3(i) ^ BIT6(i) ^ BIT7(i) ^ BIT10(i) ^ BIT11(i) ^ BIT14(i) ^ BIT15(i))
  xByte |= 0x0008;
 
 if (BIT0(i) ^ BIT1(i) ^ BIT2(i) ^ BIT3(i) ^ BIT8(i) ^ BIT9(i) ^ BIT10(i) ^ BIT11(i))
  xByte |= 0x0010;
 if (BIT4(i) ^ BIT5(i) ^ BIT6(i) ^ BIT7(i) ^ BIT12(i) ^ BIT13(i) ^ BIT14(i) ^ BIT15(i))
  xByte |= 0x0020;
 if (BIT0(i) ^ BIT1(i) ^ BIT2(i) ^ BIT3(i) ^ BIT4(i) ^ BIT5(i) ^ BIT6(i) ^ BIT7(i))
  xByte |= 0x0040;
 if (BIT8(i) ^ BIT9(i) ^ BIT10(i) ^ BIT11(i) ^ BIT12(i) ^ BIT13(i) ^ BIT14(i) ^ BIT15(i))
  xByte |= 0x0080;
 
 if (BIT0(i) ^ BIT1(i) ^ BIT2(i) ^ BIT3(i) ^ BIT4(i) ^ BIT5(i) ^ BIT6(i) ^ BIT7(i) ^ BIT8(i) ^ BIT9(i) ^ BIT10(i) ^ BIT11(i) ^ BIT12(i) ^ BIT13(i) ^ BIT14(i) ^ BIT15(i))
  xByte |= 0x0100;
 
 if (j == 31)
 {
  printf("0x%03x,\n", xByte);
  j = 0;
 }
 else
 {
  printf("0x%03x, ", xByte);
  j++;
 }
 
}
return 0;
}

    到此为止,算法工作已经完成。只需要在需要的地方调用相关函数就可以了。

    其次,改接口。这一步又分为两小步,①写接口代码。须将上面的算法函数嵌入到接口代码里,并实现每个页面的ECC码的存取位置的算法。如果是多线程的,那么还需要对每个页面都要加上互斥锁。②统一系统中的接口。将系统中对SRAM的操作统一接口,根据实际情况这一步是最麻烦的,因为你要找到原系统中所有的读写操作,将其改为统一的接口,而且还不能带来新的问题。因为此步因系统而已,所以也没什么说的了,改好不要带来新的问题就可以了。

   最后全面调试代码,按照新代码的待遇测试它,确保无问题。

• 重点内容 – 64KB 专用 RAM – 275-MHz, 500-MHz, 600-MHz, or 720-MHz – 仿真/调试 ARM® Cortex™-A8 32-位RISC 微控制器• JTAG • NEON™ SIMD 协处理器• 嵌入式跟踪模块 • 具有单错检测(奇偶校验)的32KB/32KB • 嵌入式跟踪缓冲器 L1 指令/数据高速缓存– 断控制器(高达128 个断请求) • 具有错误纠正码(ECC) 的256KB L2 高速缓• 片载存储器(共享L3 RAM) 存– 64 KB 通用片载存储器控制器(OCMC) RAM – 支持移动双倍速率同步动态随机存储器– 所有主机均可访问 (mDDR)(低功耗DDR (LPDDR))/DDR2/DDR3 – 支持快速唤醒保持 – 支持通用存储器(NAND,NOR,SRAM,等)支• 外部存储器接口(EMIF) 持高达16 位ECC – mDDR/DDR2/DDR3 控制器: – SGX530 3D 图形引擎 • mDDR: 200-MHz 时钟频率(400-MHz 数据速– LCD 控制器 率) – 可编程实时单元和工业用通信子系统(PRU- • DDR2: 266-MHz 时钟(532-MHz 数据速ICSS) 率) – 实时时钟(RTC) • DDR3: 303-MHz 时钟(606-MHz 数据速 – 最多2 个具有集成物理层的USB 2.0 高速OTG 率) 端口• 16-位数据总线 – 支持最多2 个端口的10/100/1000 以太网交换机• 1GB 全部可寻址空间 – 串口包括: • 支持1 x 16 或者2 x 8 存储器器件配置 • 2 个控制器局域网端口(CAN) • 支持快速唤醒保持 • 6 个UART,2 个McASPI,2 个McSPI,和3 个 I2C 端口 – 通用存储器控制器 (GPMC) • 具有多达7 芯片(NAND,NOR,复– 12 位逐次逼近寄存器(SAR) ADC 用NOR,SRAM等) 选择的灵活8/16-位异步 – 3 个32 位增强型捕捉模块(eCAP) 存储器接口 – 3 个增强型高分辨率PWM模块(eHRPWM) • 使用BCH 编码以支持4-位,8-位,或者16- – 加密硬件加速器(AES,SHA,PKA,RNG) 位ECC • 使用海明码(Hamming)以支持1-位ECC • MPU 子系统– 错位定位器模块(ELM) – 275-MHz,500-MHz,600-MHz,或者720-MHz • 与GPMC 联合使用,使用BCH 算法以定位 ARM® Cortex™-A8 32-位RISC 微处理器由校验多项式生成的数据错误的地址 – NEON™ SIMD 协处理器• 基于BCH 算法,每512 字节块错误定位支持 – 具有单错检测(奇偶校验)的32KB L1 指令高4-位,8-位,和16-位 速缓存• 可编程实时单元和工业用通信子系统(PRU-ICSS) – 具有单错检测(奇偶校验)的32KB 数据高速缓– 支持的协议包括 存EtherCAT®,PROFIBUS,PROFINET,Ether – 含纠错码(ECC)的256KB L2 高速缓存Net/IP™,和其它更多协议 – 176KB 片载启动ROM – PRU-ICSS 内的外设 1 Please be aware that an important notice concerning availabi
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值