cpu/msp430_common: add flashpage_raw support

This commit is contained in:
fjmolinas 2019-08-04 11:39:27 +02:00 committed by Francisco Molina
parent 291727c9e7
commit 5368415c9a
3 changed files with 75 additions and 22 deletions

View File

@ -1,2 +1,3 @@
FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_raw
FEATURES_PROVIDED += periph_pm

View File

@ -41,6 +41,13 @@ extern "C" {
#define CPU_FLASH_BASE (0x8000)
#define FLASHPAGE_NUMOF (64U) /* 32K */
#endif
/* The minimum block size which can be written is 1B. However, the erase
* block is always FLASHPAGE_SIZE.
*/
#define FLASHPAGE_RAW_BLOCKSIZE (1U)
/* Writing should be always 2 byte aligned */
#define FLASHPAGE_RAW_ALIGNMENT (2U)
/** @} */
/**

View File

@ -24,34 +24,79 @@
#include "irq.h"
#include "periph/flashpage.h"
static inline int _unlock(void)
{
int state;
state = irq_disable();
FCTL3 = FWKEY;
while (FCTL3 & BUSY) {}
return state;
}
static inline void _lock(int state)
{
FCTL3 = (FWKEY | LOCK);
irq_restore(state);
}
static inline void _erase(uint16_t *page_addr)
{
/* disable interrupts and unlock flash */
int state = _unlock();
/* erase page */
FCTL1 = (FWKEY | ERASE);
*page_addr = 0;
while (FCTL3 & BUSY) {}
/* lock flash and re-enable interrupts */
_lock(state);
}
void flashpage_write_raw(void *target_addr, const void *data, size_t len)
{
/* assert multiples of FLASHPAGE_RAW_BLOCKSIZE are written and no less of
that length. */
assert(!(len % FLASHPAGE_RAW_BLOCKSIZE));
/* ensure writes are aligned */
assert(!(((unsigned)target_addr % FLASHPAGE_RAW_ALIGNMENT) ||
((unsigned)data % FLASHPAGE_RAW_ALIGNMENT)));
/* ensure the length doesn't exceed the actual flash size */
assert(((unsigned)target_addr + len) <=
(CPU_FLASH_BASE + (FLASHPAGE_SIZE * FLASHPAGE_NUMOF)));
uint8_t *page_addr = target_addr;
const uint8_t *data_addr = data;
/* disable interrupts and unlock flash */
int state = _unlock();
/* enable write access, and write*/
FCTL1 = (FWKEY | WRT);
for (unsigned i = 0; i < len; i++) {
*(page_addr++) = *(data_addr++);
while (!(FCTL3 & WAIT)) {}
}
/* disable write access */
FCTL1 = (FWKEY);
/* lock flash and re-enable interrupts */
_lock(state);
}
void flashpage_write(int page, const void *data)
{
assert((unsigned) page < FLASHPAGE_NUMOF);
const uint8_t *src = data;
uint8_t *dst = (uint8_t *)flashpage_addr(page);
unsigned istate;
/* disable interrupts and unlock flash */
istate = irq_disable();
FCTL3 = FWKEY;
while (FCTL3 & BUSY) {}
uint16_t *page_addr = (uint16_t *)flashpage_addr(page);
/* erase page */
FCTL1 = (FWKEY | ERASE);
*dst = 0; /* erases the page */
while (FCTL3 & BUSY) {}
_erase(page_addr);
if (data) {
FCTL1 = (FWKEY | WRT);
for (unsigned i = 0; i < FLASHPAGE_SIZE; i++) {
*(dst++) = *(src++);
while (!(FCTL3 & WAIT)) {}
/* write page */
if (data != NULL) {
flashpage_write_raw(page_addr, data, FLASHPAGE_SIZE);
}
}
/* lock flash and re-enable interrupts */
FCTL1 = (FWKEY);
FCTL3 = (FWKEY | LOCK);
irq_restore(istate);
}