cnlohr / ch32v003fun

Open source minimal stack for the ch32 line of WCH processors, including the ch32v003, a 10¢ 48 MHz RISC-V Microcontroller - as well as many other chips within the ch32v/x line.
MIT License
953 stars 146 forks source link

Store more than 2 bytes in optiondata #398

Closed hientv1999 closed 1 month ago

hientv1999 commented 1 month ago

Hi, I checked the example project optiondata and had it run successfully. However, I want to store more than 2 bytes. How can I achieve this?

TommyMurphyTM1234 commented 1 month ago

Aren't there only two bytes available for user data?

For other readers: That particular address is mentioned at the top of page 179 of the CH32V003 Reference Manual. At the bottom of that page it's stated to be the reserved byte for WRP2, one of the 8 user-option bytes that are mentioned on page 178:

"The user-option bytes is solidified in FLASH and will be reloaded into the corresponding register after system reset, and can be erased and programmed by the user at will. The user option bytes information block has a total of 8 bytes (4 bytes for write protection, 1 byte for read protection, 1 byte for configuration options, and 2 bytes for storing user data), and each bit has its inverse code bit for checksum during loading."

hientv1999 commented 1 month ago

Aren't there only two bytes available for user data?

For other readers: That particular address is mentioned at the top of page 179 of the CH32V003 Reference Manual. At the bottom of that page it's stated to be the reserved byte for WRP2, one of the 8 user-option bytes that are mentioned on page 178:

"The user-option bytes is solidified in FLASH and will be reloaded into the corresponding register after system reset, and can be erased and programmed by the user at will. The user option bytes information block has a total of 8 bytes (4 bytes for write protection, 1 byte for read protection, 1 byte for configuration options, and 2 bytes for storing user data), and each bit has its inverse code bit for checksum during loading."

This guy claims to make an EEPROM library for 26 bytes, which made me think I can achieve the same https://github.com/openwch/arduino_core_ch32/issues/63#issuecomment-2039607314

TommyMurphyTM1234 commented 1 month ago

This guy claims to make an EEPROM library for 26 bytes, which made me think I can achieve the same openwch/arduino_core_ch32#63 (comment)

Then try using their code?

hientv1999 commented 1 month ago

This guy claims to make an EEPROM library for 26 bytes, which made me think I can achieve the same openwch/arduino_core_ch32#63 (comment)

Then try using their code?

Unfortunately there link is broken. But my original thought was there are more than 2 bytes and I just didn't know how to use the remaining bytes. But now you said the limit is 2 and I don't really need more than 2 bytes for my project, I'm ok with optiondata for now

1 question though: Why each data slot is uint16_t, I cannot use it as 2 bytes, to get a total of 4 bytes? I tried but after saving to flash, reading it back mess up my byte data.

TommyMurphyTM1234 commented 1 month ago

This guy claims to make an EEPROM library for 26 bytes, which made me think I can achieve the same openwch/arduino_core_ch32#63 (comment)

Then try using their code?

Unfortunately there link is broken.

The link that I posted isn't broken:

1 question though: Why each data slot is uint16_t, I cannot use it as 2 bytes, to get a total of 4 bytes? I tried but after saving to flash, reading it back mess up my byte data.

I'm not sure what exactly you're referring to but it looks like the two user data bytes are packed into a single uint16_t halfword:

You should probably refer to the datasheet/reference manual for specific details on how the user option bytes non-volatile memory block works and the mechanisms that the optionbytes example program is using to interact with it.

hientv1999 commented 1 month ago

I'm not sure what exactly you're referring to but it looks like the two user data bytes are packed into a single uint16_t halfword:

No, I think you are wrong. They pack 2 uint8_t into 1 uint32_t, which isn't efficient. I tried pack 4 uint8_t into 1 uint32_t and read back results in wrong data. Actually they pack 2 uint8_t into 2 uint16_t, but they use uint32_t to access 2 uint16_t at once.

Code is here for your reference: uint32_t hold32p=(uint32_t )hold; uint32_t ob32p=(uint32_t )OB_BASE; hold32p[0]=ob32p[0]; // Copy RDPR and USER hold32p[1]=data0+(data1<<16); // Copy in the two Data values to be written hold32p[2]=ob32p[2]; // Copy WRPR0 and WEPR1

mengstr commented 1 month ago

Hi - author of the horrible code above here ;-)

As mentioned in the comments I did it as 32 bit operations to save code space. It makes a bit harder to understand, but the goal was to make a small function that was meant to be used as-is as a plugin and not as an explanation of how the option block is actually works. Considering the rather limited amount of flash in the 003 I felt it was more important to save space.

So... While there are 16 bytes in total in the "option block" aka "User selected words" there are only two bytes of those that can be used for storing actual user-data. The rest are used for memory protection, system settings and inverted data as a rudimentary validity check. Each piece of data in the block is 1 byte, but have an attached byte of inverted data, so that's why they are grouped into a uint16_t. Each uint16_t hold the real data and the inverted data.

I did try to store other data instead of the inverted bytes, but as I remember it the 003 really didn't like that. Considering that it would be an undocumented usage of those bits there's no guarantee that it would work in the next revision of the IC, so in general I think it's better to stick to what the datasheet says.

From the manual: The user select word information block has a total of 8 bytes (4 bytes for write protection, 1 byte for read protection, 1 byte for configuration options, and 2 bytes for storing user data), and each bit has its inverse code bit for checksum during loading.

TommyMurphyTM1234 commented 1 month ago

Thanks a lot @mengstr - that's useful info in the context of this thread. 👍

Can you clarify where the inverted versions of data0 and data1 get prepared for storage or do those values get stored automatically by the Flash device during writing of data0 and data1?

Also - this says that 64 byte block is erased so values other than data0 and data1 (and their inverted versions?) need to be saved so that they can be written back but I can't see where that's happening:

The hold array is only 12 bytes in size: