ajuckler opened a new pull request, #17522:
URL: https://github.com/apache/nuttx/pull/17522
## Summary
In order to reduce code duplication and ease putting functions in common,
use the eeprom/spi_xx25xx driver within mtd/at25ee.
## Impact
* The MTD at25ee driver now interfaces the EEPROM spi_xx25xx driver
internally
* The `eeprom/spi_xx25xx.h` and `eeprom/i2c_xx24xx.h` headers have been
merged into `eeprom/eeprom.h`, to provide a common header file similar to
`mtd/mtd.h`.
* Some error codes have been changed (mainly `EFBIG`/`E2BIG` into `EFAULT`
and `EACCESS`/`EPERM` into `EROFS`)
* The `at25ee_initialize` and `ee25xx_initialize` functions take an enum
instead of an int for their `devtype` parameter
* There is a minor performance degradation (~25 ticks) for read-write
operations. Refer to the [testing section](#speed-performance-validation) for
details
## Testing
Tested on a custom target (STM32F7-based) with a Rhom BR25G256FVT EEPROM
(equivalent to a Microchip 25xx256).
### Functional validation
Test sequence (for the MTD driver):
1. Clear the EEPROM
2. Write the entire chip block-by-block
3. Read the entire chip block-by-block and check that everything has been
written correctly
4. Rewrite blocks \# 2 and \# 3 using the bytewise write function
5. Reread the entire chip using the bytewise read function and check that
everything is correctly written
6. Attempt to write blocks across and after the memory boundaries and
confirm the number of written blocks
7. Attempt to read blocks across and after the memory boundaries and confirm
the number of read blocks
8. Attempt to write bytes across and after the memory boundaries and confirm
the number of written bytes
9. Attempt to read bytes across and after the memory boundaries and confirm
the number of read bytes
10. Erase block \# 2 and \# 3 and confirm that only these blocks has been
erased
The test sequence for the character driver is similar without the checks for
the functions operating on blocks.
<details>
<summary>Sample code</summary>
```c
int at25ee_test_main(int argc, FAR char *argv[])
{
struct mtd_geometry_s geo;
int status = 0;
int ret;
uint32_t nblocks;
uint32_t i;
FAR uint8_t *buffer = NULL;
FAR struct mtd_dev_s *master = at25ee_initialize(g_spi_eep_p, 1,
EEPROM_25XX256, 0);
if (!master)
{
printf("ERROR: Failed to initialize the AT25EE MTD instance\n");
exit(1);
}
/* Erase the entire EEPROM part */
ret = MTD_IOCTL(master, MTDIOC_BULKERASE, 0);
if (ret < 0)
{
printf("ERROR: MTDIOC_BULKERASE ioctl failed: %d\n", ret);
status = 2;
goto cleanup;
}
/* Get the MTD geometry */
ret = MTD_IOCTL(master, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&geo));
if (ret < 0)
{
printf("ERROR: MTDIOC_GEOMETRY ioctl failed: %d\n", ret);
status = 3;
goto cleanup;
}
printf("MTD geometry:\n");
printf(" blocksize: %lu\n", (unsigned long)geo.blocksize);
printf(" erasesize: %lu\n", (unsigned long)geo.erasesize);
printf(" neraseblocks: %lu\n", (unsigned long)geo.neraseblocks);
/* Compute the number of blocks */
nblocks = (geo.erasesize * geo.neraseblocks) / geo.blocksize;
/* Allocate the buffer for writing */
buffer = (FAR uint8_t *)calloc(2 * geo.blocksize, sizeof(uint8_t));
if (!buffer)
{
printf("ERROR: failed to allocate the buffer for writing\n");
status = 4;
goto cleanup;
}
/* Fill each block with its offset */
printf("Writing the device...\n");
for (i = 0; i < nblocks; ++i)
{
ssize_t blockcnt;
memset(buffer, (i % UINT8_MAX), geo.blocksize);
blockcnt = MTD_BWRITE(master, i, 1, buffer);
if (blockcnt != 1)
{
printf("ERROR: failed to write block #%ld: %d\n", i, blockcnt);
status = 5;
goto cleanup;
}
}
/* Read each block and check that it is correctly written */
printf("Checking successful write...\n");
for (i = 0; i < nblocks; ++i)
{
uint32_t j;
const ssize_t blockcnt = MTD_BREAD(master, i, 1, buffer);
if (blockcnt != 1)
{
printf("ERROR: failed to read block #%ld: %d\n", i, blockcnt);
status = 6;
goto cleanup;
}
for (j = 0; j < geo.blocksize; ++j)
{
const uint8_t exp = i % UINT8_MAX;
if (buffer[j] != exp)
{
printf("ERROR: read-write mismatch at block #%ld offset %"
PRIu32 " (read %" PRIu8 " , exp %" PRIu8 ")\n", i, j,
buffer[j], exp);
status = 7;
goto cleanup;
}
}
}
{
/* Replace the contents of blocks #2 and #3 using byte write */
const uint32_t opsize = geo.blocksize / 2;
off_t offset = (geo.blocksize * 2);
memset(buffer, 0xa5, opsize);
printf("Altering the written data...\n");
for (i = 0; i < 4; ++i)
{
const ssize_t bytecnt = MTD_WRITE(master, offset, opsize, buffer);
if (bytecnt != opsize)
{
printf("ERROR: failed to write at offset %jd: %zd\n",
(intmax_t)offset, bytecnt);
status = 8;
goto cleanup;
}
offset += opsize;
}
/* Check that the byte write function properly wrote to the device */
printf("Checking the altered data...\n");
offset = 0;
for (i = 0; i < ((geo.erasesize * geo.neraseblocks) / opsize); ++i)
{
uint32_t j;
const ssize_t bytecnt = MTD_READ(master, offset, opsize, buffer);
if (bytecnt != opsize)
{
printf("ERROR: failed to read at offset %jd: %zd\n",
(intmax_t)offset, bytecnt);
status = 9;
goto cleanup;
}
for (j = 0; j < opsize; ++j)
{
const uint32_t blockidx = offset / geo.blocksize;
uint8_t exp = blockidx % UINT8_MAX;
if ((blockidx == 2) || (blockidx == 3))
{
exp = 0xa5;
}
if (buffer[j] != exp)
{
printf("ERROR: read-write mismatch at offset %jd (read %"
PRIu8 " , exp %" PRIu8 ")\n",
(intmax_t)(offset + j), buffer[j], exp);
status = 10;
goto cleanup;
}
}
offset += opsize;
}
}
printf("Checking block read/write side cases...\n");
{
ssize_t blkcnt;
/* Attempt to write across/after the device boundaries */
memset(buffer, 0xa5, 2 * geo.blocksize);
blkcnt = MTD_BWRITE(master, nblocks - 1, 2, buffer);
if (blkcnt != 1)
{
printf("ERROR: failed writing across the memory boundaries: %zd\n",
blkcnt);
status = 11;
goto cleanup;
}
blkcnt = MTD_BWRITE(master, nblocks, 2, buffer);
if (blkcnt != 0)
{
printf("ERROR: failed writing after the memory boundaries: %zd\n",
blkcnt);
status = 12;
goto cleanup;
}
/* Read across/after the device boundaries */
memset(buffer, 0, 2 * geo.blocksize);
blkcnt = MTD_BREAD(master, nblocks - 1, 2, buffer);
if (blkcnt != 1)
{
printf("ERROR: failed reading across the memory boundaries: %zd\n",
blkcnt);
status = 13;
goto cleanup;
}
blkcnt = MTD_BREAD(master, nblocks, 2, buffer);
if (blkcnt != 0)
{
printf("ERROR: failed reading after the memory boundaries: %zd\n",
blkcnt);
status = 14;
goto cleanup;
}
}
printf("Checking binary read/write side cases...\n");
{
ssize_t bytecnt;
/* Attempt to write across/after the device boundaries */
memset(buffer, 0xa5, geo.blocksize);
bytecnt = MTD_WRITE(master, (geo.erasesize * geo.neraseblocks) - 5
geo.blocksize, buffer);
if (bytecnt != 5)
{
printf("ERROR: failed writing across the memory boundaries: %zd\n",
bytecnt);
status = 15;
goto cleanup;
}
bytecnt = MTD_WRITE(master, (geo.erasesize * geo.neraseblocks),
geo.blocksize, buffer);
if (bytecnt != 0)
{
printf("ERROR: failed writing after the memory boundaries: %zd\n",
bytecnt);
status = 16;
goto cleanup;
}
/* Read across/after the device boundaries */
memset(buffer, 0, geo.blocksize);
bytecnt = MTD_READ(master, (geo.erasesize * geo.neraseblocks) - 5,
geo.blocksize, buffer);
if (bytecnt != 5)
{
printf("ERROR: failed reading across the memory boundaries: %zd\n",
bytecnt);
status = 17;
goto cleanup;
}
bytecnt = MTD_READ(master, (geo.erasesize * geo.neraseblocks),
geo.blocksize, buffer);
if (bytecnt != 0)
{
printf("ERROR: failed reading after the memory boundaries: %zd\n",
bytecnt);
status = 18;
goto cleanup;
}
}
#ifdef CONFIG_AT25EE_ENABLE_BLOCK_ERASE
printf("Checking block erase...\n");
{
/* Erase some blocks */
ret = MTD_ERASE(master, 2, 2);
if (ret != 2)
{
printf("ERROR: failed erasing blocks: %d\n", ret);
status = 20;
goto cleanup;
}
/* Check that the blocks have been erased, ignore the last block */
for (i = 0; i < nblocks - 1; ++i)
{
uint32_t j;
const ssize_t blockcnt = MTD_BREAD(master, i, 1, buffer);
if (blockcnt != 1)
{
printf("ERROR: failed to read block #%ld: %d\n", i, blockcnt);
status = 21;
goto cleanup;
}
for (j = 0; j < geo.blocksize; ++j)
{
const uint8_t exp = ((i == 2) || (i == 3)) ? 0xff
: (i % UINT8_MAX);
if (buffer[j] != exp)
{
printf("ERROR: erase mismatch at block #%ld offset %"
PRIu32 " (read %" PRIu8 " , exp %" PRIu8 ")\n", i,
j, buffer[j], exp);
status = 22;
goto cleanup;
}
}
}
}
#endif /* CONFIG_AT25EE_ENABLE_BLOCK_ERASE */
status = 0;
printf("PASS: All tests completed\n");
cleanup:
if (master != NULL)
{
at25ee_teardown(master);
}
free(buffer);
exit(status);
return 0;
}
```
</details>
### Speed performance validation
Compiled using arm-none-eabi-gcc 13.2.1 on Ubuntu 22.04.
Test sequence (MTD driver only):
1. Repeat 100 times:
1. Write the entire EEPROM in blocks of 64 bytes (corresponding to the
page size)
2. Read the entire EEPROM in blocks of 64 bytes
2. Compute the average execution time for 1 iteration
Test results:
| Driver | Time [ticks] |
| ------- | ------------ |
| Current | 219700 |
| New | 219725 |
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]