mirror of
https://github.com/qmk/qmk_firmware.git
synced 2025-08-06 06:54:58 +00:00
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
097f1a299f | ||
![]() |
d12d058bae | ||
![]() |
972388447b | ||
![]() |
6794a5c9dc | ||
![]() |
621ce29a53 |
@@ -13,9 +13,11 @@ People often define custom names using `#define`. For example:
|
||||
|
||||
This will allow you to use `FN_CAPS` and `ALT_TAB` in your `KEYMAP()`, keeping it more readable.
|
||||
|
||||
### Limits of These Aliases
|
||||
### Caveats
|
||||
|
||||
Currently, the keycodes able to used with these functions are limited to the [Basic Keycodes](keycodes_basic.md), meaning you can't use keycodes like `KC_TILD`, or anything greater than 0xFF. For a full list of the keycodes able to be used see [Basic Keycodes](keycodes_basic.md).
|
||||
Currently, `LT()` and `MT()` are limited to the [Basic Keycode set](keycodes_basic.md), meaning you can't use keycodes like `LCTL()`, `KC_TILD`, or anything greater than `0xFF`. Modifiers specified as part of a Layer Tap or Mod Tap's keycode will be ignored.
|
||||
|
||||
Additionally, if at least one right-handed modifier is specified in a Mod Tap or Layer Tap, it will cause all modifiers specified to become right-handed, so it is not possible to mix and match the two.
|
||||
|
||||
# Switching and Toggling Layers
|
||||
|
||||
@@ -103,10 +105,6 @@ We've added shortcuts to make common modifier/tap (mod-tap) mappings more compac
|
||||
* `LCAG_T(kc)` - is CtrlAltGui when held and *kc* when tapped
|
||||
* `MEH_T(kc)` - is like Hyper, but not as cool -- does not include the Cmd/Win key, so just sends Alt+Ctrl+Shift.
|
||||
|
||||
?> Due to the way that keycodes are structured, any modifiers specified as part of `kc`, such as `LCTL()` or `KC_LPRN`, will only activate when held instead of tapped.
|
||||
|
||||
?> Additionally, if there is at least one right-handed modifier, any other modifiers in a chain of functions will turn into their right-handed equivalents, so it is not possible to "mix and match" the two.
|
||||
|
||||
# One Shot Keys
|
||||
|
||||
One shot keys are keys that remain active until the next key is pressed, and then are released. This allows you to type keyboard combinations without pressing more than one key at a time. These keys are usually called "Sticky keys" or "Dead keys".
|
||||
|
@@ -12,4 +12,9 @@ Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make alt67:default
|
||||
|
||||
For information on flashing this keyboard, visit the following links:
|
||||
|
||||
[Massdrop Loader Releases](https://github.com/Massdrop/mdloader/releases/tag/0.0.1)
|
||||
[Massdrop Loader Repository and Instructions](https://github.com/Massdrop/mdloader)
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
@@ -12,4 +12,9 @@ Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make ctrl:default
|
||||
|
||||
For information on flashing this keyboard, visit the following links:
|
||||
|
||||
[Massdrop Loader Releases](https://github.com/Massdrop/mdloader/releases/tag/0.0.1)
|
||||
[Massdrop Loader Repository and Instructions](https://github.com/Massdrop/mdloader)
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
@@ -34,6 +34,8 @@ enum {
|
||||
FUNCTION,
|
||||
};
|
||||
|
||||
bool screenWorks = 0;
|
||||
|
||||
//13 characters max without re-writing the "Layer: " format in iota_gfx_task_user()
|
||||
static char layer_lookup[][14] = {"Base","Function"};
|
||||
|
||||
@@ -93,7 +95,9 @@ void matrix_init_user(void) {
|
||||
// calls code for the SSD1306 OLED
|
||||
_delay_ms(400);
|
||||
TWI_Init(TWI_BIT_PRESCALE_1, TWI_BITLENGTH_FROM_FREQ(1, 800000));
|
||||
iota_gfx_init(); // turns on the display
|
||||
if(iota_gfx_init()){ // turns on the display
|
||||
screenWorks = 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#ifdef AUDIO_ENABLE
|
||||
@@ -103,7 +107,9 @@ void matrix_init_user(void) {
|
||||
|
||||
void matrix_scan_user(void) {
|
||||
#ifdef SSD1306OLED
|
||||
iota_gfx_task(); // this is what updates the display continuously
|
||||
if(screenWorks){
|
||||
iota_gfx_task(); // this is what updates the display continuously
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -34,6 +34,8 @@ enum {
|
||||
FUNCTION,
|
||||
};
|
||||
|
||||
bool screenWorks = 0;
|
||||
|
||||
//13 characters max without re-writing the "Layer: " format in iota_gfx_task_user()
|
||||
static char layer_lookup[][14] = {"Base","Function"};
|
||||
|
||||
@@ -93,7 +95,9 @@ void matrix_init_user(void) {
|
||||
// calls code for the SSD1306 OLED
|
||||
_delay_ms(400);
|
||||
TWI_Init(TWI_BIT_PRESCALE_1, TWI_BITLENGTH_FROM_FREQ(1, 800000));
|
||||
iota_gfx_init(); // turns on the display
|
||||
if(iota_gfx_init()){ // turns on the display
|
||||
screenWorks = 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#ifdef AUDIO_ENABLE
|
||||
@@ -103,7 +107,9 @@ void matrix_init_user(void) {
|
||||
|
||||
void matrix_scan_user(void) {
|
||||
#ifdef SSD1306OLED
|
||||
iota_gfx_task(); // this is what updates the display continuously
|
||||
if(screenWorks){
|
||||
iota_gfx_task(); // this is what updates the display continuously
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -459,27 +459,27 @@ enum quantum_keycodes {
|
||||
};
|
||||
|
||||
// Ability to use mods in layouts
|
||||
#define LCTL(kc) (kc | QK_LCTL)
|
||||
#define LSFT(kc) (kc | QK_LSFT)
|
||||
#define LALT(kc) (kc | QK_LALT)
|
||||
#define LGUI(kc) (kc | QK_LGUI)
|
||||
#define LCTL(kc) (QK_LCTL | (kc))
|
||||
#define LSFT(kc) (QK_LSFT | (kc))
|
||||
#define LALT(kc) (QK_LALT | (kc))
|
||||
#define LGUI(kc) (QK_LGUI | (kc))
|
||||
#define LCMD(kc) LGUI(kc)
|
||||
#define LWIN(kc) LGUI(kc)
|
||||
#define RCTL(kc) (kc | QK_RCTL)
|
||||
#define RSFT(kc) (kc | QK_RSFT)
|
||||
#define RALT(kc) (kc | QK_RALT)
|
||||
#define RGUI(kc) (kc | QK_RGUI)
|
||||
#define RCTL(kc) (QK_RCTL | (kc))
|
||||
#define RSFT(kc) (QK_RSFT | (kc))
|
||||
#define RALT(kc) (QK_RALT | (kc))
|
||||
#define RGUI(kc) (QK_RGUI | (kc))
|
||||
#define RCMD(kc) RGUI(kc)
|
||||
#define RWIN(kc) RGUI(kc)
|
||||
|
||||
#define HYPR(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT | QK_LGUI)
|
||||
#define MEH(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT)
|
||||
#define LCAG(kc) (kc | QK_LCTL | QK_LALT | QK_LGUI)
|
||||
#define ALTG(kc) (kc | QK_RCTL | QK_RALT)
|
||||
#define SGUI(kc) (kc | QK_LGUI | QK_LSFT)
|
||||
#define HYPR(kc) (QK_LCTL | QK_LSFT | QK_LALT | QK_LGUI | (kc))
|
||||
#define MEH(kc) (QK_LCTL | QK_LSFT | QK_LALT | (kc))
|
||||
#define LCAG(kc) (QK_LCTL | QK_LALT | QK_LGUI | (kc))
|
||||
#define ALTG(kc) (QK_RCTL | QK_RALT | (kc))
|
||||
#define SGUI(kc) (QK_LGUI | QK_LSFT | (kc))
|
||||
#define SCMD(kc) SGUI(kc)
|
||||
#define SWIN(kc) SGUI(kc)
|
||||
#define LCA(kc) (kc | QK_LCTL | QK_LALT)
|
||||
#define LCA(kc) (QK_LCTL | QK_LALT | (kc))
|
||||
|
||||
#define MOD_HYPR 0xf
|
||||
#define MOD_MEH 0x7
|
||||
@@ -557,15 +557,15 @@ enum quantum_keycodes {
|
||||
#define KC_DELT KC_DELETE // Del key (four letter code)
|
||||
|
||||
// Alias for function layers than expand past FN31
|
||||
#define FUNC(kc) (kc | QK_FUNCTION)
|
||||
#define FUNC(kc) (QK_FUNCTION | (kc))
|
||||
|
||||
// Aliases
|
||||
#define S(kc) LSFT(kc)
|
||||
#define F(kc) FUNC(kc)
|
||||
|
||||
#define M(kc) (kc | QK_MACRO)
|
||||
#define M(kc) (QK_MACRO | (kc))
|
||||
|
||||
#define MACROTAP(kc) (kc | QK_MACRO | FUNC_TAP<<8)
|
||||
#define MACROTAP(kc) (QK_MACRO | (FUNC_TAP << 8) | (kc))
|
||||
#define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE)
|
||||
|
||||
#define KC_GESC GRAVE_ESC
|
||||
@@ -590,7 +590,7 @@ enum quantum_keycodes {
|
||||
#define RGB_M_T RGB_MODE_RGBTEST
|
||||
|
||||
// L-ayer, T-ap - 256 keycode max, 16 layer max
|
||||
#define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8))
|
||||
#define LT(layer, kc) (QK_LAYER_TAP | ((layer & 0xF) << 8) | ((kc) & 0xFF))
|
||||
|
||||
#define AG_SWAP MAGIC_SWAP_ALT_GUI
|
||||
#define AG_NORM MAGIC_UNSWAP_ALT_GUI
|
||||
@@ -602,32 +602,32 @@ enum quantum_keycodes {
|
||||
// Unless you have a good reason not to do so, prefer ON_PRESS (1) as your default.
|
||||
// In fact, we changed it to assume ON_PRESS for sanity/simplicity. If needed, you can add your own
|
||||
// keycode modeled after the old version, kept below for this.
|
||||
/* #define TO(layer, when) (layer | QK_TO | (when << 0x4)) */
|
||||
#define TO(layer) (layer | QK_TO | (ON_PRESS << 0x4))
|
||||
/* #define TO(layer, when) (QK_TO | (when << 0x4) | (layer & 0xFF)) */
|
||||
#define TO(layer) (QK_TO | (ON_PRESS << 0x4) | (layer & 0xFF))
|
||||
|
||||
// Momentary switch layer - 256 layer max
|
||||
#define MO(layer) (layer | QK_MOMENTARY)
|
||||
#define MO(layer) (QK_MOMENTARY | (layer & 0xFF))
|
||||
|
||||
// Set default layer - 256 layer max
|
||||
#define DF(layer) (layer | QK_DEF_LAYER)
|
||||
#define DF(layer) (QK_DEF_LAYER | (layer & 0xFF))
|
||||
|
||||
// Toggle to layer - 256 layer max
|
||||
#define TG(layer) (layer | QK_TOGGLE_LAYER)
|
||||
#define TG(layer) (QK_TOGGLE_LAYER | (layer & 0xFF))
|
||||
|
||||
// One-shot layer - 256 layer max
|
||||
#define OSL(layer) (layer | QK_ONE_SHOT_LAYER)
|
||||
#define OSL(layer) (QK_ONE_SHOT_LAYER | (layer & 0xFF))
|
||||
|
||||
// L-ayer M-od: Momentary switch layer with modifiers active - 16 layer max, left mods only
|
||||
#define LM(layer, mod) (QK_LAYER_MOD | (((layer) & 0xF) << 4) | ((mod) & 0xF))
|
||||
#define LM(layer, mod) (QK_LAYER_MOD | ((layer & 0xF) << 4) | ((mod) & 0xF))
|
||||
|
||||
// One-shot mod
|
||||
#define OSM(mod) ((mod) | QK_ONE_SHOT_MOD)
|
||||
#define OSM(mod) (QK_ONE_SHOT_MOD | ((mod) & 0xFF))
|
||||
|
||||
// Layer tap-toggle
|
||||
#define TT(layer) (layer | QK_LAYER_TAP_TOGGLE)
|
||||
#define TT(layer) (QK_LAYER_TAP_TOGGLE | (layer & 0xFF))
|
||||
|
||||
// M-od, T-ap - 256 keycode max
|
||||
#define MT(mod, kc) (kc | QK_MOD_TAP | (((mod) & 0x1F) << 8))
|
||||
#define MT(mod, kc) (QK_MOD_TAP | (((mod) & 0x1F) << 8) | ((kc) & 0xFF))
|
||||
|
||||
#define CTL_T(kc) MT(MOD_LCTL, kc)
|
||||
#define LCTL_T(kc) MT(MOD_LCTL, kc)
|
||||
@@ -652,15 +652,15 @@ enum quantum_keycodes {
|
||||
#define RCMD_T(kc) RGUI_T(kc)
|
||||
#define RWIN_T(kc) RGUI_T(kc)
|
||||
|
||||
#define C_S_T(kc) MT((MOD_LCTL | MOD_LSFT), kc) // Control + Shift e.g. for gnome-terminal
|
||||
#define MEH_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT), kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl
|
||||
#define LCAG_T(kc) MT((MOD_LCTL | MOD_LALT | MOD_LGUI), kc) // Left control alt and gui
|
||||
#define RCAG_T(kc) MT((MOD_RCTL | MOD_RALT | MOD_RGUI), kc) // Right control alt and gui
|
||||
#define ALL_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI), kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/
|
||||
#define SGUI_T(kc) MT((MOD_LGUI | MOD_LSFT), kc)
|
||||
#define C_S_T(kc) MT(MOD_LCTL | MOD_LSFT, kc) // Control + Shift e.g. for gnome-terminal
|
||||
#define MEH_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT, kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl
|
||||
#define LCAG_T(kc) MT(MOD_LCTL | MOD_LALT | MOD_LGUI, kc) // Left control alt and gui
|
||||
#define RCAG_T(kc) MT(MOD_RCTL | MOD_RALT | MOD_RGUI, kc) // Right control alt and gui
|
||||
#define ALL_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI, kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/
|
||||
#define SGUI_T(kc) MT(MOD_LGUI | MOD_LSFT, kc)
|
||||
#define SCMD_T(kc) SGUI_T(kc)
|
||||
#define SWIN_T(kc) SGUI_T(kc)
|
||||
#define LCA_T(kc) MT((MOD_LCTL | MOD_LALT), kc) // Left control and left alt
|
||||
#define LCA_T(kc) MT(MOD_LCTL | MOD_LALT, kc) // Left control and left alt
|
||||
|
||||
// Dedicated keycode versions for Hyper and Meh, if you want to use them as standalone keys rather than mod-tap
|
||||
#define KC_HYPR HYPR(KC_NO)
|
||||
@@ -670,22 +670,22 @@ enum quantum_keycodes {
|
||||
// For sending unicode codes.
|
||||
// You may not send codes over 7FFF -- this supports most of UTF8.
|
||||
// To have a key that sends out Œ, go UC(0x0152)
|
||||
#define UNICODE(n) (n | QK_UNICODE)
|
||||
#define UNICODE(n) (QK_UNICODE | (n))
|
||||
#define UC(n) UNICODE(n)
|
||||
#endif
|
||||
|
||||
#ifdef UNICODEMAP_ENABLE
|
||||
#define X(n) (n | QK_UNICODE_MAP)
|
||||
#define X(n) (QK_UNICODE_MAP | (n))
|
||||
#endif
|
||||
|
||||
#ifdef SWAP_HANDS_ENABLE
|
||||
#define SH_T(key) (QK_SWAP_HANDS | key)
|
||||
#define SH_TG (QK_SWAP_HANDS | OP_SH_TOGGLE)
|
||||
#define SH_TT (QK_SWAP_HANDS | OP_SH_TAP_TOGGLE)
|
||||
#define SH_MON (QK_SWAP_HANDS | OP_SH_ON_OFF)
|
||||
#define SH_MOFF (QK_SWAP_HANDS | OP_SH_OFF_ON)
|
||||
#define SH_ON (QK_SWAP_HANDS | OP_SH_ON)
|
||||
#define SH_OFF (QK_SWAP_HANDS | OP_SH_OFF)
|
||||
#define SH_T(kc) (QK_SWAP_HANDS | (kc))
|
||||
#define SH_TG (QK_SWAP_HANDS | OP_SH_TOGGLE)
|
||||
#define SH_TT (QK_SWAP_HANDS | OP_SH_TAP_TOGGLE)
|
||||
#define SH_MON (QK_SWAP_HANDS | OP_SH_ON_OFF)
|
||||
#define SH_MOFF (QK_SWAP_HANDS | OP_SH_OFF_ON)
|
||||
#define SH_ON (QK_SWAP_HANDS | OP_SH_ON)
|
||||
#define SH_OFF (QK_SWAP_HANDS | OP_SH_OFF)
|
||||
#endif
|
||||
|
||||
#endif // QUANTUM_KEYCODES_H
|
||||
|
@@ -31,7 +31,12 @@ endif
|
||||
|
||||
ifeq ($(PLATFORM),CHIBIOS)
|
||||
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c
|
||||
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
|
||||
ifeq ($(MCU_SERIES), STM32F3xx)
|
||||
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom_stm32.c
|
||||
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/flash_stm32.c
|
||||
else
|
||||
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom_teensy.c
|
||||
endif
|
||||
ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes)
|
||||
TMK_COMMON_SRC += $(CHIBIOS)/os/various/syscalls.c
|
||||
endif
|
||||
|
673
tmk_core/common/chibios/eeprom_stm32.c
Executable file
673
tmk_core/common/chibios/eeprom_stm32.c
Executable file
@@ -0,0 +1,673 @@
|
||||
/*
|
||||
* This software is experimental and a work in progress.
|
||||
* Under no circumstances should these files be used in relation to any critical system(s).
|
||||
* Use of these files is at your own risk.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and
|
||||
* https://github.com/leaflabs/libmaple
|
||||
*
|
||||
* Modifications for QMK and STM32F303 by Yiancar
|
||||
*/
|
||||
|
||||
#include "eeprom_stm32.h"
|
||||
|
||||
FLASH_Status EE_ErasePage(uint32_t);
|
||||
|
||||
uint16_t EE_CheckPage(uint32_t, uint16_t);
|
||||
uint16_t EE_CheckErasePage(uint32_t, uint16_t);
|
||||
uint16_t EE_Format(void);
|
||||
uint32_t EE_FindValidPage(void);
|
||||
uint16_t EE_GetVariablesCount(uint32_t, uint16_t);
|
||||
uint16_t EE_PageTransfer(uint32_t, uint32_t, uint16_t);
|
||||
uint16_t EE_VerifyPageFullWriteVariable(uint16_t, uint16_t);
|
||||
|
||||
uint32_t PageBase0 = EEPROM_PAGE0_BASE;
|
||||
uint32_t PageBase1 = EEPROM_PAGE1_BASE;
|
||||
uint32_t PageSize = EEPROM_PAGE_SIZE;
|
||||
uint16_t Status = EEPROM_NOT_INIT;
|
||||
|
||||
// See http://www.st.com/web/en/resource/technical/document/application_note/CD00165693.pdf
|
||||
|
||||
/**
|
||||
* @brief Check page for blank
|
||||
* @param page base address
|
||||
* @retval Success or error
|
||||
* EEPROM_BAD_FLASH: page not empty after erase
|
||||
* EEPROM_OK: page blank
|
||||
*/
|
||||
uint16_t EE_CheckPage(uint32_t pageBase, uint16_t status)
|
||||
{
|
||||
uint32_t pageEnd = pageBase + (uint32_t)PageSize;
|
||||
|
||||
// Page Status not EEPROM_ERASED and not a "state"
|
||||
if ((*(__IO uint16_t*)pageBase) != EEPROM_ERASED && (*(__IO uint16_t*)pageBase) != status)
|
||||
return EEPROM_BAD_FLASH;
|
||||
for(pageBase += 4; pageBase < pageEnd; pageBase += 4)
|
||||
if ((*(__IO uint32_t*)pageBase) != 0xFFFFFFFF) // Verify if slot is empty
|
||||
return EEPROM_BAD_FLASH;
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erase page with increment erase counter (page + 2)
|
||||
* @param page base address
|
||||
* @retval Success or error
|
||||
* FLASH_COMPLETE: success erase
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
FLASH_Status EE_ErasePage(uint32_t pageBase)
|
||||
{
|
||||
FLASH_Status FlashStatus;
|
||||
uint16_t data = (*(__IO uint16_t*)(pageBase));
|
||||
if ((data == EEPROM_ERASED) || (data == EEPROM_VALID_PAGE) || (data == EEPROM_RECEIVE_DATA))
|
||||
data = (*(__IO uint16_t*)(pageBase + 2)) + 1;
|
||||
else
|
||||
data = 0;
|
||||
|
||||
FlashStatus = FLASH_ErasePage(pageBase);
|
||||
if (FlashStatus == FLASH_COMPLETE)
|
||||
FlashStatus = FLASH_ProgramHalfWord(pageBase + 2, data);
|
||||
|
||||
return FlashStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check page for blank and erase it
|
||||
* @param page base address
|
||||
* @retval Success or error
|
||||
* - Flash error code: on write Flash error
|
||||
* - EEPROM_BAD_FLASH: page not empty after erase
|
||||
* - EEPROM_OK: page blank
|
||||
*/
|
||||
uint16_t EE_CheckErasePage(uint32_t pageBase, uint16_t status)
|
||||
{
|
||||
uint16_t FlashStatus;
|
||||
if (EE_CheckPage(pageBase, status) != EEPROM_OK)
|
||||
{
|
||||
FlashStatus = EE_ErasePage(pageBase);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
return FlashStatus;
|
||||
return EE_CheckPage(pageBase, status);
|
||||
}
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find valid Page for write or read operation
|
||||
* @param Page0: Page0 base address
|
||||
* Page1: Page1 base address
|
||||
* @retval Valid page address (PAGE0 or PAGE1) or NULL in case of no valid page was found
|
||||
*/
|
||||
uint32_t EE_FindValidPage(void)
|
||||
{
|
||||
uint16_t status0 = (*(__IO uint16_t*)PageBase0); // Get Page0 actual status
|
||||
uint16_t status1 = (*(__IO uint16_t*)PageBase1); // Get Page1 actual status
|
||||
|
||||
if (status0 == EEPROM_VALID_PAGE && status1 == EEPROM_ERASED)
|
||||
return PageBase0;
|
||||
if (status1 == EEPROM_VALID_PAGE && status0 == EEPROM_ERASED)
|
||||
return PageBase1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate unique variables in EEPROM
|
||||
* @param start: address of first slot to check (page + 4)
|
||||
* @param end: page end address
|
||||
* @param address: 16 bit virtual address of the variable to excluse (or 0XFFFF)
|
||||
* @retval count of variables
|
||||
*/
|
||||
uint16_t EE_GetVariablesCount(uint32_t pageBase, uint16_t skipAddress)
|
||||
{
|
||||
uint16_t varAddress, nextAddress;
|
||||
uint32_t idx;
|
||||
uint32_t pageEnd = pageBase + (uint32_t)PageSize;
|
||||
uint16_t count = 0;
|
||||
|
||||
for (pageBase += 6; pageBase < pageEnd; pageBase += 4)
|
||||
{
|
||||
varAddress = (*(__IO uint16_t*)pageBase);
|
||||
if (varAddress == 0xFFFF || varAddress == skipAddress)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
for(idx = pageBase + 4; idx < pageEnd; idx += 4)
|
||||
{
|
||||
nextAddress = (*(__IO uint16_t*)idx);
|
||||
if (nextAddress == varAddress)
|
||||
{
|
||||
count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transfers last updated variables data from the full Page to an empty one.
|
||||
* @param newPage: new page base address
|
||||
* @param oldPage: old page base address
|
||||
* @param SkipAddress: 16 bit virtual address of the variable (or 0xFFFF)
|
||||
* @retval Success or error status:
|
||||
* - FLASH_COMPLETE: on success
|
||||
* - EEPROM_OUT_SIZE: if valid new page is full
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
uint16_t EE_PageTransfer(uint32_t newPage, uint32_t oldPage, uint16_t SkipAddress)
|
||||
{
|
||||
uint32_t oldEnd, newEnd;
|
||||
uint32_t oldIdx, newIdx, idx;
|
||||
uint16_t address, data, found;
|
||||
FLASH_Status FlashStatus;
|
||||
|
||||
// Transfer process: transfer variables from old to the new active page
|
||||
newEnd = newPage + ((uint32_t)PageSize);
|
||||
|
||||
// Find first free element in new page
|
||||
for (newIdx = newPage + 4; newIdx < newEnd; newIdx += 4)
|
||||
if ((*(__IO uint32_t*)newIdx) == 0xFFFFFFFF) // Verify if element
|
||||
break; // contents are 0xFFFFFFFF
|
||||
if (newIdx >= newEnd)
|
||||
return EEPROM_OUT_SIZE;
|
||||
|
||||
oldEnd = oldPage + 4;
|
||||
oldIdx = oldPage + (uint32_t)(PageSize - 2);
|
||||
|
||||
for (; oldIdx > oldEnd; oldIdx -= 4)
|
||||
{
|
||||
address = *(__IO uint16_t*)oldIdx;
|
||||
if (address == 0xFFFF || address == SkipAddress)
|
||||
continue; // it's means that power off after write data
|
||||
|
||||
found = 0;
|
||||
for (idx = newPage + 6; idx < newIdx; idx += 4)
|
||||
if ((*(__IO uint16_t*)(idx)) == address)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
if (newIdx < newEnd)
|
||||
{
|
||||
data = (*(__IO uint16_t*)(oldIdx - 2));
|
||||
|
||||
FlashStatus = FLASH_ProgramHalfWord(newIdx, data);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
return FlashStatus;
|
||||
|
||||
FlashStatus = FLASH_ProgramHalfWord(newIdx + 2, address);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
return FlashStatus;
|
||||
|
||||
newIdx += 4;
|
||||
}
|
||||
else
|
||||
return EEPROM_OUT_SIZE;
|
||||
}
|
||||
|
||||
// Erase the old Page: Set old Page status to EEPROM_EEPROM_ERASED status
|
||||
data = EE_CheckErasePage(oldPage, EEPROM_ERASED);
|
||||
if (data != EEPROM_OK)
|
||||
return data;
|
||||
|
||||
// Set new Page status
|
||||
FlashStatus = FLASH_ProgramHalfWord(newPage, EEPROM_VALID_PAGE);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
return FlashStatus;
|
||||
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verify if active page is full and Writes variable in EEPROM.
|
||||
* @param Address: 16 bit virtual address of the variable
|
||||
* @param Data: 16 bit data to be written as variable value
|
||||
* @retval Success or error status:
|
||||
* - FLASH_COMPLETE: on success
|
||||
* - EEPROM_PAGE_FULL: if valid page is full (need page transfer)
|
||||
* - EEPROM_NO_VALID_PAGE: if no valid page was found
|
||||
* - EEPROM_OUT_SIZE: if EEPROM size exceeded
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
uint16_t EE_VerifyPageFullWriteVariable(uint16_t Address, uint16_t Data)
|
||||
{
|
||||
FLASH_Status FlashStatus;
|
||||
uint32_t idx, pageBase, pageEnd, newPage;
|
||||
uint16_t count;
|
||||
|
||||
// Get valid Page for write operation
|
||||
pageBase = EE_FindValidPage();
|
||||
if (pageBase == 0)
|
||||
return EEPROM_NO_VALID_PAGE;
|
||||
|
||||
// Get the valid Page end Address
|
||||
pageEnd = pageBase + PageSize; // Set end of page
|
||||
|
||||
for (idx = pageEnd - 2; idx > pageBase; idx -= 4)
|
||||
{
|
||||
if ((*(__IO uint16_t*)idx) == Address) // Find last value for address
|
||||
{
|
||||
count = (*(__IO uint16_t*)(idx - 2)); // Read last data
|
||||
if (count == Data)
|
||||
return EEPROM_OK;
|
||||
if (count == 0xFFFF)
|
||||
{
|
||||
FlashStatus = FLASH_ProgramHalfWord(idx - 2, Data); // Set variable data
|
||||
if (FlashStatus == FLASH_COMPLETE)
|
||||
return EEPROM_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check each active page address starting from begining
|
||||
for (idx = pageBase + 4; idx < pageEnd; idx += 4)
|
||||
if ((*(__IO uint32_t*)idx) == 0xFFFFFFFF) // Verify if element
|
||||
{ // contents are 0xFFFFFFFF
|
||||
FlashStatus = FLASH_ProgramHalfWord(idx, Data); // Set variable data
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
return FlashStatus;
|
||||
FlashStatus = FLASH_ProgramHalfWord(idx + 2, Address); // Set variable virtual address
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
return FlashStatus;
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Empty slot not found, need page transfer
|
||||
// Calculate unique variables in page
|
||||
count = EE_GetVariablesCount(pageBase, Address) + 1;
|
||||
if (count >= (PageSize / 4 - 1))
|
||||
return EEPROM_OUT_SIZE;
|
||||
|
||||
if (pageBase == PageBase1)
|
||||
newPage = PageBase0; // New page address where variable will be moved to
|
||||
else
|
||||
newPage = PageBase1;
|
||||
|
||||
// Set the new Page status to RECEIVE_DATA status
|
||||
FlashStatus = FLASH_ProgramHalfWord(newPage, EEPROM_RECEIVE_DATA);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
return FlashStatus;
|
||||
|
||||
// Write the variable passed as parameter in the new active page
|
||||
FlashStatus = FLASH_ProgramHalfWord(newPage + 4, Data);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
return FlashStatus;
|
||||
|
||||
FlashStatus = FLASH_ProgramHalfWord(newPage + 6, Address);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
return FlashStatus;
|
||||
|
||||
return EE_PageTransfer(newPage, pageBase, Address);
|
||||
}
|
||||
|
||||
/*EEPROMClass::EEPROMClass(void)
|
||||
{
|
||||
PageBase0 = EEPROM_PAGE0_BASE;
|
||||
PageBase1 = EEPROM_PAGE1_BASE;
|
||||
PageSize = EEPROM_PAGE_SIZE;
|
||||
Status = EEPROM_NOT_INIT;
|
||||
}*/
|
||||
/*
|
||||
uint16_t EEPROM_init(uint32_t pageBase0, uint32_t pageBase1, uint32_t pageSize)
|
||||
{
|
||||
PageBase0 = pageBase0;
|
||||
PageBase1 = pageBase1;
|
||||
PageSize = pageSize;
|
||||
return EEPROM_init();
|
||||
}*/
|
||||
|
||||
uint16_t EEPROM_init(void)
|
||||
{
|
||||
uint16_t status0 = 6, status1 = 6;
|
||||
FLASH_Status FlashStatus;
|
||||
|
||||
FLASH_Unlock();
|
||||
Status = EEPROM_NO_VALID_PAGE;
|
||||
|
||||
status0 = (*(__IO uint16_t *)PageBase0);
|
||||
status1 = (*(__IO uint16_t *)PageBase1);
|
||||
|
||||
switch (status0)
|
||||
{
|
||||
/*
|
||||
Page0 Page1
|
||||
----- -----
|
||||
EEPROM_ERASED EEPROM_VALID_PAGE Page1 valid, Page0 erased
|
||||
EEPROM_RECEIVE_DATA Page1 need set to valid, Page0 erased
|
||||
EEPROM_ERASED make EE_Format
|
||||
any Error: EEPROM_NO_VALID_PAGE
|
||||
*/
|
||||
case EEPROM_ERASED:
|
||||
if (status1 == EEPROM_VALID_PAGE) // Page0 erased, Page1 valid
|
||||
Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED);
|
||||
else if (status1 == EEPROM_RECEIVE_DATA) // Page0 erased, Page1 receive
|
||||
{
|
||||
FlashStatus = FLASH_ProgramHalfWord(PageBase1, EEPROM_VALID_PAGE);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
Status = FlashStatus;
|
||||
else
|
||||
Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED);
|
||||
}
|
||||
else if (status1 == EEPROM_ERASED) // Both in erased state so format EEPROM
|
||||
Status = EEPROM_format();
|
||||
break;
|
||||
/*
|
||||
Page0 Page1
|
||||
----- -----
|
||||
EEPROM_RECEIVE_DATA EEPROM_VALID_PAGE Transfer Page1 to Page0
|
||||
EEPROM_ERASED Page0 need set to valid, Page1 erased
|
||||
any EEPROM_NO_VALID_PAGE
|
||||
*/
|
||||
case EEPROM_RECEIVE_DATA:
|
||||
if (status1 == EEPROM_VALID_PAGE) // Page0 receive, Page1 valid
|
||||
Status = EE_PageTransfer(PageBase0, PageBase1, 0xFFFF);
|
||||
else if (status1 == EEPROM_ERASED) // Page0 receive, Page1 erased
|
||||
{
|
||||
Status = EE_CheckErasePage(PageBase1, EEPROM_ERASED);
|
||||
if (Status == EEPROM_OK)
|
||||
{
|
||||
FlashStatus = FLASH_ProgramHalfWord(PageBase0, EEPROM_VALID_PAGE);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
Status = FlashStatus;
|
||||
else
|
||||
Status = EEPROM_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/*
|
||||
Page0 Page1
|
||||
----- -----
|
||||
EEPROM_VALID_PAGE EEPROM_VALID_PAGE Error: EEPROM_NO_VALID_PAGE
|
||||
EEPROM_RECEIVE_DATA Transfer Page0 to Page1
|
||||
any Page0 valid, Page1 erased
|
||||
*/
|
||||
case EEPROM_VALID_PAGE:
|
||||
if (status1 == EEPROM_VALID_PAGE) // Both pages valid
|
||||
Status = EEPROM_NO_VALID_PAGE;
|
||||
else if (status1 == EEPROM_RECEIVE_DATA)
|
||||
Status = EE_PageTransfer(PageBase1, PageBase0, 0xFFFF);
|
||||
else
|
||||
Status = EE_CheckErasePage(PageBase1, EEPROM_ERASED);
|
||||
break;
|
||||
/*
|
||||
Page0 Page1
|
||||
----- -----
|
||||
any EEPROM_VALID_PAGE Page1 valid, Page0 erased
|
||||
EEPROM_RECEIVE_DATA Page1 valid, Page0 erased
|
||||
any EEPROM_NO_VALID_PAGE
|
||||
*/
|
||||
default:
|
||||
if (status1 == EEPROM_VALID_PAGE)
|
||||
Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED); // Check/Erase Page0
|
||||
else if (status1 == EEPROM_RECEIVE_DATA)
|
||||
{
|
||||
FlashStatus = FLASH_ProgramHalfWord(PageBase1, EEPROM_VALID_PAGE);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
Status = FlashStatus;
|
||||
else
|
||||
Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases PAGE0 and PAGE1 and writes EEPROM_VALID_PAGE / 0 header to PAGE0
|
||||
* @param PAGE0 and PAGE1 base addresses
|
||||
* @retval Status of the last operation (Flash write or erase) done during EEPROM formating
|
||||
*/
|
||||
uint16_t EEPROM_format(void)
|
||||
{
|
||||
uint16_t status;
|
||||
FLASH_Status FlashStatus;
|
||||
|
||||
FLASH_Unlock();
|
||||
|
||||
// Erase Page0
|
||||
status = EE_CheckErasePage(PageBase0, EEPROM_VALID_PAGE);
|
||||
if (status != EEPROM_OK)
|
||||
return status;
|
||||
if ((*(__IO uint16_t*)PageBase0) == EEPROM_ERASED)
|
||||
{
|
||||
// Set Page0 as valid page: Write VALID_PAGE at Page0 base address
|
||||
FlashStatus = FLASH_ProgramHalfWord(PageBase0, EEPROM_VALID_PAGE);
|
||||
if (FlashStatus != FLASH_COMPLETE)
|
||||
return FlashStatus;
|
||||
}
|
||||
// Erase Page1
|
||||
return EE_CheckErasePage(PageBase1, EEPROM_ERASED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the erase counter for current page
|
||||
* @param Data: Global variable contains the read variable value
|
||||
* @retval Success or error status:
|
||||
* - EEPROM_OK: if erases counter return.
|
||||
* - EEPROM_NO_VALID_PAGE: if no valid page was found.
|
||||
*/
|
||||
uint16_t EEPROM_erases(uint16_t *Erases)
|
||||
{
|
||||
uint32_t pageBase;
|
||||
if (Status != EEPROM_OK)
|
||||
if (EEPROM_init() != EEPROM_OK)
|
||||
return Status;
|
||||
|
||||
// Get active Page for read operation
|
||||
pageBase = EE_FindValidPage();
|
||||
if (pageBase == 0)
|
||||
return EEPROM_NO_VALID_PAGE;
|
||||
|
||||
*Erases = (*(__IO uint16_t*)pageBase+2);
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last stored variable data, if found,
|
||||
* which correspond to the passed virtual address
|
||||
* @param Address: Variable virtual address
|
||||
* @retval Data for variable or EEPROM_DEFAULT_DATA, if any errors
|
||||
*/
|
||||
/*
|
||||
uint16_t EEPROM_read (uint16_t Address)
|
||||
{
|
||||
uint16_t data;
|
||||
EEPROM_read(Address, &data);
|
||||
return data;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* @brief Returns the last stored variable data, if found,
|
||||
* which correspond to the passed virtual address
|
||||
* @param Address: Variable virtual address
|
||||
* @param Data: Pointer to data variable
|
||||
* @retval Success or error status:
|
||||
* - EEPROM_OK: if variable was found
|
||||
* - EEPROM_BAD_ADDRESS: if the variable was not found
|
||||
* - EEPROM_NO_VALID_PAGE: if no valid page was found.
|
||||
*/
|
||||
uint16_t EEPROM_read(uint16_t Address, uint16_t *Data)
|
||||
{
|
||||
uint32_t pageBase, pageEnd;
|
||||
|
||||
// Set default data (empty EEPROM)
|
||||
*Data = EEPROM_DEFAULT_DATA;
|
||||
|
||||
if (Status == EEPROM_NOT_INIT)
|
||||
if (EEPROM_init() != EEPROM_OK)
|
||||
return Status;
|
||||
|
||||
// Get active Page for read operation
|
||||
pageBase = EE_FindValidPage();
|
||||
if (pageBase == 0)
|
||||
return EEPROM_NO_VALID_PAGE;
|
||||
|
||||
// Get the valid Page end Address
|
||||
pageEnd = pageBase + ((uint32_t)(PageSize - 2));
|
||||
|
||||
// Check each active page address starting from end
|
||||
for (pageBase += 6; pageEnd >= pageBase; pageEnd -= 4)
|
||||
if ((*(__IO uint16_t*)pageEnd) == Address) // Compare the read address with the virtual address
|
||||
{
|
||||
*Data = (*(__IO uint16_t*)(pageEnd - 2)); // Get content of Address-2 which is variable value
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
// Return ReadStatus value: (0: variable exist, 1: variable doesn't exist)
|
||||
return EEPROM_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes/upadtes variable data in EEPROM.
|
||||
* @param VirtAddress: Variable virtual address
|
||||
* @param Data: 16 bit data to be written
|
||||
* @retval Success or error status:
|
||||
* - FLASH_COMPLETE: on success
|
||||
* - EEPROM_BAD_ADDRESS: if address = 0xFFFF
|
||||
* - EEPROM_PAGE_FULL: if valid page is full
|
||||
* - EEPROM_NO_VALID_PAGE: if no valid page was found
|
||||
* - EEPROM_OUT_SIZE: if no empty EEPROM variables
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
uint16_t EEPROM_write(uint16_t Address, uint16_t Data)
|
||||
{
|
||||
if (Status == EEPROM_NOT_INIT)
|
||||
if (EEPROM_init() != EEPROM_OK)
|
||||
return Status;
|
||||
|
||||
if (Address == 0xFFFF)
|
||||
return EEPROM_BAD_ADDRESS;
|
||||
|
||||
// Write the variable virtual address and value in the EEPROM
|
||||
uint16_t status = EE_VerifyPageFullWriteVariable(Address, Data);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes/upadtes variable data in EEPROM.
|
||||
The value is written only if differs from the one already saved at the same address.
|
||||
* @param VirtAddress: Variable virtual address
|
||||
* @param Data: 16 bit data to be written
|
||||
* @retval Success or error status:
|
||||
* - EEPROM_SAME_VALUE: If new Data matches existing EEPROM Data
|
||||
* - FLASH_COMPLETE: on success
|
||||
* - EEPROM_BAD_ADDRESS: if address = 0xFFFF
|
||||
* - EEPROM_PAGE_FULL: if valid page is full
|
||||
* - EEPROM_NO_VALID_PAGE: if no valid page was found
|
||||
* - EEPROM_OUT_SIZE: if no empty EEPROM variables
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
uint16_t EEPROM_update(uint16_t Address, uint16_t Data)
|
||||
{
|
||||
uint16_t temp;
|
||||
EEPROM_read(Address, &temp);
|
||||
if (Address == Data)
|
||||
return EEPROM_SAME_VALUE;
|
||||
else
|
||||
return EEPROM_write(Address, Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return number of variable
|
||||
* @retval Number of variables
|
||||
*/
|
||||
uint16_t EEPROM_count(uint16_t *Count)
|
||||
{
|
||||
if (Status == EEPROM_NOT_INIT)
|
||||
if (EEPROM_init() != EEPROM_OK)
|
||||
return Status;
|
||||
|
||||
// Get valid Page for write operation
|
||||
uint32_t pageBase = EE_FindValidPage();
|
||||
if (pageBase == 0)
|
||||
return EEPROM_NO_VALID_PAGE; // No valid page, return max. numbers
|
||||
|
||||
*Count = EE_GetVariablesCount(pageBase, 0xFFFF);
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
uint16_t EEPROM_maxcount(void)
|
||||
{
|
||||
return ((PageSize / 4)-1);
|
||||
}
|
||||
|
||||
|
||||
uint8_t eeprom_read_byte (const uint8_t *Address)
|
||||
{
|
||||
const uint16_t p = (const uint32_t) Address;
|
||||
uint16_t temp;
|
||||
EEPROM_read(p, &temp);
|
||||
return (uint8_t) temp;
|
||||
}
|
||||
|
||||
void eeprom_write_byte (uint8_t *Address, uint8_t Value)
|
||||
{
|
||||
uint16_t p = (uint32_t) Address;
|
||||
EEPROM_write(p, (uint16_t) Value);
|
||||
}
|
||||
|
||||
void eeprom_update_byte (uint8_t *Address, uint8_t Value)
|
||||
{
|
||||
uint16_t p = (uint32_t) Address;
|
||||
EEPROM_update(p, (uint16_t) Value);
|
||||
}
|
||||
|
||||
uint16_t eeprom_read_word (const uint16_t *Address)
|
||||
{
|
||||
const uint16_t p = (const uint32_t) Address;
|
||||
uint16_t temp;
|
||||
EEPROM_read(p, &temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
void eeprom_write_word (uint16_t *Address, uint16_t Value)
|
||||
{
|
||||
uint16_t p = (uint32_t) Address;
|
||||
EEPROM_write(p, Value);
|
||||
}
|
||||
|
||||
void eeprom_update_word (uint16_t *Address, uint16_t Value)
|
||||
{
|
||||
uint16_t p = (uint32_t) Address;
|
||||
EEPROM_update(p, Value);
|
||||
}
|
||||
|
||||
uint32_t eeprom_read_dword (const uint32_t *Address)
|
||||
{
|
||||
const uint16_t p = (const uint32_t) Address;
|
||||
uint16_t temp1, temp2;
|
||||
EEPROM_read(p, &temp1);
|
||||
EEPROM_read(p + 1, &temp2);
|
||||
return temp1 | (temp2 << 16);
|
||||
}
|
||||
|
||||
void eeprom_write_dword (uint32_t *Address, uint32_t Value)
|
||||
{
|
||||
uint16_t temp = (uint16_t) Value;
|
||||
uint16_t p = (uint32_t) Address;
|
||||
EEPROM_write(p, temp);
|
||||
temp = (uint16_t) (Value >> 16);
|
||||
EEPROM_write(p + 1, temp);
|
||||
}
|
||||
|
||||
void eeprom_update_dword (uint32_t *Address, uint32_t Value)
|
||||
{
|
||||
uint16_t temp = (uint16_t) Value;
|
||||
uint16_t p = (uint32_t) Address;
|
||||
EEPROM_update(p, temp);
|
||||
temp = (uint16_t) (Value >> 16);
|
||||
EEPROM_update(p + 1, temp);
|
||||
}
|
89
tmk_core/common/chibios/eeprom_stm32.h
Executable file
89
tmk_core/common/chibios/eeprom_stm32.h
Executable file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* This software is experimental and a work in progress.
|
||||
* Under no circumstances should these files be used in relation to any critical system(s).
|
||||
* Use of these files is at your own risk.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and
|
||||
* https://github.com/leaflabs/libmaple
|
||||
*
|
||||
* Modifications for QMK and STM32F303 by Yiancar
|
||||
*/
|
||||
|
||||
// This file must be modified if the MCU is not defined below.
|
||||
// This library also assumes that the pages are not used by the firmware.
|
||||
|
||||
#ifndef __EEPROM_H
|
||||
#define __EEPROM_H
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "flash_stm32.h"
|
||||
|
||||
// HACK ALERT. This definition may not match your processor
|
||||
// To Do. Work out correct value for EEPROM_PAGE_SIZE on the STM32F103CT6 etc
|
||||
#define MCU_STM32F303CC
|
||||
|
||||
#ifndef EEPROM_PAGE_SIZE
|
||||
#if defined (MCU_STM32F103RB)
|
||||
#define EEPROM_PAGE_SIZE (uint16_t)0x400 /* Page size = 1KByte */
|
||||
#elif defined (MCU_STM32F103ZE) || defined (MCU_STM32F103RE) || defined (MCU_STM32F103RD) || defined (MCU_STM32F303CC)
|
||||
#define EEPROM_PAGE_SIZE (uint16_t)0x800 /* Page size = 2KByte */
|
||||
#else
|
||||
#error "No MCU type specified. Add something like -DMCU_STM32F103RB to your compiler arguments (probably in a Makefile)."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EEPROM_START_ADDRESS
|
||||
#if defined (MCU_STM32F103RB)
|
||||
#define EEPROM_START_ADDRESS ((uint32_t)(0x8000000 + 128 * 1024 - 2 * EEPROM_PAGE_SIZE))
|
||||
#elif defined (MCU_STM32F103ZE) || defined (MCU_STM32F103RE)
|
||||
#define EEPROM_START_ADDRESS ((uint32_t)(0x8000000 + 512 * 1024 - 2 * EEPROM_PAGE_SIZE))
|
||||
#elif defined (MCU_STM32F103RD)
|
||||
#define EEPROM_START_ADDRESS ((uint32_t)(0x8000000 + 384 * 1024 - 2 * EEPROM_PAGE_SIZE))
|
||||
#elif defined (MCU_STM32F303CC)
|
||||
#define EEPROM_START_ADDRESS ((uint32_t)(0x8000000 + 250 * 1024 - 2 * EEPROM_PAGE_SIZE))
|
||||
#else
|
||||
#error "No MCU type specified. Add something like -DMCU_STM32F103RB to your compiler arguments (probably in a Makefile)."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Pages 0 and 1 base and end addresses */
|
||||
#define EEPROM_PAGE0_BASE ((uint32_t)(EEPROM_START_ADDRESS + 0x000))
|
||||
#define EEPROM_PAGE1_BASE ((uint32_t)(EEPROM_START_ADDRESS + EEPROM_PAGE_SIZE))
|
||||
|
||||
/* Page status definitions */
|
||||
#define EEPROM_ERASED ((uint16_t)0xFFFF) /* PAGE is empty */
|
||||
#define EEPROM_RECEIVE_DATA ((uint16_t)0xEEEE) /* PAGE is marked to receive data */
|
||||
#define EEPROM_VALID_PAGE ((uint16_t)0x0000) /* PAGE containing valid data */
|
||||
|
||||
/* Page full define */
|
||||
enum uint16_t
|
||||
{
|
||||
EEPROM_OK = ((uint16_t)0x0000),
|
||||
EEPROM_OUT_SIZE = ((uint16_t)0x0081),
|
||||
EEPROM_BAD_ADDRESS = ((uint16_t)0x0082),
|
||||
EEPROM_BAD_FLASH = ((uint16_t)0x0083),
|
||||
EEPROM_NOT_INIT = ((uint16_t)0x0084),
|
||||
EEPROM_SAME_VALUE = ((uint16_t)0x0085),
|
||||
EEPROM_NO_VALID_PAGE = ((uint16_t)0x00AB)
|
||||
};
|
||||
|
||||
#define EEPROM_DEFAULT_DATA 0xFFFF
|
||||
|
||||
uint16_t EEPROM_init(void);
|
||||
uint16_t EEPROM_format(void);
|
||||
uint16_t EEPROM_erases(uint16_t *);
|
||||
uint16_t EEPROM_read (uint16_t address, uint16_t *data);
|
||||
uint16_t EEPROM_write(uint16_t address, uint16_t data);
|
||||
uint16_t EEPROM_update(uint16_t address, uint16_t data);
|
||||
uint16_t EEPROM_count(uint16_t *);
|
||||
uint16_t EEPROM_maxcount(void);
|
||||
|
||||
#endif /* __EEPROM_H */
|
180
tmk_core/common/chibios/flash_stm32.c
Executable file
180
tmk_core/common/chibios/flash_stm32.c
Executable file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* This software is experimental and a work in progress.
|
||||
* Under no circumstances should these files be used in relation to any critical system(s).
|
||||
* Use of these files is at your own risk.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and
|
||||
* https://github.com/leaflabs/libmaple
|
||||
*
|
||||
* Modifications for QMK and STM32F303 by Yiancar
|
||||
*/
|
||||
|
||||
#define STM32F303xC
|
||||
|
||||
#include "stm32f3xx.h"
|
||||
#include "flash_stm32.h"
|
||||
|
||||
#define FLASH_KEY1 ((uint32_t)0x45670123)
|
||||
#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)
|
||||
|
||||
/* Delay definition */
|
||||
#define EraseTimeout ((uint32_t)0x00000FFF)
|
||||
#define ProgramTimeout ((uint32_t)0x0000001F)
|
||||
|
||||
#define ASSERT(exp) (void)((0))
|
||||
|
||||
/**
|
||||
* @brief Inserts a time delay.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void delay(void)
|
||||
{
|
||||
__IO uint32_t i = 0;
|
||||
for(i = 0xFF; i != 0; i--) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the FLASH Status.
|
||||
* @param None
|
||||
* @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
|
||||
* FLASH_ERROR_WRP or FLASH_COMPLETE
|
||||
*/
|
||||
FLASH_Status FLASH_GetStatus(void)
|
||||
{
|
||||
if ((FLASH->SR & FLASH_SR_BSY) == FLASH_SR_BSY)
|
||||
return FLASH_BUSY;
|
||||
|
||||
if ((FLASH->SR & FLASH_SR_PGERR) != 0)
|
||||
return FLASH_ERROR_PG;
|
||||
|
||||
if ((FLASH->SR & FLASH_SR_WRPERR) != 0 )
|
||||
return FLASH_ERROR_WRP;
|
||||
|
||||
if ((FLASH->SR & FLASH_OBR_OPTERR) != 0 )
|
||||
return FLASH_ERROR_OPT;
|
||||
|
||||
return FLASH_COMPLETE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits for a Flash operation to complete or a TIMEOUT to occur.
|
||||
* @param Timeout: FLASH progamming Timeout
|
||||
* @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
|
||||
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
|
||||
*/
|
||||
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)
|
||||
{
|
||||
FLASH_Status status;
|
||||
|
||||
/* Check for the Flash Status */
|
||||
status = FLASH_GetStatus();
|
||||
/* Wait for a Flash operation to complete or a TIMEOUT to occur */
|
||||
while ((status == FLASH_BUSY) && (Timeout != 0x00))
|
||||
{
|
||||
delay();
|
||||
status = FLASH_GetStatus();
|
||||
Timeout--;
|
||||
}
|
||||
if (Timeout == 0)
|
||||
status = FLASH_TIMEOUT;
|
||||
/* Return the operation status */
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases a specified FLASH page.
|
||||
* @param Page_Address: The page address to be erased.
|
||||
* @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
|
||||
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
|
||||
*/
|
||||
FLASH_Status FLASH_ErasePage(uint32_t Page_Address)
|
||||
{
|
||||
FLASH_Status status = FLASH_COMPLETE;
|
||||
/* Check the parameters */
|
||||
ASSERT(IS_FLASH_ADDRESS(Page_Address));
|
||||
/* Wait for last operation to be completed */
|
||||
status = FLASH_WaitForLastOperation(EraseTimeout);
|
||||
|
||||
if(status == FLASH_COMPLETE)
|
||||
{
|
||||
/* if the previous operation is completed, proceed to erase the page */
|
||||
FLASH->CR |= FLASH_CR_PER;
|
||||
FLASH->AR = Page_Address;
|
||||
FLASH->CR |= FLASH_CR_STRT;
|
||||
|
||||
/* Wait for last operation to be completed */
|
||||
status = FLASH_WaitForLastOperation(EraseTimeout);
|
||||
if(status != FLASH_TIMEOUT)
|
||||
{
|
||||
/* if the erase operation is completed, disable the PER Bit */
|
||||
FLASH->CR &= ~FLASH_CR_PER;
|
||||
}
|
||||
FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR);
|
||||
}
|
||||
/* Return the Erase Status */
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Programs a half word at a specified address.
|
||||
* @param Address: specifies the address to be programmed.
|
||||
* @param Data: specifies the data to be programmed.
|
||||
* @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
|
||||
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
|
||||
*/
|
||||
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
|
||||
{
|
||||
FLASH_Status status = FLASH_BAD_ADDRESS;
|
||||
|
||||
if (IS_FLASH_ADDRESS(Address))
|
||||
{
|
||||
/* Wait for last operation to be completed */
|
||||
status = FLASH_WaitForLastOperation(ProgramTimeout);
|
||||
if(status == FLASH_COMPLETE)
|
||||
{
|
||||
/* if the previous operation is completed, proceed to program the new data */
|
||||
FLASH->CR |= FLASH_CR_PG;
|
||||
*(__IO uint16_t*)Address = Data;
|
||||
/* Wait for last operation to be completed */
|
||||
status = FLASH_WaitForLastOperation(ProgramTimeout);
|
||||
if(status != FLASH_TIMEOUT)
|
||||
{
|
||||
/* if the program operation is completed, disable the PG Bit */
|
||||
FLASH->CR &= ~FLASH_CR_PG;
|
||||
}
|
||||
FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unlocks the FLASH Program Erase Controller.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void FLASH_Unlock(void)
|
||||
{
|
||||
/* Authorize the FPEC Access */
|
||||
FLASH->KEYR = FLASH_KEY1;
|
||||
FLASH->KEYR = FLASH_KEY2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Locks the FLASH Program Erase Controller.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void FLASH_Lock(void)
|
||||
{
|
||||
/* Set the Lock Bit to lock the FPEC and the FCR */
|
||||
FLASH->CR |= FLASH_CR_LOCK;
|
||||
}
|
53
tmk_core/common/chibios/flash_stm32.h
Executable file
53
tmk_core/common/chibios/flash_stm32.h
Executable file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This software is experimental and a work in progress.
|
||||
* Under no circumstances should these files be used in relation to any critical system(s).
|
||||
* Use of these files is at your own risk.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and
|
||||
* https://github.com/leaflabs/libmaple
|
||||
*
|
||||
* Modifications for QMK and STM32F303 by Yiancar
|
||||
*/
|
||||
|
||||
#ifndef __FLASH_STM32_H
|
||||
#define __FLASH_STM32_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FLASH_BUSY = 1,
|
||||
FLASH_ERROR_PG,
|
||||
FLASH_ERROR_WRP,
|
||||
FLASH_ERROR_OPT,
|
||||
FLASH_COMPLETE,
|
||||
FLASH_TIMEOUT,
|
||||
FLASH_BAD_ADDRESS
|
||||
} FLASH_Status;
|
||||
|
||||
#define IS_FLASH_ADDRESS(ADDRESS) (((ADDRESS) >= 0x08000000) && ((ADDRESS) < 0x0807FFFF))
|
||||
|
||||
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
|
||||
FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
|
||||
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
|
||||
|
||||
void FLASH_Unlock(void);
|
||||
void FLASH_Lock(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FLASH_STM32_H */
|
@@ -3,12 +3,20 @@
|
||||
#include "eeprom.h"
|
||||
#include "eeconfig.h"
|
||||
|
||||
#ifdef STM32F303xC
|
||||
#include "hal.h"
|
||||
#include "eeprom_stm32.h"
|
||||
#endif
|
||||
|
||||
/** \brief eeconfig initialization
|
||||
*
|
||||
* FIXME: needs doc
|
||||
*/
|
||||
void eeconfig_init(void)
|
||||
{
|
||||
#ifdef STM32F303xC
|
||||
EEPROM_format();
|
||||
#endif
|
||||
eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
|
||||
eeprom_update_byte(EECONFIG_DEBUG, 0);
|
||||
eeprom_update_byte(EECONFIG_DEFAULT_LAYER, 0);
|
||||
@@ -43,6 +51,9 @@ void eeconfig_enable(void)
|
||||
*/
|
||||
void eeconfig_disable(void)
|
||||
{
|
||||
#ifdef STM32F303xC
|
||||
EEPROM_format();
|
||||
#endif
|
||||
eeprom_update_word(EECONFIG_MAGIC, 0xFFFF);
|
||||
}
|
||||
|
||||
|
@@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEED
|
||||
|
||||
/* eeprom parameteter address */
|
||||
#if !defined(STM32F303xC)
|
||||
#define EECONFIG_MAGIC (uint16_t *)0
|
||||
#define EECONFIG_DEBUG (uint8_t *)2
|
||||
#define EECONFIG_DEFAULT_LAYER (uint8_t *)3
|
||||
@@ -38,6 +39,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// EEHANDS for two handed boards
|
||||
#define EECONFIG_HANDEDNESS (uint8_t *)14
|
||||
|
||||
#else
|
||||
/* STM32F3 uses 16byte block. Reconfigure memory map */
|
||||
#define EECONFIG_MAGIC (uint16_t *)0
|
||||
#define EECONFIG_DEBUG (uint8_t *)1
|
||||
#define EECONFIG_DEFAULT_LAYER (uint8_t *)2
|
||||
#define EECONFIG_KEYMAP (uint8_t *)3
|
||||
#define EECONFIG_MOUSEKEY_ACCEL (uint8_t *)4
|
||||
#define EECONFIG_BACKLIGHT (uint8_t *)5
|
||||
#define EECONFIG_AUDIO (uint8_t *)6
|
||||
#define EECONFIG_RGBLIGHT (uint32_t *)7
|
||||
#define EECONFIG_UNICODEMODE (uint8_t *)9
|
||||
#define EECONFIG_STENOMODE (uint8_t *)10
|
||||
// EEHANDS for two handed boards
|
||||
#define EECONFIG_HANDEDNESS (uint8_t *)11
|
||||
#endif
|
||||
|
||||
/* debug bit */
|
||||
#define EECONFIG_DEBUG_ENABLE (1<<0)
|
||||
|
@@ -44,6 +44,9 @@
|
||||
#ifdef MIDI_ENABLE
|
||||
#include "qmk_midi.h"
|
||||
#endif
|
||||
#ifdef STM32F303xC
|
||||
#include "eeprom_stm32.h"
|
||||
#endif
|
||||
#include "suspend.h"
|
||||
#include "wait.h"
|
||||
|
||||
@@ -109,6 +112,10 @@ int main(void) {
|
||||
halInit();
|
||||
chSysInit();
|
||||
|
||||
#ifdef STM32F303xC
|
||||
EEPROM_init();
|
||||
#endif
|
||||
|
||||
// TESTING
|
||||
// chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
|
||||
|
||||
|
Reference in New Issue
Block a user