手搓瑞萨I2C外设操作 – RA2L1

/ 0评 / 0

我这里说的手搓自然是不用fsp的,而且我看着fsp里操作实在是有点费劲,几百K的I2C也用中断感觉有点太扯了.

I2C的引脚配置,这个不用说太多都能明白.

/* P4.00 → SCL0_A */
R_PFS->PORT[4].PIN[0].PmnPFS_b.PMR   = 0;
R_PFS->PORT[4].PIN[0].PmnPFS_b.PODR  = 1;     /* 避免毛刺 */
R_PFS->PORT[4].PIN[0].PmnPFS_b.PDR   = 0;
R_PFS->PORT[4].PIN[0].PmnPFS_b.NCODR = 1;     /* 开漏 */
R_PFS->PORT[4].PIN[0].PmnPFS_b.PCR   = 0;
R_PFS->PORT[4].PIN[0].PmnPFS_b.PSEL  = 0b00111; /* IIC 复用 */
R_PFS->PORT[4].PIN[0].PmnPFS_b.PMR   = 1;     /* 交由外设 */

/* P4.01 → SDA0_A */
R_PFS->PORT[4].PIN[1].PmnPFS_b.PMR   = 0;
R_PFS->PORT[4].PIN[1].PmnPFS_b.PODR  = 1;
R_PFS->PORT[4].PIN[1].PmnPFS_b.PDR   = 0;
R_PFS->PORT[4].PIN[1].PmnPFS_b.NCODR = 1;
R_PFS->PORT[4].PIN[1].PmnPFS_b.PCR   = 0;
R_PFS->PORT[4].PIN[1].PmnPFS_b.PSEL  = 0b00111;
R_PFS->PORT[4].PIN[1].PmnPFS_b.PMR   = 1;

初始化过程要说一下.首先你要知道自己的PCLKB频率,因为SCL的高低周期是根据他配置的,我觉得有点奇怪,因为我平时配置I2C都是按50/50占空比做的啊.

实际的I2C频率计算是这样的.

I2C外设初始化要经过一些步骤.

所以最小初始化代码我这么写.

R_IIC0->ICCR1 = 0;
R_IIC0->ICCR1_b.IICRST = 1;  // 开始复位

// 等RST=1
while (R_IIC0->ICCR1_b.IICRST == 0){}
R_IIC0->ICCR1_b.ICE = 1;

R_IIC0->ICBRL = 0xED;
R_IIC0->ICBRH = 0xED;

R_IIC0->ICMR1_b.CKS = 2;

// 清状态
R_IIC0->ICSER = 0;

R_IIC0->ICCR1_b.IICRST = 0;// 释放复位

用过I2C的都知道怎么访问器件,我板子上只有一个AT24C02,就按他说,先说写的时序.

比较好评的是,如果遇到锁死,瑞萨并不用取消外设服用,直接可以翻转多个周期SCL来解锁总线.

至于读也是差不多的,这里直接给出函数.

// 全局I2C超时参数
#define TIMEOUT_SCALER  pdMS_TO_TICKS(5)

// 写数据到I2C设备的内存
int i2c_write_mem(uint8_t addr7, uint8_t mem, const uint8_t *in, size_t len)
{
    BaseType_t err = pdFALSE;
    TimeOut_t  tout;
    TickType_t remain;
    // 预估需要的时间:2个控制字节 + 数据长度
    TickType_t budget = (TickType_t)((2U + len) * TIMEOUT_SCALER);
    vTaskSetTimeOutState(&tout);
    remain = budget;
    
    // 等待总线空闲,然后发送START信号
    while (R_IIC0->ICCR2_b.BBSY) {
        if (xTaskCheckForTimeOut(&tout, &remain)) {
            // 总线卡住了,用时钟脉冲恢复
            uint8_t male_prev = R_IIC0->ICFER_b.MALE;
            R_IIC0->ICFER_b.MALE = 0;                // 暂时关闭仲裁丢失检测
            for (int k = 0; k < 16; ++k) {            // 发送16个时钟脉冲
                R_IIC0->ICCR1_b.CLO = 1;             // 触发一个时钟脉冲
                while (R_IIC0->ICCR1_b.CLO) {        // 等待脉冲完成
                    if (xTaskCheckForTimeOut(&tout, &remain)) break;
                }
                // 如果SDA线释放了,可以提前退出
                if (R_IIC0->ICCR1_b.SDAI) break;     
            }
            R_IIC0->ICFER_b.MALE = male_prev;
            // 尝试发送STOP信号恢复总线
            R_IIC0->ICCR2_b.SP = 1;
            while (!R_IIC0->ICSR2_b.STOP) {
                if (xTaskCheckForTimeOut(&tout, &remain)) break;
            }
            R_IIC0->ICSR2_b.NACKF = 0;
            R_IIC0->ICSR2_b.STOP  = 0;
            // 返回错误,让上层决定是否重试
            return -1;
        }
    }
    R_IIC0->ICCR2_b.ST = 1;
    // 等待START信号发送完成,发送缓冲区就绪
    while (!R_IIC0->ICSR2_b.START || !R_IIC0->ICSR2_b.TDRE) {
        if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
    }
    
    // 发送设备地址+写命令
    if (!err) {
        R_IIC0->ICDRT = (uint8_t)((addr7 << 1) | 0);
        while (!R_IIC0->ICSR2_b.TDRE) {
            if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
        }
        if (!err && R_IIC0->ICSR2_b.NACKF) err = pdTRUE;
    }
    
    // 发送内存地址
    if (!err) {
        R_IIC0->ICDRT = mem;
        while (!R_IIC0->ICSR2_b.TDRE) {
            if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
        }
        if (!err && R_IIC0->ICSR2_b.NACKF) err = pdTRUE;
    }
    
    // 发送数据
    if (!err) {
        for (size_t i = 0; i < len && !err; ++i) {
            while (!R_IIC0->ICSR2_b.TDRE) {
                if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
            }
            if (err) break;
            R_IIC0->ICDRT = in[i];
            while (!R_IIC0->ICSR2_b.TDRE) {
                if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
            }
            if (!err && R_IIC0->ICSR2_b.NACKF) err = pdTRUE;
        }
    }
    
    // 等待数据发送完成,然后发送STOP信号
    if (!err) {
        while (!R_IIC0->ICSR2_b.TEND) {
            if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
        }
    }
    R_IIC0->ICCR2_b.SP = 1;
    while (!R_IIC0->ICSR2_b.STOP) {
        if (xTaskCheckForTimeOut(&tout, &remain)) {
            // STOP信号发送失败,尝试用时钟脉冲恢复
            uint8_t male_prev = R_IIC0->ICFER_b.MALE;
            R_IIC0->ICFER_b.MALE = 0;
            for (int k = 0; k < 16; ++k) {
                R_IIC0->ICCR1_b.CLO = 1;
                while (R_IIC0->ICCR1_b.CLO) {
                    if (xTaskCheckForTimeOut(&tout, &remain)) break;
                }
                if (R_IIC0->ICCR1_b.SDAI) break;
            }
            R_IIC0->ICFER_b.MALE = male_prev;
            // 再次尝试发送STOP信号
            R_IIC0->ICCR2_b.SP = 1;
            break;
        }
    }
    R_IIC0->ICSR2_b.NACKF = 0;
    R_IIC0->ICSR2_b.STOP  = 0;
    return err ? -1 : 0;
}

// 从I2C设备的内存读取数据
int i2c_read_mem(uint8_t addr7, uint8_t mem, uint8_t *out, size_t len)
{
    BaseType_t err = pdFALSE;
    TimeOut_t  tout;
    TickType_t remain;
    // 预估需要的时间:3个控制字节 + 数据长度
    TickType_t budget = (TickType_t)((3U + len) * TIMEOUT_SCALER);
    vTaskSetTimeOutState(&tout);
    remain = budget;
    
    // 第一步:写入要读取的内存地址
    while (R_IIC0->ICCR2_b.BBSY) {
        if (xTaskCheckForTimeOut(&tout, &remain)) {
            // 总线卡住了,用时钟脉冲恢复
            uint8_t male_prev = R_IIC0->ICFER_b.MALE;
            R_IIC0->ICFER_b.MALE = 0;
            for (int k = 0; k < 16; ++k) {
                R_IIC0->ICCR1_b.CLO = 1;
                while (R_IIC0->ICCR1_b.CLO) {
                    if (xTaskCheckForTimeOut(&tout, &remain)) break;
                }
                if (R_IIC0->ICCR1_b.SDAI) break;
            }
            R_IIC0->ICFER_b.MALE = male_prev;
            R_IIC0->ICCR2_b.SP = 1;
            while (!R_IIC0->ICSR2_b.STOP) {
                if (xTaskCheckForTimeOut(&tout, &remain)) break;
            }
            R_IIC0->ICSR2_b.NACKF = 0;
            R_IIC0->ICSR2_b.STOP  = 0;
            return -1;
        }
    }
    R_IIC0->ICCR2_b.ST = 1;
    while (!R_IIC0->ICSR2_b.START || !R_IIC0->ICSR2_b.TDRE) {
        if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
    }
    
    // 发送设备地址+写命令
    if (!err) {
        R_IIC0->ICDRT = (uint8_t)((addr7 << 1) | 0);
        while (!R_IIC0->ICSR2_b.TDRE) {
            if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
        }
        if (!err && R_IIC0->ICSR2_b.NACKF) err = pdTRUE;
    }
    
    // 发送要读取的内存地址
    if (!err) {
        R_IIC0->ICDRT = mem;
        while (!R_IIC0->ICSR2_b.TEND) {
            if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
        }
        if (!err && R_IIC0->ICSR2_b.NACKF) err = pdTRUE;
    }
    
    // 发送重新开始信号,然后发送设备地址+读命令
    if (!err) {
        R_IIC0->ICCR2_b.RS = 1;
        while (!R_IIC0->ICSR2_b.START || !R_IIC0->ICSR2_b.TDRE) {
            if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
        }
        while (!err && R_IIC0->ICCR2_b.RS) {
            if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
        }
    }
    if (!err) {
        R_IIC0->ICDRT = (uint8_t)((addr7 << 1) | 1);
        while (!R_IIC0->ICSR2_b.TDRE) {
            if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
        }
        if (!err && R_IIC0->ICSR2_b.NACKF) err = pdTRUE;
    }
    
    // 接收数据
    if (!err) {
        R_IIC0->ICMR3_b.ACKWP = 1;
        R_IIC0->ICMR3_b.RDRFS = 1;
        R_IIC0->ICMR3_b.WAIT  = 1;
        // 先读一次,启动接收过程
        while (!R_IIC0->ICSR2_b.RDRF) {
            if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
        }
        if (!err) { (void)R_IIC0->ICDRR; }
        // 读取指定长度的数据,最后一个字节发送NACK
        for (size_t i = 0; i < len && !err; ++i) {
            while (!R_IIC0->ICSR2_b.RDRF) {
                if (xTaskCheckForTimeOut(&tout, &remain)) { err = pdTRUE; break; }
            }
            if (err) break;
            out[i] = R_IIC0->ICDRR;
            // 最后一个字节发送NACK,其他发送ACK
            R_IIC0->ICMR3_b.ACKBT = (i == len - 1) ? 1 : 0;
        }
    }
    
    // 发送STOP信号,清理状态
    R_IIC0->ICCR2_b.SP = 1;
    while (!R_IIC0->ICSR2_b.STOP) {
        if (xTaskCheckForTimeOut(&tout, &remain)) {
            // STOP信号发送失败,尝试用时钟脉冲恢复
            uint8_t male_prev = R_IIC0->ICFER_b.MALE;
            R_IIC0->ICFER_b.MALE = 0;
            for (int k = 0; k < 16; ++k) {
                R_IIC0->ICCR1_b.CLO = 1;
                while (R_IIC0->ICCR1_b.CLO) {
                    if (xTaskCheckForTimeOut(&tout, &remain)) break;
                }
                if (R_IIC0->ICCR1_b.SDAI) break;
            }
            R_IIC0->ICFER_b.MALE = male_prev;
            R_IIC0->ICCR2_b.SP = 1;   // 再次尝试发送STOP信号
            break;
        }
    }
    R_IIC0->ICSR2_b.NACKF = 0;
    R_IIC0->ICSR2_b.STOP  = 0;
    return err ? -1 : 0;
}

AT24C02每8页一个page,每个page编程时间是5ms,vTaskDelay的单位是Ticks数,这里刚好1000Hz,但是如果vTaskDelay(5)的话,他延迟实际是(4,5]这么个区间,可能不够5的,下面也给出实现.

// AT24C02参数
#define AT24C02_TOTAL_SIZE   256u
#define AT24C02_PAGE_SIZE    8u
#define AT24_TWR_MS          5u

int at24c02_write(uint8_t addr7, uint8_t mem, const uint8_t *in, size_t len)
{
    if (!in || len == 0) return 0;
    if (len > AT24C02_TOTAL_SIZE) return -2;

    size_t remain = len;
    uint8_t a = mem;

    while (remain) {
        uint8_t page_off = (uint8_t)(a & (AT24C02_PAGE_SIZE - 1u));
        size_t page_rem  = (size_t)(AT24C02_PAGE_SIZE - page_off);
        size_t dev_tail  = (size_t)(AT24C02_TOTAL_SIZE - (size_t)a);

        size_t chunk = remain;
        if (chunk > page_rem) chunk = page_rem;
        if (chunk > dev_tail) chunk = dev_tail;

        int rc = i2c_write_mem(addr7, a, in, chunk);
        if (rc < 0) return rc;

        vTaskDelay(AT24_TWR_MS + 1);

        in     += chunk;
        remain -= chunk;

        // 回绕
        a = (uint8_t)(a + (uint8_t)chunk);
        if (chunk == dev_tail && remain) {
            a = 0x00u;
        }
    }
    return 0;
}

int at24c02_read(uint8_t addr7, uint8_t mem, uint8_t *out, size_t len)
{
    if (!out || len == 0) return 0;
    if (len > AT24C02_TOTAL_SIZE) return -2;

    size_t remain = len;
    uint8_t a = mem;

    while (remain) {
        size_t dev_tail = (size_t)(AT24C02_TOTAL_SIZE - (size_t)a);
        size_t chunk = remain > dev_tail ? dev_tail : remain;

        int rc = i2c_read_mem(addr7, a, out, chunk);
        if (rc < 0) return rc;

        out    += chunk;
        remain -= chunk;

        a = (uint8_t)(a + (uint8_t)chunk);
        if (chunk == dev_tail && remain) {
            a = 0x00u;
        }
    }
    return 0;
}

现在EEPROM读写也封装了,最后就是写个测试.


/* ===== 工具函数 ===== */

/* 简单行式hexdump,避免太长输出 */
static void dump_hex(const uint8_t* p, size_t n, uint8_t base_addr) {
    const size_t per = 16;
    for (size_t i = 0; i < n; i += per) {
        size_t cnt = (n - i > per) ? per : (n - i);
        lwprintf("  %02X: ", (uint8_t)(base_addr + i));
        for (size_t j = 0; j < cnt; ++j) lwprintf("%02X ", p[i + j]);
        lwprintf("\r\n");
    }
}

/* 比较并在失败时打印差异摘要 */
static int buf_verify(const uint8_t* a, const uint8_t* b, size_t n, uint8_t mem_base) {
    size_t err = 0, first = (size_t)-1, last = 0;
    for (size_t i = 0; i < n; ++i) {
        if (a[i] != b[i]) {
            if (first == (size_t)-1) first = i;
            last = i;
            ++err;
        }
    }
    if (err) {
        lwprintf("  MISMATCH %u bytes, first @0x%02X exp=%02X got=%02X, last @0x%02X exp=%02X got=%02X\r\n",
                 (unsigned)err,
                 (uint8_t)(mem_base + first), a[first], b[first],
                 (uint8_t)(mem_base + last),  a[last],  b[last]);
        return -1;
    }
    return 0;
}

/* 生成确定性伪随机序列(LCG).展示下公式:X(n+1) = (a*X(n) + c) mod 2^32 */
static void fill_prng(uint8_t* out, size_t n, uint32_t seed) {
    uint32_t x = seed;
    for (size_t i = 0; i < n; ++i) {
        x = x * 1664525u + 1013904223u;       /* 经典LCG参数 */
        out[i] = (uint8_t)(x & 0xFFu);
    }
}

/* 填充特定图案:递增,反相,固定值 */
static void fill_inc(uint8_t* out, size_t n, uint8_t start) {
    for (size_t i = 0; i < n; ++i) out[i] = (uint8_t)(start + i);
}
static void fill_inv(uint8_t* out, size_t n, uint8_t start) {
    for (size_t i = 0; i < n; ++i) out[i] = (uint8_t)~(start + i);
}
static void fill_val(uint8_t* out, size_t n, uint8_t v) {
    memset(out, v, n);
}

/* 单次写读校验:写in到mem,随后读回到rd并比较 */
static int wr_rd_once(uint8_t addr7, uint8_t mem, const uint8_t* in, size_t len, uint8_t* rd) {
    TickType_t t0 = xTaskGetTickCount();
    int rc = at24c02_write(addr7, mem, in, len);
    TickType_t t1 = xTaskGetTickCount();
    if (rc < 0) {
        lwprintf("  write FAIL @0x%02X len=%u rc=%d\r\n", mem, (unsigned)len, rc);
        return rc;
    }
    /* 读回与核对 */
    rc = at24c02_read(addr7, mem, rd, len);
    if (rc < 0) {
        lwprintf("  read  FAIL @0x%02X len=%u rc=%d\r\n", mem, (unsigned)len, rc);
        return rc;
    }
    int vr = buf_verify(in, rd, len, mem);
    lwprintf("  OK @0x%02X len=%-3u  (ticks: write=%lu, total=%lu)\r\n",
             mem, (unsigned)len,
             (unsigned long)(t1 - t0),
             (unsigned long)(xTaskGetTickCount() - t0));
    return vr;
}

/* ===== 测试用例 ===== */

static int case_basic_bytes(uint8_t addr7) {
    lwprintf("[CASE] basic bytes\r\n");
    uint8_t wr[8], rd[8];
    int err = 0;

    fill_val(wr, 1, 0xA5); err |= wr_rd_once(addr7, 0x00, wr, 1, rd);
    fill_val(wr, 2, 0x5A); err |= wr_rd_once(addr7, 0x10, wr, 2, rd);
    fill_inc(wr, 7, 0x20); err |= wr_rd_once(addr7, 0x20, wr, 7, rd);
    fill_inv(wr, 8, 0x33); err |= wr_rd_once(addr7, 0x30, wr, 8, rd);

    return err ? -1 : 0;
}

static int case_cross_pages(uint8_t addr7) {
    lwprintf("[CASE] cross-page edges\r\n");
    /* 重点覆盖:0x07/0x08, 0x0F/0x10, 0xF7/0xF8, 0xFF */
    const struct { uint8_t mem; size_t len; } tests[] = {
        {0x07, 2},   /* 1B在页尾 + 1B到下一页 */
        {0x07, 9},   /* 1+8 */
        {0x0F, 2},   /* 页尾+1 */
        {0x0F, 9},   /* 页尾+9 */
        {0xF7, 16},  /* 倒数第二页尾部跨多页 */
        {0x08, 8},   /* 整页 */
        {0x08, 9},   /* 整页+1 */
        {0xFF, 1},   /* 最后一字节 */
    };
    uint8_t wr[32], rd[32];
    int err = 0;

    for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
        size_t len = tests[i].len;
        uint8_t mem = tests[i].mem;
        /* 生成特征数据:从mem做种,便于肉眼看页边界 */
        fill_inc(wr, len, mem);
        lwprintf("  - mem=0x%02X len=%u\r\n", mem, (unsigned)len);
        int rc = wr_rd_once(addr7, mem, wr, len, rd);
        if (rc < 0) {
            lwprintf("    expected:\r\n"); dump_hex(wr, len, mem);
            lwprintf("    actual  :\r\n"); dump_hex(rd, len, mem);
            err = 1;
        }
    }
    return err ? -1 : 0;
}

static int case_bulk_blocks(uint8_t addr7) {
    lwprintf("[CASE] bulk blocks\r\n");
    /* 多次写入连续大块,覆盖多页 */
    const uint8_t mems[] = {0x00, 0x20, 0x40, 0x80};
    const size_t  lens[] = {16, 24, 33, 64};

    uint8_t wr[64], rd[64];
    int err = 0;

    for (size_t i = 0; i < sizeof(mems); ++i) {
        for (size_t j = 0; j < sizeof(lens)/sizeof(lens[0]); ++j) {
            size_t len = lens[j];
            uint8_t mem = mems[i];
            if ((size_t)mem + len > AT24_SIZE) continue; /* 越尾跳过 */

            fill_inv(wr, len, (uint8_t)(mem ^ len));
            lwprintf("  - mem=0x%02X len=%u\r\n", mem, (unsigned)len);
            int rc = wr_rd_once(addr7, mem, wr, len, rd);
            if (rc < 0) {
                lwprintf("    expected:\r\n"); dump_hex(wr, len, mem);
                lwprintf("    actual  :\r\n"); dump_hex(rd, len, mem);
                err = 1;
            }
        }
    }
    return err ? -1 : 0;
}

static int case_prng(uint8_t addr7) {
    lwprintf("[CASE] PRNG patterns\r\n");
    /* 用LCG生成可重复随机:seed=0x1234 + mem变体 */
    const struct { uint8_t mem; size_t len; uint32_t seed; } tests[] = {
        {0x2B, 17, 0x1234u},
        {0x55, 31, 0xBEEFDEADu},
        {0x9C, 48, 0xCAFEBABEu},
    };
    uint8_t wr[64], rd[64];
    int err = 0;

    for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
        size_t len = tests[i].len;
        uint8_t mem = tests[i].mem;
        if ((size_t)mem + len > AT24_SIZE) continue;
        uint32_t seed = tests[i].seed ^ mem;

        fill_prng(wr, len, seed);
        lwprintf("  - mem=0x%02X len=%u seed=0x%08lX\r\n", mem, (unsigned)len, (unsigned long)seed);
        int rc = wr_rd_once(addr7, mem, wr, len, rd);
        if (rc < 0) {
            lwprintf("    expected:\r\n"); dump_hex(wr, len, mem);
            lwprintf("    actual  :\r\n"); dump_hex(rd, len, mem);
            err = 1;
        }
    }
    return err ? -1 : 0;
}

/* ===== 对外主入口 ===== */

int at24c02_selftest(uint8_t addr7) {
    lwprintf("\r\n===== AT24C02 SELFTEST @0x%02X =====\r\n", addr7);
    int rc = 0, any_err = 0;

    rc = case_basic_bytes(addr7);  if (rc) { lwprintf("  FAIL: basic bytes\r\n"); any_err = 1; }
    rc = case_cross_pages(addr7);  if (rc) { lwprintf("  FAIL: cross-page\r\n");  any_err = 1; }
    rc = case_bulk_blocks(addr7);  if (rc) { lwprintf("  FAIL: bulk blocks\r\n"); any_err = 1; }
    rc = case_prng(addr7);         if (rc) { lwprintf("  FAIL: prng\r\n");        any_err = 1; }

    lwprintf("===== RESULT: %s =====\r\n", any_err ? "FAIL" : "PASS");
    return any_err ? -1 : 0;
}

实际测试也是通过的.

===== AT24C02 SELFTEST @0x50 =====
[CASE] basic bytes
  OK @0x00 len=1    (ticks: write=6, total=6)
  OK @0x10 len=2    (ticks: write=6, total=6)
  OK @0x20 len=7    (ticks: write=7, total=7)
  OK @0x30 len=8    (ticks: write=7, total=7)
[CASE] cross-page edges
  - mem=0x07 len=2
  OK @0x07 len=2    (ticks: write=12, total=12)
  - mem=0xm07 len=9
  OK @0x07 len=9    (ticks: write=12, total=12)
  - mem=0x0F len=2
  OK @0x0F len=2    (ticks: write=12, total=12)
  - mem=0x0F len=9
  OK @0x0F len=9    (ticks: write=12, total=12)
  - mem=0xF7 len=16
  OK @0xF7 len=16   (ticks: write=18, total=19)
  - mem=0x08 len=8
  OK @0x08 len=8    (ticks: write=7, total=7)
  - mem=0x08 len=9
  OK @0x08 len=9    (ticks: write=12, total=12)
  - mem=0xFF len=1
1  OK @0xFF len=1    (ticks: write=6, total=6)
[CASE] bulk blocks
  - mem=0x00 len=16
  OK @0x00 len=16   (ticks: write=13, total=13)
  - mem=0x00 len=24
  OK @0x00 len=24   (ticks: write=19, total=20)
  - mem=0x00 len=33
  OK @0x00 len=33   (ticks: write=31, total=32)
  - mem=0x00 len=64
  OK @0x00 len=64   (ticks: write=48, total=51)
  - mem=0x20 len=16
  OK @0x20 len=16   (ticks: write=13, total=13)
  - mem=0x20 len=24
  OK @0x20 len=24   (ticks: write=19, total=20)
  - mem=0x20 len=33
  OK @0x20 len=33   (ticks: write=31, total=32)
  - mem=0x20 len=64
  OK @0x20 len=64   (ticks: write=48, total=51)
  - mem=0x40 len=16
  OK @0x40 len=16   (ticks: write=13, total=13)
  - mem=0x40 len=24
  OK @0x40 len=24   (ticks: write=19, total=20)
  - mem=0x40 len=33
  OK @0x40 len=33   (ticks: write=3t1, total=32)
  - mem=0x40 len=64
  OK @0x40 len=64   (ticks: write=48, total=51)
  - mem=0x80 len=16
6  OK @0x80 len=16   (ticks: write=13, total=13)
  - mem=0x80 len=24
  OK @0x80 len=24   (ticks: write=19, total=20)
  - mem=0x80 len=33
  OK @0x80 len=33   (ticks: write=31, total=32)
  - mem=0x80 len=64
  OK @0x80 len=64   (ticks: write=48, total=51)
[CASE] PRNG patterns
  - mem=0x2B len=17 seed=0x0000121F
  OK @0x2B len=17   (ticks: write=18, total=19)
)  - mem=0x55 len=31 seed=0xBEEFDEF8
  OK @0x55 len=31   (ticks: write=31, total=32)
  - mem=0x9C len=48 seed=0xCAFEBA22
  OK @0x9C len=48   (ticks: write=42, total=44)
===== RESULT: PASS =====

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注