CHGame 0.3.0
Libraries for the CHGame handheld
Loading...
Searching...
No Matches
EEPROM.h
Go to the documentation of this file.
1/*
2 EEPROM - Enables reading and writing to non-volatile storage in the processor.
3
4 Uses the Option bytes area in Flash to emulate EEPROM.
5 On the CH32V003 there are 2+24 bytes available.
6 The first two bytes are Option bytes data0 and data1.
7 All bytes are copied to a 26-byte long byte array in RAM.
8 After changing a value the commit() method is used to write flash.
9
10 Ported by Maxint R&D to CH32, based on multiple sources.
11 Tested on CH32V003 using Arduino IDE 2.3.2 and OpenWCH core 1.0.4.
12 Includes code from Option Data example of CH32V003fun by CNLOHR.
13 Arduino original copyright (c) 2006 David A. Mellis. All right reserved.
14 ESP8266 version copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
15
16 This library is free software; you can redistribute it and/or
17 modify it under the terms of the GNU Lesser General Public
18 License as published by the Free Software Foundation; either
19 version 2.1 of the License, or (at your option) any later version.
20
21 This library is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 Lesser General Public License for more details.
25
26 You should have received a copy of the GNU Lesser General Public
27 License along with this library; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29*/
30
31/**
32 * @file
33 * @brief Arduino's EEPROM API, emulated in 26 bytes of the chip's option-byte
34 * area (written for the CH32V003).
35 */
36
37/**
38 * @defgroup core_eeprom EEPROM
39 * @ingroup lib_core
40 * @brief The Arduino EEPROM API over the option-byte area, for the
41 * CH32V003. **On the CHGame board (CH32X035) it does not save:** commit()
42 * writes nothing and returns `false`.
43 *
44 * @note **Saving on the CHGame board?** Use the CHGame library's
45 * @ref chgame_save "save::" functions: a CRC-checked record of up to 244
46 * bytes in the top two pages of the application flash, shared by every game
47 * (each tells its records apart by its own magic), which survives power
48 * cuts and re-uploads.
49 *
50 * What the library does on the chip it was written for, the CH32V003:
51 *
52 * - **26 bytes**, copied into a buffer on the heap by begin(). Bytes 0 and 1
53 * are the user option bytes `Data0` and `Data1`; bytes 2-25 are kept as
54 * half-words (each value with its inverse) at 0x1FFFF810-0x1FFFF83F,
55 * after the 16 bytes of the option-byte block (`OB_BASE`, 0x1FFFF800).
56 * - read(), write(), get(), put(), erase() and `[]` work on that buffer.
57 * Nothing reaches flash until commit() (or end()).
58 * - commit() erases the whole option-byte area, writes back the read
59 * protection (`RDPR`), user (`USER`) and write protection (`WRPR0-3`) words
60 * it copied just before, then `Data0`, `Data1` and every byte that is not
61 * 0xFF. It does not check what it wrote.
62 *
63 * **On the CH32X035** that commit() is switched off, and a sketch that
64 * includes this header gets a compiler message saying so. The chip's
65 * option-byte block is the 16 bytes alone, and WCH's CH32X035 library
66 * programs it only as one fast-programmed page, never a half-word at a
67 * time as above. A write that did not take after the erase would leave the
68 * chip read-protected (removing that with the factory ISP erases the whole
69 * flash, bootloader included) or with its user options changed (on this
70 * board they keep PB7, SELECT, from being the reset pin). So on this chip
71 * begin() reads `Data0` and `Data1` and sets bytes 2-25 to 0xFF, everything
72 * works on the RAM copy as usual, and commit() returns `false` without
73 * writing. Nothing survives a reset.
74 * @{
75 */
76#ifndef EEPROM_h
77#define EEPROM_h
78#include <Arduino.h>
79
80// A message, not a #warning: the board's default "Compiler warnings: None"
81// (-w) would hide a warning, and this one matters.
82#if defined(CH32X035) && !defined(EEPROM_NO_WARNING)
83#pragma message "EEPROM does not save on the CH32X035 (the CHGame board): commit() writes nothing and returns false. Save with the CHGame library's save:: (CHGame.h). Define EEPROM_NO_WARNING to silence this."
84#endif
85
86/** @cond */
87// Required definitions copied from /system/CH32V00x/SRC/Peripheral/src/ch32v00x_flash.c
88/* Flash Control Register bits */
89//#define CR_PG_Set ((uint32_t)0x00000001)
90//#define CR_PG_Reset ((uint32_t)0xFFFFFFFE)
91//#define CR_PER_Set ((uint32_t)0x00000002)
92//#define CR_PER_Reset ((uint32_t)0xFFFFFFFD)
93//#define CR_MER_Set ((uint32_t)0x00000004)
94//#define CR_MER_Reset ((uint32_t)0xFFFFFFFB)
95#define CR_OPTPG_Set ((uint32_t)0x00000010)
96#define CR_OPTPG_Reset ((uint32_t)0xFFFFFFEF)
97#define CR_OPTER_Set ((uint32_t)0x00000020)
98#define CR_OPTER_Reset ((uint32_t)0xFFFFFFDF)
99#define CR_STRT_Set ((uint32_t)0x00000040)
100#define CR_LOCK_Set ((uint32_t)0x00000080)
101//#define CR_PAGE_PG ((uint32_t)0x00010000)
102//#define CR_PAGE_ER ((uint32_t)0x00020000)
103//#define CR_BUF_LOAD ((uint32_t)0x00040000)
104//#define CR_BUF_RST ((uint32_t)0x00080000)
105
106/* FLASH Keys */
107//#define RDP_Key ((uint16_t)0x00A5)
108#define FLASH_KEY1 ((uint32_t)0x45670123)
109#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)
110/** @endcond */
111
112
113/**
114 * @brief 26 bytes of emulated EEPROM in the option-byte area, worked on in a
115 * RAM copy and written by commit() (see @ref core_eeprom).
116 */
118 public:
119 /**
120 * @brief Makes the object; nothing is read until begin().
121 */
123 /**
124 * @brief Calls end(), which commits any change.
125 */
127
128 /**
129 * @brief Copies the 26 bytes from the option-byte area into RAM (26 bytes on
130 * the heap, allocated the first time). Call it before anything else.
131 *
132 * On the CH32X035 only bytes 0 and 1 (`Data0`, `Data1`) are read; bytes
133 * 2-25 start as 0xFF.
134 */
135 void begin(void);
136
137 /**
138 * @brief The 26-byte RAM copy, to change in place; marks it changed, so the
139 * next commit() writes it.
140 * @return the copy, or `nullptr` before begin().
141 */
142 uint8_t * getDataPtr();
143 /**
144 * @brief The 26-byte RAM copy, read-only.
145 * @return the copy, or `nullptr` before begin().
146 */
147 uint8_t const * getConstDataPtr() const;
148 /**
149 * @brief Reads the option bytes `Data0` and `Data1` straight from the chip
150 * (no begin() needed).
151 * @return `Data0`'s half-word in the high 16 bits and `Data1`'s in the low
152 * 16; in each, the low byte is the value and the high byte its
153 * inverse.
154 */
155 uint32_t ReadOptionBytes(void); // return data0 and data1 option bytes including their inversed values
156
157 /**
158 * @brief Reads a byte of the RAM copy.
159 * @param idx 0 to 25.
160 * @return the byte; 0 if `idx` is out of range or before begin().
161 */
162 uint8_t read( int const idx );
163 /**
164 * @brief Changes a byte of the RAM copy; commit() writes it.
165 * @param idx 0 to 25; anything else is ignored, as is a call before begin().
166 * @param val the new value.
167 */
168 void write( int const idx, uint8_t const val); // requires commit() to make data stick
169 /**
170 * @brief Sets the 26 bytes of the RAM copy to 0xFF; commit() writes them.
171 */
172 void erase(void); // requires commit() to make data stick
173
174 /**
175 * @brief Writes the RAM copy to the option-byte area, if anything changed
176 * since begin() or the last commit().
177 *
178 * Erases the whole area and rewrites it (see @ref core_eeprom). On the
179 * CH32X035 it writes nothing.
180 * @return `true` if nothing had changed, or (CH32V003) once written: what
181 * was written is not checked. `false` on the CH32X035 whenever
182 * there was something to write.
183 */
184 bool commit(void);
185 /**
186 * @brief Commits, then forgets the RAM copy (its 26 bytes are not freed);
187 * begin() starts again.
188 * @return what commit() returned.
189 */
190 bool end(void);
191
192 /**
193 * @brief Copies `sizeof(T)` bytes of the RAM copy into `t`.
194 * @tparam T any plain type or struct.
195 * @param address the first byte, 0 to 26 - `sizeof(T)`.
196 * @param t receives the bytes; left as it was if they would not fit.
197 * @return `t`.
198 */
199 template<typename T>
200 T &get(int const address, T &t) {
201 if (address < 0 || address + sizeof(T) > _size)
202 return t;
203 memcpy((uint8_t*) &t, _data + address, sizeof(T));
204 return t;
205 }
206
207 /**
208 * @brief Copies `t` into the RAM copy, if it differs; commit() writes it.
209 * @tparam T any plain type or struct.
210 * @param address the first byte, 0 to 26 - `sizeof(T)`; nothing is stored
211 * if `t` would not fit.
212 * @param t the value.
213 * @return `t`.
214 */
215 template<typename T>
216 const T &put(int const address, const T &t) {
217 if (address < 0 || address + sizeof(T) > _size)
218 return t;
219 if (memcmp(_data + address, (const uint8_t*)&t, sizeof(T)) != 0) {
220 _dirty = true;
221 memcpy(_data + address, (const uint8_t*)&t, sizeof(T));
222 }
223 return t;
224 }
225
226 /**
227 * @brief The emulated EEPROM's size.
228 * @return 26 after begin(), 0 before.
229 */
230 size_t length() {return _size;}
231
232 /**
233 * @brief A byte of the RAM copy, to read or change; marks the copy changed.
234 * No range check: call begin() first and keep to 0-25.
235 * @param address 0 to 25.
236 * @return the byte.
237 */
238 uint8_t& operator[](int const address) {return getDataPtr()[address];}
239 /**
240 * @brief A byte of the RAM copy, read-only. No range check.
241 * @param address 0 to 25.
242 * @return the byte.
243 */
244 uint8_t const & operator[](int const address) const {return getConstDataPtr()[address];}
245
246 protected:
247 /** @brief The RAM copy (26 bytes after begin()). */
248 uint8_t* _data = nullptr;
249 /** @brief Whether the copy changed since begin() or the last commit(). */
250 bool _dirty = false;
251 /** @brief The copy's size: 26 after begin(), else 0. */
252 size_t _size = 0;
253};
254
255#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM)
256/**
257 * @brief The emulated EEPROM. Call `EEPROM.begin()` first.
258 */
259extern EEPROMClass EEPROM;
260#endif
261
262
263/** @} */
264
265#endif // #ifndef EEPROM_h
26 bytes of emulated EEPROM in the option-byte area, worked on in a RAM copy and written by commit() ...
Definition EEPROM.h:117
bool end(void)
Commits, then forgets the RAM copy (its 26 bytes are not freed); begin() starts again.
void write(int const idx, uint8_t const val)
Changes a byte of the RAM copy; commit() writes it.
uint32_t ReadOptionBytes(void)
Reads the option bytes Data0 and Data1 straight from the chip (no begin() needed).
uint8_t & operator[](int const address)
A byte of the RAM copy, to read or change; marks the copy changed.
Definition EEPROM.h:238
EEPROMClass(void)
Makes the object; nothing is read until begin().
uint8_t const * getConstDataPtr() const
The 26-byte RAM copy, read-only.
~EEPROMClass(void)
Calls end(), which commits any change.
uint8_t const & operator[](int const address) const
A byte of the RAM copy, read-only.
Definition EEPROM.h:244
void begin(void)
Copies the 26 bytes from the option-byte area into RAM (26 bytes on the heap, allocated the first tim...
size_t length()
The emulated EEPROM's size.
Definition EEPROM.h:230
size_t _size
The copy's size: 26 after begin(), else 0.
Definition EEPROM.h:252
uint8_t read(int const idx)
Reads a byte of the RAM copy.
bool commit(void)
Writes the RAM copy to the option-byte area, if anything changed since begin() or the last commit().
void erase(void)
Sets the 26 bytes of the RAM copy to 0xFF; commit() writes them.
T & get(int const address, T &t)
Copies sizeof(T) bytes of the RAM copy into t.
Definition EEPROM.h:200
const T & put(int const address, const T &t)
Copies t into the RAM copy, if it differs; commit() writes it.
Definition EEPROM.h:216
uint8_t * getDataPtr()
The 26-byte RAM copy, to change in place; marks it changed, so the next commit() writes it.
bool _dirty
Whether the copy changed since begin() or the last commit().
Definition EEPROM.h:250
uint8_t * _data
The RAM copy (26 bytes after begin()).
Definition EEPROM.h:248
EEPROMClass EEPROM
The emulated EEPROM.