Skip to content
Snippets Groups Projects
Unverified Commit 43e972fc authored by Kaspar Schleiser's avatar Kaspar Schleiser Committed by GitHub
Browse files

Merge pull request #7970 from kYc0o/add_flashpage_write_raw

periph/flashpage: add flashpage_write_raw interface
parents 24476e08 202c9e17
No related branches found
No related tags found
No related merge requests found
FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_raw
-include $(RIOTCPU)/cortexm_common/Makefile.features
......@@ -42,9 +42,15 @@ extern "C" {
* @{
*/
/* a flashpage in RIOT is mapped to a flash row on the SAM0s */
#define FLASHPAGE_SIZE (256U)
#define FLASHPAGE_SIZE (256U)
/* one SAM0 row contains 4 SAM0 pages -> 4x the amount of RIOT flashpages */
#define FLASHPAGE_NUMOF (FLASH_NB_OF_PAGES / 4)
#define FLASHPAGE_NUMOF (FLASH_NB_OF_PAGES / 4)
/* The minimum block size which can be written is 16B. However, the erase
* block is always FLASHPAGE_SIZE (SAM0 row).
*/
#define FLASHPAGE_RAW_BLOCKSIZE (16)
/* Writing should be always 4 byte aligned */
#define FLASHPAGE_RAW_ALIGNMENT (4)
/** @} */
#ifdef __cplusplus
......
......@@ -17,7 +17,7 @@
* The sam0 has its flash memory organized in pages and rows, where each row
* consists of 4 pages. While pages are writable one at a time, it is only
* possible to delete a complete row. This implementation abstracts this
* behavior by only writing complete rows at a time, so the FLASH_PAGE_SIZE we
* behavior by only writing complete rows at a time, so the FLASHPAGE_SIZE we
* use in RIOT is actually the row size as specified in the datasheet.
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
......@@ -25,18 +25,15 @@
* @}
*/
#include <assert.h>
#include "cpu.h"
#include "assert.h"
#include "periph/flashpage.h"
#define NVMCTRL_PAC_BIT (0x00000002)
void flashpage_write(int page, void *data)
static void _unlock(void)
{
assert(page < FLASHPAGE_NUMOF);
uint32_t *page_addr = (uint32_t *)flashpage_addr(page);
/* remove peripheral access lock for the NVMCTRL peripheral */
#ifdef CPU_FAM_SAML21
PAC->WRCTRL.reg = (PAC_WRCTRL_KEY_CLR | ID_NVMCTRL);
......@@ -45,19 +42,68 @@ void flashpage_write(int page, void *data)
PAC1->WPCLR.reg = NVMCTRL_PAC_BIT;
}
#endif
}
static void _lock(void)
{
/* put peripheral access lock for the NVMCTRL peripheral */
#ifdef CPU_FAM_SAML21
PAC->WRCTRL.reg = (PAC_WRCTRL_KEY_SET | ID_NVMCTRL);
#else
if (PAC1->WPCLR.reg & NVMCTRL_PAC_BIT) {
PAC1->WPSET.reg = NVMCTRL_PAC_BIT;
}
#endif
}
void flashpage_write_raw(void *target_addr, void *data, size_t len)
{
/* The actual minimal block size for writing is 16B, thus we
* assert we write on multiples and no less of that length.
*/
assert(!(len % FLASHPAGE_RAW_BLOCKSIZE));
/* ensure 4 byte aligned writes */
assert(!(((unsigned)target_addr % FLASHPAGE_RAW_ALIGNMENT) ||
((unsigned)data % FLASHPAGE_RAW_ALIGNMENT)));
/* ensure the length doesn't exceed the actual flash size */
assert(((uint8_t*)target_addr + len) <
(CPU_FLASH_BASE + (FLASHPAGE_SIZE * FLASHPAGE_NUMOF)));
uint32_t *dst = (uint32_t *)target_addr;
uint32_t *data_addr = (uint32_t *)data;
/* write 4 bytes in one go */
len /= 4;
_unlock();
NVMCTRL->CTRLA.reg = (NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC);
for (unsigned i = 0; i < len; i++) {
*dst++ = *data_addr++;
}
NVMCTRL->CTRLA.reg = (NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP);
_lock();
}
void flashpage_write(int page, void *data)
{
assert(page < FLASHPAGE_NUMOF);
uint32_t *page_addr = (uint32_t *)flashpage_addr(page);
/* erase given page (the ADDR register uses 16-bit addresses) */
_unlock();
NVMCTRL->ADDR.reg = (((uint32_t)page_addr) >> 1);
NVMCTRL->CTRLA.reg = (NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER);
while (!NVMCTRL->INTFLAG.bit.READY) {}
_lock();
/* write data to page */
if (data != NULL) {
uint32_t *data_addr = (uint32_t *)data;
NVMCTRL->CTRLA.reg = (NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC);
for (unsigned i = 0; i < (FLASHPAGE_SIZE / 4); i++) {
*page_addr++ = data_addr[i];
}
NVMCTRL->CTRLA.reg = (NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP);
flashpage_write_raw(page_addr, data, FLASHPAGE_SIZE);
}
}
/*
* Copyright (C) 2016 Freie Universität Berlin
* 2017 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
......@@ -28,6 +29,9 @@
* @brief Low-level flash page peripheral driver interface
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Francisco Acosta <francisco.acosta@inria.fr>
*
*/
#ifndef PERIPH_FLASHPAGE_H
......@@ -47,8 +51,30 @@ extern "C" {
#ifndef CPU_FLASH_BASE
#define CPU_FLASH_BASE (0)
#endif
/**
* @def FLASHPAGE_RAW_BLOCKSIZE
*
* @brief For raw writings to the flash, this constant must define the
* minimum write length allowed by the MCU.
*/
#ifdef DOXYGEN
#define FLASHPAGE_RAW_BLOCKSIZE
#endif
/**
* @def FLASHPAGE_RAW_ALIGNMENT
*
* @brief The buffers to be written to the flash MUST be aligned, as well as
* the address on which the buffer is written to the flash. This variable
* must be defined for that purpose, according to the MCU align
* requirements.
*/
#ifdef DOXYGEN
#define FLASHPAGE_RAW_ALIGNMENT
#endif
/**
* @def FLASHPAGE_SIZE
*
* @brief Make sure the page size and the number of pages is defined
*/
#ifndef FLASHPAGE_SIZE
......@@ -101,16 +127,39 @@ static inline int flashpage_page(void *addr)
* @brief Write the given page with the given data
*
* @param[in] page page to write
* @param[in] data data to write to the page, MUST be @p FLASHPAGE_SIZE
* @param[in] data data to write to the page, MUST be FLASHPAGE_SIZE
* byte. Set to NULL for page erase only.
*/
void flashpage_write(int page, void *data);
/**
* @brief Write any number of data bytes to a given location in the
* flash memory
*
* @warning Make sure the targeted memory area is erased before calling
* this function
*
* Both target address and data address must be aligned to
* FLASHPAGE_RAW_ALIGN. @p len must be a multiple of FLASHPAGE_RAW_BLOCKSIZE.
* This function doesn't erase any area in flash, thus be sure the targeted
* memory area is erased before writing on it (using the flashpage_write function).
*
* @param[in] target_addr address in flash to write to. MUST be aligned
* to FLASHPAGE_RAW_ALIGNMENT.
* @param[in] data data to write to the address. MUST be aligned
* to FLASHPAGE_RAW_ALIGNMENT.
* @param[in] len length of the data to be written. It MUST be
* multiple of FLASHPAGE_RAW_BLOCKSIZE. Also,
* ensure it doesn't exceed the actual flash
* memory size.
*/
void flashpage_write_raw(void *target_addr, void *data, size_t len);
/**
* @brief Read the given page into the given memory location
*
* @param[in] page page to read
* @param[out] data memory to write the page to, MUST be @p FLASHPAGE_SIZE
* @param[out] data memory to write the page to, MUST be FLASHPAGE_SIZE
* byte
*/
void flashpage_read(int page, void *data);
......@@ -119,7 +168,7 @@ void flashpage_read(int page, void *data);
* @brief Verify the given page against the given data
*
* @param[in] page page to verify
* @param[in] data data to compare page against, MUST be @p FLASHPAGE_SIZE
* @param[in] data data to compare page against, MUST be FLASHPAGE_SIZE
* byte of data
*
* @return FLASHPAGE_OK if data in the page is identical to @p data
......@@ -133,7 +182,7 @@ int flashpage_verify(int page, void *data);
* This is a convenience function wrapping flashpage_write and flashpage_verify.
*
* @param[in] page page to write
* @param[in] data data to write to the page, MUST be @p FLASHPAGE_SIZE
* @param[in] data data to write to the page, MUST be FLASHPAGE_SIZE
* byte.
*
* @return FLASHPAGE_OK on success
......
BOARD ?= iotlab-m3
include ../Makefile.tests_common
FEATURES_REQUIRED = periph_flashpage
FEATURES_REQUIRED += periph_flashpage
FEATURES_OPTIONAL += periph_flashpage_raw
USEMODULE += shell
......
......@@ -32,6 +32,20 @@
*/
static uint8_t page_mem[FLASHPAGE_SIZE];
#ifdef MODULE_PERIPH_FLASHPAGE_RAW
/*
* @brief Allocate an aligned buffer for raw writings
*/
static char raw_buf[64] __attribute__ ((aligned (FLASHPAGE_RAW_ALIGNMENT)));
static uint32_t getaddr(const char *str)
{
uint32_t addr = strtol(str, NULL, 16);
return addr;
}
#endif
static int getpage(const char *str)
{
int page = atoi(str);
......@@ -164,6 +178,29 @@ static int cmd_write(int argc, char **argv)
return 0;
}
#ifdef MODULE_PERIPH_FLASHPAGE_RAW
static int cmd_write_raw(int argc, char **argv)
{
uint32_t addr;
if (argc < 3) {
printf("usage: %s <addr> <data>\n", argv[0]);
return 1;
}
addr = getaddr(argv[1]);
/* try to align */
memcpy(raw_buf, argv[2], strlen(argv[2]));
flashpage_write_raw((void*)addr, raw_buf, strlen(raw_buf));
printf("wrote local data to flash address %#lx of len %u\n",
addr, strlen(raw_buf));
return 0;
}
#endif
static int cmd_erase(int argc, char **argv)
{
int page;
......@@ -248,6 +285,9 @@ static const shell_command_t shell_commands[] = {
{ "dump_local", "Dump the local page buffer to STDOUT", cmd_dump_local },
{ "read", "Read and output the given page", cmd_read },
{ "write", "Write (ASCII) data to the given page", cmd_write },
#ifdef MODULE_PERIPH_FLASHPAGE_RAW
{ "write_raw", "Write (ASCII, max 64B) data to the given address", cmd_write_raw },
#endif
{ "erase", "Erase the given page", cmd_erase },
{ "edit", "Write bytes to the local page", cmd_edit },
{ "test", "Write and verify test pattern", cmd_test },
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment