我这里说的手搓自然是不用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,就按他说,先说写的时序.
- 等外设从繁忙中解除
- 发送START
- 发送地址
- 发送寄存器地址
- 发送要写的内容
比较好评的是,如果遇到锁死,瑞萨并不用取消外设服用,直接可以翻转多个周期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 =====