liam-geotab opened a new pull request, #20144:
URL: https://github.com/apache/nuttx/pull/20144
## Summary
Add an API for OTP (one-time programmable) memory on stm32h5. There are OTP
APIs for non-STM32 platforms. There is no other API for STM32 so far with these
names.
Implement it in stm32h563xx_flash.c since the progmem abstraction also lives
there.
```c
int stm32_otp_write(const uint16_t *data, uint16_t len, uint32_t offset);
int stm32_otp_read(uint16_t *data, uint16_t len, uint32_t offset);
```
The API allows cross-block reads/writes that don't necessarily start/end at
block boundaries.
The type of `data` is uint16_t * to express to the caller that the pointer
should be 2-aligned. The natural size of OTP words is 16 bits. `len` is
uint16_t for no strong reason. Preserve author's work.
```c
uint32_t stm32_otp_getlockstatus(void);
```
Get a mask of blocks that are locked. A block being locked is considered as
being one-time programmed. In future stm32 platform support, uint32_t may not
be sufficient to represent all blocks. This platform has 32 blocks.
The user can be ignorant of the block sizes but they must be aware of the
full size of the OTP area and there is no define for it in a public header. If
the user writes half of a block, the unwritten half still gets locked, so the
user cannot e.g. write the whole OTP area one word at a time, so they actually
do need to be aware of the block size.
If these issues are unacceptable, changes should be requested by reviewers.
I am favoring preserving the author's work by default.
## Impact
If the new STM32 OTP API is bad, there will be a breaking change later (e.g.
when OTP is added for other STM32 platforms) to improve it.
The other impact worth noting is that this permanently sets a device's OTP
contents irreversibly, if that wasn't clear.
## Testing
`nucleo-h563zi:nsh` with `CONFIG_STM32_PROGMEM` enabled.
```diff
diff --git a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c
b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c
index 2cfb962226..57100f0975 100644
--- a/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c
+++ b/boards/arm/stm32h5/nucleo-h563zi/src/stm32_bringup.c
@@ -42,10 +42,53 @@
# include "stm32_wdg.h"
#endif
+#include "stm32_flash.h"
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+#define BLOCK_SIZE 64
+#define BLOCK 5 /* block to write */
+
+static const uint8_t block_data[BLOCK_SIZE] =
"\xff\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33\xab\xcd\xef\x33";
+
+static uint16_t otp_block[BLOCK_SIZE / 2];
+
+static int dump_otp(void)
+{
+ int ret;
+ uint8_t *otp_block_u8 = (uint8_t *)otp_block;
+
+ uint32_t lock_bits = stm32_otp_getlockstatus();
+ printf("OTP lock bits: 0x%08"PRIx32"\n", lock_bits);
+
+ for (int i = 0; i < 32; i++)
+ {
+ printf("OTP block %2d (offset %4d):", i, i * BLOCK_SIZE);
+
+ if (((1 << i) & lock_bits) == 0)
+ {
+ printf(" not programmed\n");
+ continue;
+ }
+
+ ret = stm32_otp_read(otp_block, BLOCK_SIZE, i * BLOCK_SIZE);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: Failed to read OTP: %d\n", ret);
+ return ret;
+ }
+ for (int j = 0; j < BLOCK_SIZE; j++)
+ {
+ printf(" %02"PRIx8, otp_block_u8[j]);
+ }
+ printf("\n");
+ }
+
+ return OK;
+}
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -177,6 +220,35 @@ int stm32_bringup(void)
}
#endif
+ ret = dump_otp();
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ if (((1 << BLOCK) & stm32_otp_getlockstatus()) == 0)
+ {
+ printf("writing block %d\n", BLOCK);
+
+ memcpy(otp_block, block_data, BLOCK_SIZE);
+ ret = stm32_otp_write(otp_block, BLOCK_SIZE, BLOCK * BLOCK_SIZE);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: Failed to write OTP: %d\n", ret);
+ return ret;
+ }
+
+ ret = dump_otp();
+ if (ret < 0)
+ {
+ return ret;
+ }
+ }
+ else
+ {
+ printf("block %d is already written\n", BLOCK);
+ }
+
UNUSED(ret);
return OK;
}
```
```
ABCG
OTP lock bits: 0x00000001
OTP block 0 (offset 0): ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33
ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd
ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33
OTP block 1 (offset 64): not programmed
OTP block 2 (offset 128): not programmed
OTP block 3 (offset 192): not programmed
OTP block 4 (offset 256): not programmed
OTP block 5 (offset 320): not programmed
OTP block 6 (offset 384): not programmed
OTP block 7 (offset 448): not programmed
OTP block 8 (offset 512): not programmed
OTP block 9 (offset 576): not programmed
OTP block 10 (offset 640): not programmed
OTP block 11 (offset 704): not programmed
OTP block 12 (offset 768): not programmed
OTP block 13 (offset 832): not programmed
OTP block 14 (offset 896): not programmed
OTP block 15 (offset 960): not programmed
OTP block 16 (offset 1024): not programmed
OTP block 17 (offset 1088): not programmed
OTP block 18 (offset 1152): not programmed
OTP block 19 (offset 1216): not programmed
OTP block 20 (offset 1280): not programmed
OTP block 21 (offset 1344): not programmed
OTP block 22 (offset 1408): not programmed
OTP block 23 (offset 1472): not programmed
OTP block 24 (offset 1536): not programmed
OTP block 25 (offset 1600): not programmed
OTP block 26 (offset 1664): not programmed
OTP block 27 (offset 1728): not programmed
OTP block 28 (offset 1792): not programmed
OTP block 29 (offset 1856): not programmed
OTP block 30 (offset 1920): not programmed
OTP block 31 (offset 1984): not programmed
writing block 5
OTP lock bits: 0x00000021
OTP block 0 (offset 0): ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33
ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd
ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33
OTP block 1 (offset 64): not programmed
OTP block 2 (offset 128): not programmed
OTP block 3 (offset 192): not programmed
OTP block 4 (offset 256): not programmed
OTP block 5 (offset 320): ff cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33
ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd
ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33
OTP block 6 (offset 384): not programmed
OTP block 7 (offset 448): not programmed
OTP block 8 (offset 512): not programmed
OTP block 9 (offset 576): not programmed
OTP block 10 (offset 640): not programmed
OTP block 11 (offset 704): not programmed
OTP block 12 (offset 768): not programmed
OTP block 13 (offset 832): not programmed
OTP block 14 (offset 896): not programmed
OTP block 15 (offset 960): not programmed
OTP block 16 (offset 1024): not programmed
OTP block 17 (offset 1088): not programmed
OTP block 18 (offset 1152): not programmed
OTP block 19 (offset 1216): not programmed
OTP block 20 (offset 1280): not programmed
OTP block 21 (offset 1344): not programmed
OTP block 22 (offset 1408): not programmed
OTP block 23 (offset 1472): not programmed
OTP block 24 (offset 1536): not programmed
OTP block 25 (offset 1600): not programmed
OTP block 26 (offset 1664): not programmed
OTP block 27 (offset 1728): not programmed
OTP block 28 (offset 1792): not programmed
OTP block 29 (offset 1856): not programmed
OTP block 30 (offset 1920): not programmed
OTP block 31 (offset 1984): not programmed
NuttShell (NSH) NuttX-13.0.1-RC1
nsh>
```
(reset)
```
ABCG
OTP lock bits: 0x00000021
OTP block 0 (offset 0): ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33
ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd
ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33
OTP block 1 (offset 64): not programmed
OTP block 2 (offset 128): not programmed
OTP block 3 (offset 192): not programmed
OTP block 4 (offset 256): not programmed
OTP block 5 (offset 320): ff cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33
ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd
ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33 ab cd ef 33
OTP block 6 (offset 384): not programmed
OTP block 7 (offset 448): not programmed
OTP block 8 (offset 512): not programmed
OTP block 9 (offset 576): not programmed
OTP block 10 (offset 640): not programmed
OTP block 11 (offset 704): not programmed
OTP block 12 (offset 768): not programmed
OTP block 13 (offset 832): not programmed
OTP block 14 (offset 896): not programmed
OTP block 15 (offset 960): not programmed
OTP block 16 (offset 1024): not programmed
OTP block 17 (offset 1088): not programmed
OTP block 18 (offset 1152): not programmed
OTP block 19 (offset 1216): not programmed
OTP block 20 (offset 1280): not programmed
OTP block 21 (offset 1344): not programmed
OTP block 22 (offset 1408): not programmed
OTP block 23 (offset 1472): not programmed
OTP block 24 (offset 1536): not programmed
OTP block 25 (offset 1600): not programmed
OTP block 26 (offset 1664): not programmed
OTP block 27 (offset 1728): not programmed
OTP block 28 (offset 1792): not programmed
OTP block 29 (offset 1856): not programmed
OTP block 30 (offset 1920): not programmed
OTP block 31 (offset 1984): not programmed
block 5 is already written
NuttShell (NSH) NuttX-13.0.1-RC1
nsh>
```
--
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]