blob: e394b694bca634fe39ae410e249bb9c27a0973c9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <inttypes.h>
#include "os/mynewt.h"
#include <console/console.h>
#include <hal/hal_bsp.h>
#include <hal/hal_flash.h>
#include <hal/hal_flash_int.h>
#include <shell/shell.h>
#include <stdio.h>
#include <string.h>
static int flash_cli_cmd(int argc, char **argv);
static struct shell_cmd flash_cmd_struct = {
.sc_cmd = "flash",
.sc_cmd_func = flash_cli_cmd
};
static int
flash_cli_cmd(int argc, char **argv)
{
const struct hal_flash *hf;
uint32_t off = 0;
uint32_t sz = 1;
int sec_cnt;
int i;
int devid;
int soff;
char *eptr;
char tmp_buf[32];
char pr_str[80];
if (argc > 1 && (!strcmp(argv[1], "?") || !strcmp(argv[1], "help"))) {
console_printf("Commands Available\n");
console_printf("flash [flash-id] -- dumps sector map \n");
console_printf("flash <flash-id> read <offset> <size> -- reads bytes from flash \n");
console_printf("flash <flash-id> write <offset> <size> -- writes incrementing data pattern 0-8 to flash \n");
console_printf("flash <flash-id> erase <offset> <size> -- erases flash \n");
return 0;
}
devid = 0;
if (argc < 3) {
if (argc == 2) {
devid = strtoul(argv[1], &eptr, 0);
if (*eptr != 0) {
console_printf("Invalid flash id %s\n", argv[1]);
return 0;
}
}
do {
hf = hal_bsp_flash_dev(devid);
if (!hf) {
if (argc == 2) {
console_printf("Flash device not present\n");
}
return 0;
}
console_printf("Flash %d at 0x%lx size 0x%lx with %d sectors,"
" alignment req %d bytes\n",
devid,
(long unsigned int) hf->hf_base_addr,
(long unsigned int) hf->hf_size,
hf->hf_sector_cnt,
hf->hf_align);
sec_cnt = hf->hf_sector_cnt;
if (sec_cnt > 32) {
sec_cnt = 32;
}
for (i = 0; i < sec_cnt; i++) {
console_printf(" %d: %lx\n", i,
(long unsigned int) hal_flash_sector_size(hf, i));
}
if (sec_cnt != hf->hf_sector_cnt) {
console_printf("... %d: %lx\n", hf->hf_sector_cnt - 1,
(long unsigned int) hal_flash_sector_size(hf, hf->hf_sector_cnt - 1));
}
++devid;
} while(argc == 1);
return 0;
}
if (argc > 1) {
devid = strtoul(argv[1], &eptr, 0);
if (*eptr != 0) {
console_printf("Invalid flash id %s\n", argv[1]);
goto err;
}
}
if (argc > 3) {
off = strtoul(argv[3], &eptr, 0);
if (*eptr != '\0') {
console_printf("Invalid offset %s\n", argv[2]);
goto err;
}
}
if (argc > 4) {
sz = strtoul(argv[4], &eptr, 0);
if (*eptr != '\0') {
console_printf("Invalid size %s\n", argv[3]);
goto err;
}
}
if (!strcmp(argv[2], "erase")) {
console_printf("Erase 0x%lx + %lx\n",
(long unsigned int) off, (long unsigned int) sz);
if (hal_flash_erase(devid, off, sz)) {
console_printf("Flash erase failed\n");
}
console_printf("Done!\n");
} else if (!strcmp(argv[2], "read")) {
console_printf("Read 0x%lx + %lx\n",
(long unsigned int) off, (long unsigned int) sz);
sz += off;
while (off < sz) {
sec_cnt = min(sizeof(tmp_buf), sz - off);
if (hal_flash_read(devid, off, tmp_buf, sec_cnt)) {
console_printf("flash read failure at %lx\n",
(long unsigned int) off);
break;
}
for (i = 0, soff = 0; i < sec_cnt; i++) {
soff += snprintf(pr_str + soff, sizeof(pr_str) - soff,
"0x%02x ", tmp_buf[i] & 0xff);
if (i % 8 == 7) {
console_printf(" 0x%lx: %s\n",
(long unsigned int) off, pr_str);
soff = 0;
off += 8;
}
}
if (i % 8) {
console_printf(" 0x%lx: %s\n",
(long unsigned int) off, pr_str);
off += i;
}
}
} else if (!strcmp(argv[2], "write")) {
console_printf("Write 0x%lx + %lx\n",
(long unsigned int) off, (long unsigned int) sz);
sz += off;
for (i = 0; i < sizeof(tmp_buf); i++) {
tmp_buf[i] = i + 1;
}
while (off < sz) {
sec_cnt = min(sizeof(tmp_buf), sz - off);
if (hal_flash_write(devid, off, tmp_buf, sec_cnt)) {
console_printf("flash write failure at %lx\n",
(long unsigned int) off);
}
off += sec_cnt;
}
console_printf("Done!\n");
}
return 0;
err:
return -1;
}
/*
* Returns # of ops done within 2 seconds.
*/
int
flash_speed_test(int flash_dev, uint32_t addr, int sz, int move)
{
int rc;
int cnt = 0;
int off = 0;
int start_time;
int end_time;
void *data_buf;
data_buf = malloc(sz);
if (!data_buf) {
return -1;
}
/*
* Catch start of a tick.
*/
start_time = os_time_get();
while (1) {
end_time = os_time_get();
if (end_time != start_time) {
start_time = end_time;
break;
}
}
/*
* Measure for 2 secs.
*/
do {
rc = hal_flash_read(flash_dev, addr + off, data_buf, sz);
if (rc) {
console_printf("hal_flash_read(%d, 0x%x, %d) = %d\n",
flash_dev, (unsigned int)addr + off, (unsigned int)sz, rc);
return -1;
}
if (move) {
off++;
if (off > 16) {
off = 0;
}
}
end_time = os_time_get();
cnt++;
} while (end_time - start_time < 2 * OS_TICKS_PER_SEC);
free(data_buf);
return cnt;
}
static int
flash_speed_test_cli(int argc, char **argv)
{
char *ep;
int flash_dev;
uint32_t addr;
uint32_t sz;
int move;
int cnt;
int i;
if (argc < 4) {
console_printf("flash_speed <flash_id> <addr> <rd_sz>|range [move]\n");
return 0;
}
flash_dev = strtoul(argv[1], &ep, 10);
if (*ep != '\0') {
console_printf("Invalid flash_id: %s\n", argv[1]);
return 0;
}
addr = strtoul(argv[2], &ep, 0);
if (*ep != '\0') {
console_printf("Invalid address: %s\n", argv[2]);
return 0;
}
if (!strcmp(argv[3], "range")) {
i = 1;
} else {
i = 0;
sz = strtoul(argv[3], &ep, 0);
if (*ep != '\0') {
console_printf("Invalid read size: %s\n", argv[3]);
return 0;
}
}
if (argc > 4 && !strcmp(argv[4], "move")) {
move = 1;
} else {
move = 0;
}
if (i == 0) {
console_printf("Speed test, hal_flash_read(%d, 0x%x%s, %d)\n",
flash_dev, (unsigned int)addr, move?"..":"", (unsigned int)sz);
cnt = flash_speed_test(flash_dev, addr, sz, move);
console_printf("%d\n", cnt >> 1);
} else {
uint32_t sizes[] = {
1, 2, 4, 8, 16, 24, 32, 48, 64, 96, 128, 192, 256
};
console_printf("Speed test, hal_flash_read(%d, 0x%x%s, X)\n",
flash_dev, (unsigned int)addr, move?"..":"");
for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) {
cnt = flash_speed_test(flash_dev, addr, sizes[i], move);
console_printf("%3d %d\n", (int)sizes[i], cnt >> 1);
os_time_delay(OS_TICKS_PER_SEC / 8);
}
}
return 0;
}
static struct shell_cmd flash_speed_cli_struct = {
.sc_cmd = "flash_speed",
.sc_cmd_func = flash_speed_test_cli
};
/*
* Initialize the package. Only called from sysinit().
*/
void
flash_test_init(void)
{
shell_cmd_register(&flash_cmd_struct);
shell_cmd_register(&flash_speed_cli_struct);
}