mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
376 lines
8.6 KiB
C
376 lines
8.6 KiB
C
/*
|
|
* Copyright (C) 2015 Freie Universität Berlin
|
|
*
|
|
* 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
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @ingroup tests
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Manual test application for flashpage peripheral drivers
|
|
*
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "shell.h"
|
|
#include "periph/flashpage.h"
|
|
|
|
#define LINE_LEN (16)
|
|
|
|
/* When writing raw bytes on flash, data must be correctly aligned. */
|
|
#ifdef MODULE_PERIPH_FLASHPAGE_RAW
|
|
#define ALIGNMENT_ATTR __attribute__ ((aligned (FLASHPAGE_RAW_ALIGNMENT)))
|
|
|
|
/*
|
|
* @brief Allocate an aligned buffer for raw writings
|
|
*/
|
|
static char raw_buf[64] ALIGNMENT_ATTR;
|
|
#else
|
|
#define ALIGNMENT_ATTR
|
|
#endif
|
|
|
|
/**
|
|
* @brief Allocate space for 1 flash page in RAM
|
|
*
|
|
* @note The flash page in RAM must be correctly aligned, even in RAM, when
|
|
* using flashpage_raw. This is because some architecture uses
|
|
* 32 bit alignment implicitly and there are cases (stm32l4) that
|
|
* requires 64 bit alignment.
|
|
*/
|
|
static uint8_t page_mem[FLASHPAGE_SIZE] ALIGNMENT_ATTR;
|
|
|
|
static int getpage(const char *str)
|
|
{
|
|
int page = atoi(str);
|
|
if ((page >= (int)FLASHPAGE_NUMOF) || (page < 0)) {
|
|
printf("error: page %i is invalid\n", page);
|
|
return -1;
|
|
}
|
|
return page;
|
|
}
|
|
|
|
static void dumpchar(uint8_t mem)
|
|
{
|
|
if (mem >= ' ' && mem <= '~') {
|
|
printf(" %c ", mem);
|
|
}
|
|
else {
|
|
printf(" ?? ");
|
|
}
|
|
}
|
|
|
|
static void memdump(void *addr, size_t len)
|
|
{
|
|
unsigned pos = 0;
|
|
uint8_t *mem = (uint8_t *)addr;
|
|
|
|
while (pos < (unsigned)len) {
|
|
for (unsigned i = 0; i < LINE_LEN; i++) {
|
|
printf("0x%02x ", mem[pos + i]);
|
|
}
|
|
puts("");
|
|
for (unsigned i = 0; i < LINE_LEN; i++) {
|
|
dumpchar(mem[pos++]);
|
|
}
|
|
puts("");
|
|
}
|
|
}
|
|
|
|
static void dump_local(void)
|
|
{
|
|
puts("Local page buffer:");
|
|
memdump(page_mem, FLASHPAGE_SIZE);
|
|
}
|
|
|
|
static int cmd_info(int argc, char **argv)
|
|
{
|
|
(void)argc;
|
|
(void)argv;
|
|
|
|
printf("Flash start addr:\t0x%08x\n", (int)CPU_FLASH_BASE);
|
|
printf("Page size:\t\t%i\n", (int)FLASHPAGE_SIZE);
|
|
printf("Number of pages:\t%i\n", (int)FLASHPAGE_NUMOF);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_dump(int argc, char **argv)
|
|
{
|
|
int page;
|
|
void *addr;
|
|
|
|
if (argc < 2) {
|
|
printf("usage: %s <page>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
page = getpage(argv[1]);
|
|
if (page < 0) {
|
|
return 1;
|
|
}
|
|
addr = flashpage_addr(page);
|
|
|
|
printf("Flash page %i at address %p\n", page, addr);
|
|
memdump(addr, FLASHPAGE_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_dump_local(int argc, char **argv)
|
|
{
|
|
(void)argc;
|
|
(void)argv;
|
|
|
|
dump_local();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_read(int argc, char **argv)
|
|
{
|
|
int page;
|
|
|
|
if (argc < 2) {
|
|
printf("usage: %s <page>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
page = getpage(argv[1]);
|
|
if (page < 0) {
|
|
return 1;
|
|
}
|
|
|
|
flashpage_read(page, page_mem);
|
|
printf("Read flash page %i into local page buffer\n", page);
|
|
dump_local();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_write(int argc, char **argv)
|
|
{
|
|
int page;
|
|
|
|
if (argc < 2) {
|
|
printf("usage: %s <page>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
page = getpage(argv[1]);
|
|
if (page < 0) {
|
|
return 1;
|
|
}
|
|
|
|
if (flashpage_write_and_verify(page, page_mem) != FLASHPAGE_OK) {
|
|
printf("error: verification for page %i failed\n", page);
|
|
return 1;
|
|
}
|
|
|
|
printf("wrote local page buffer to flash page %i at addr %p\n",
|
|
page, flashpage_addr(page));
|
|
return 0;
|
|
}
|
|
|
|
#ifdef MODULE_PERIPH_FLASHPAGE_RAW
|
|
static uint32_t getaddr(const char *str)
|
|
{
|
|
uint32_t addr = strtol(str, NULL, 16);
|
|
|
|
return addr;
|
|
}
|
|
|
|
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 %#" PRIx32 " of len %u\n",
|
|
addr, strlen(raw_buf));
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int cmd_erase(int argc, char **argv)
|
|
{
|
|
int page;
|
|
|
|
if (argc < 2) {
|
|
printf("usage: %s <page>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
page = getpage(argv[1]);
|
|
if (page < 0) {
|
|
return 1;
|
|
}
|
|
flashpage_write(page, NULL);
|
|
|
|
printf("successfully erased page %i (addr %p)\n",
|
|
page, flashpage_addr(page));
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_edit(int argc, char **argv)
|
|
{
|
|
int offset;
|
|
size_t data_len;
|
|
|
|
if (argc < 3) {
|
|
printf("usage: %s <offset> <data>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
offset = atoi(argv[1]);
|
|
if (offset >= (int)FLASHPAGE_SIZE) {
|
|
printf("error: given offset is out of bounce\n");
|
|
return -1;
|
|
}
|
|
data_len = strlen(argv[2]);
|
|
if ((data_len + offset) > FLASHPAGE_SIZE) {
|
|
data_len = FLASHPAGE_SIZE - offset;
|
|
}
|
|
|
|
memcpy(&page_mem[offset], argv[2], data_len);
|
|
dump_local();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_test(int argc, char **argv)
|
|
{
|
|
int page;
|
|
char fill = 'a';
|
|
|
|
if (argc < 2) {
|
|
printf("usage: %s <page>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
page = getpage(argv[1]);
|
|
if (page < 0) {
|
|
return 1;
|
|
}
|
|
|
|
for (unsigned i = 0; i < sizeof(page_mem); i++) {
|
|
page_mem[i] = (uint8_t)fill++;
|
|
if (fill > 'z') {
|
|
fill = 'a';
|
|
}
|
|
}
|
|
|
|
if (flashpage_write_and_verify(page, page_mem) != FLASHPAGE_OK) {
|
|
printf("error verifying the content of page %i\n", page);
|
|
return 1;
|
|
}
|
|
|
|
printf("wrote local page buffer to flash page %i at addr %p\n",
|
|
page, flashpage_addr(page));
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Does a write and verify test on last page available
|
|
*
|
|
* @note Since every hardware can have different flash layouts for
|
|
* automated testing we always write to the last page available
|
|
* so we are independent of the size or layout
|
|
*/
|
|
static int cmd_test_last(int argc, char **argv)
|
|
{
|
|
(void) argc;
|
|
(void) argv;
|
|
char fill = 'a';
|
|
|
|
for (unsigned i = 0; i < sizeof(page_mem); i++) {
|
|
page_mem[i] = (uint8_t)fill++;
|
|
if (fill > 'z') {
|
|
fill = 'a';
|
|
}
|
|
}
|
|
|
|
if (flashpage_write_and_verify((int)FLASHPAGE_NUMOF - 2, page_mem) != FLASHPAGE_OK) {
|
|
puts("error verifying the content of last page");
|
|
return 1;
|
|
}
|
|
|
|
puts("wrote local page buffer to last flash page");
|
|
return 0;
|
|
}
|
|
|
|
#ifdef MODULE_PERIPH_FLASHPAGE_RAW
|
|
/**
|
|
* @brief Does a short raw write on last page available
|
|
*
|
|
* @note Since every hardware can have different flash layouts for
|
|
* automated testing we always write to the last page available
|
|
* so we are independent of the size or layout
|
|
*/
|
|
static int cmd_test_last_raw(int argc, char **argv)
|
|
{
|
|
(void) argc;
|
|
(void) argv;
|
|
|
|
/* try to align */
|
|
memcpy(raw_buf, "test12344321tset", 16);
|
|
|
|
flashpage_write_raw((void*) ((int)CPU_FLASH_BASE + (int)FLASHPAGE_SIZE * ((int)FLASHPAGE_NUMOF - 2)), raw_buf, strlen(raw_buf));
|
|
|
|
puts("wrote raw short buffer to last flash page");
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static const shell_command_t shell_commands[] = {
|
|
{ "info", "Show information about pages", cmd_info },
|
|
{ "dump", "Dump the selected page to STDOUT", cmd_dump },
|
|
{ "dump_local", "Dump the local page buffer to STDOUT", cmd_dump_local },
|
|
{ "read", "Copy the given page to the local page buffer and dump to STDOUT", cmd_read },
|
|
{ "write", "Write the local page buffer 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 buffer", cmd_erase },
|
|
{ "edit", "Write bytes to the local page buffer", cmd_edit },
|
|
{ "test", "Write and verify test pattern", cmd_test },
|
|
{ "test_last", "Write and verify test pattern on last page available", cmd_test_last },
|
|
#ifdef MODULE_PERIPH_FLASHPAGE_RAW
|
|
{ "test_last_raw", "Write and verify raw short write on last page available", cmd_test_last_raw },
|
|
#endif
|
|
{ NULL, NULL, NULL }
|
|
};
|
|
|
|
int main(void)
|
|
{
|
|
puts("ROM flash read write test\n");
|
|
puts("Please refer to the README.md for further information\n");
|
|
|
|
cmd_info(0, NULL);
|
|
|
|
/* run the shell */
|
|
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
|
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
|
return 0;
|
|
}
|