aboutsummaryrefslogtreecommitdiff
path: root/projects
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2016-04-11 14:44:44 -0400
committerPaul Selkirk <paul@psgd.org>2016-04-11 14:44:44 -0400
commit79b1ba7104dba52dbfacf11a07305702889f440b (patch)
tree75a08fdc6e3af427e953f319b3fdb0f9dcfdf80e /projects
parentd5669dac8c7ab2fbf6bd3c7faed7ce050c94ee1a (diff)
Reorganize Makefile and directory structure, because it's messy, and it's about to get messier.
Diffstat (limited to 'projects')
-rw-r--r--projects/board-test/Makefile18
-rw-r--r--projects/board-test/fmc-perf.c126
-rw-r--r--projects/board-test/fmc-test.c240
-rw-r--r--projects/board-test/led-test.c33
-rw-r--r--projects/board-test/short-test.c205
-rw-r--r--projects/board-test/uart-test.c34
-rw-r--r--projects/libhal-test/Makefile33
-rw-r--r--projects/libhal-test/gettimeofday.c63
-rw-r--r--projects/libhal-test/main.c61
-rw-r--r--projects/libhal-test/printf.c453
10 files changed, 1266 insertions, 0 deletions
diff --git a/projects/board-test/Makefile b/projects/board-test/Makefile
new file mode 100644
index 0000000..21f24c9
--- /dev/null
+++ b/projects/board-test/Makefile
@@ -0,0 +1,18 @@
+TEST = led-test short-test uart-test fmc-test fmc-perf
+
+all: $(TEST:=.elf)
+
+%.elf: %.o $(BOARD_OBJS) $(LIBS)
+ $(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map
+ $(OBJCOPY) -O ihex $*.elf $*.hex
+ $(OBJCOPY) -O binary $*.elf $*.bin
+ $(OBJDUMP) -St $*.elf >$*.lst
+ $(SIZE) $*.elf
+
+clean:
+ rm -f *.o
+ rm -f *.elf
+ rm -f *.hex
+ rm -f *.bin
+ rm -f *.map
+ rm -f *.lst
diff --git a/projects/board-test/fmc-perf.c b/projects/board-test/fmc-perf.c
new file mode 100644
index 0000000..0c753a7
--- /dev/null
+++ b/projects/board-test/fmc-perf.c
@@ -0,0 +1,126 @@
+/*
+ * Test read/write performance of the fmc bus
+ */
+#include "stm32f4xx_hal.h"
+#include "stm-init.h"
+#include "stm-led.h"
+#include "stm-fmc.h"
+#include "stm-uart.h"
+
+#define TEST_NUM_ROUNDS 2000000
+
+RNG_HandleTypeDef rng_inst;
+
+static void MX_RNG_Init(void)
+{
+ rng_inst.Instance = RNG;
+ HAL_RNG_Init(&rng_inst);
+}
+
+static uint32_t random(void)
+{
+ uint32_t rnd;
+ if (HAL_RNG_GenerateRandomNumber(&rng_inst, &rnd) != HAL_OK) {
+ uart_send_string("HAL_RNG_GenerateRandomNumber failed\r\n");
+ Error_Handler();
+ }
+ return rnd;
+}
+
+static void sanity(void)
+{
+ uint32_t rnd, data;
+
+ rnd = random();
+ if (fmc_write_32(0, &rnd) != 0) {
+ uart_send_string("fmc_write_32 failed\r\n");
+ Error_Handler();
+ }
+ if (fmc_read_32(0, &data) != 0) {
+ uart_send_string("fmc_read_32 failed\r\n");
+ Error_Handler();
+ }
+ if (data != rnd) {
+ uart_send_string("Data bus fail: expected ");
+ uart_send_hex(rnd, 8);
+ uart_send_string(", got ");
+ uart_send_hex(data, 8);
+ uart_send_string(", diff ");
+ uart_send_hex(data ^ rnd, 8);
+ uart_send_string("\r\n");
+ Error_Handler();
+ }
+}
+
+static void _time_check(char *label, const uint32_t t0)
+{
+ uint32_t t = HAL_GetTick() - t0;
+
+ uart_send_string(label);
+ uart_send_integer(t / 1000, 0);
+ uart_send_char('.');
+ uart_send_integer(t % 1000, 3);
+ uart_send_string(" seconds, ");
+ uart_send_integer(((1000 * TEST_NUM_ROUNDS) / t), 0);
+ uart_send_string("/sec\r\n");
+}
+
+#define time_check(_label_, _expr_) \
+ do { \
+ uint32_t _t = HAL_GetTick(); \
+ (_expr_); \
+ _time_check(_label_, _t); \
+ } while (0)
+
+static void test_read(void)
+{
+ uint32_t i, data;
+
+ for (i = 0; i < TEST_NUM_ROUNDS; ++i) {
+ if (fmc_read_32(0, &data) != 0) {
+ uart_send_string("fmc_read_32 failed\r\n");
+ Error_Handler();
+ }
+ }
+}
+
+static void test_write(void)
+{
+ uint32_t i;
+
+ for (i = 0; i < TEST_NUM_ROUNDS; ++i) {
+ if (fmc_write_32(0, &i) != 0) {
+ uart_send_string("fmc_write_32 failed\r\n");
+ Error_Handler();
+ }
+ }
+}
+
+int main(void)
+{
+ stm_init();
+
+ uart_send_string("Keep calm for Novena boot...\r\n");
+
+ // Blink blue LED for six seconds to not upset the Novena at boot.
+ led_on(LED_BLUE);
+ for (int i = 0; i < 12; i++) {
+ HAL_Delay(500);
+ led_toggle(LED_BLUE);
+ }
+ led_off(LED_BLUE);
+
+ // initialize rng
+ MX_RNG_Init();
+
+ // prepare fmc interface
+ fmc_init();
+
+ sanity();
+
+ time_check("read ", test_read());
+ time_check("write ", test_write());
+
+ uart_send_string("Done.\r\n\r\n");
+ return 0;
+}
diff --git a/projects/board-test/fmc-test.c b/projects/board-test/fmc-test.c
new file mode 100644
index 0000000..cf17087
--- /dev/null
+++ b/projects/board-test/fmc-test.c
@@ -0,0 +1,240 @@
+//------------------------------------------------------------------------------
+// main.c
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+#include "stm32f4xx_hal.h"
+#include "stm-init.h"
+#include "stm-led.h"
+#include "stm-fmc.h"
+#include "stm-uart.h"
+
+//------------------------------------------------------------------------------
+// Defines
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// Variables
+//------------------------------------------------------------------------------
+RNG_HandleTypeDef rng_inst;
+
+// FT: "I changed some interesting-to-look-at-in-the-debugger values to be
+// volatile, so that my compiler wouldn't optimize/obscure them."
+
+volatile uint32_t data_diff = 0;
+volatile uint32_t addr_diff = 0;
+
+
+//------------------------------------------------------------------------------
+// Prototypes
+//------------------------------------------------------------------------------
+/* XXX move this to stm-rng.[ch] */
+static void MX_RNG_Init(void);
+
+int test_fpga_data_bus(void);
+int test_fpga_address_bus(void);
+
+
+//------------------------------------------------------------------------------
+// Defines
+//------------------------------------------------------------------------------
+#define TEST_NUM_ROUNDS 100000
+
+
+//------------------------------------------------------------------------------
+int main(void)
+//------------------------------------------------------------------------------
+{
+ int i;
+
+ stm_init();
+
+ uart_send_string("Keep calm for Novena boot...\r\n");
+
+ // Blink blue LED for six seconds to not upset the Novena at boot.
+ led_on(LED_BLUE);
+ for (i = 0; i < 12; i++) {
+ HAL_Delay(500);
+ led_toggle(LED_BLUE);
+ }
+
+ // initialize rng
+ MX_RNG_Init();
+
+ // prepare fmc interface
+ fmc_init();
+
+ // turn on green led, turn off other leds
+ led_on(LED_GREEN);
+ led_off(LED_YELLOW);
+ led_off(LED_RED);
+ led_off(LED_BLUE);
+
+ // vars
+ volatile int data_test_ok = 0, addr_test_ok = 0, successful_runs = 0, failed_runs = 0, sleep = 0;
+
+ // main loop (test, until an error is detected)
+ while (1)
+ {
+ // test data bus
+ data_test_ok = test_fpga_data_bus();
+ // test address bus
+ addr_test_ok = test_fpga_address_bus();
+
+ uart_send_string("Data: ");
+ uart_send_integer(data_test_ok, 6);
+ uart_send_string(", addr: ");
+ uart_send_integer(addr_test_ok, 6);
+ uart_send_string("\r\n");
+
+ if (data_test_ok == TEST_NUM_ROUNDS &&
+ addr_test_ok == TEST_NUM_ROUNDS) {
+ // toggle yellow led to indicate, that we are alive
+ led_toggle(LED_YELLOW);
+
+ successful_runs++;
+ sleep = 100;
+ } else {
+ led_on(LED_RED);
+ failed_runs++;
+ sleep = 2000;
+ }
+
+ uart_send_string("Success ");
+ uart_send_integer(successful_runs, 0);
+ uart_send_string(", fail ");
+ uart_send_integer(failed_runs, 0);
+ uart_send_string("\r\n\r\n");
+
+ HAL_Delay(sleep);
+ }
+
+ // should never reach this line
+}
+
+
+//------------------------------------------------------------------------------
+int test_fpga_data_bus(void)
+//------------------------------------------------------------------------------
+{
+ int c, ok;
+ uint32_t rnd, buf;
+ HAL_StatusTypeDef hal_result;
+
+ // run some rounds of data bus test
+ for (c=0; c<TEST_NUM_ROUNDS; c++)
+ {
+ data_diff = 0;
+ // try to generate "random" number
+ hal_result = HAL_RNG_GenerateRandomNumber(&rng_inst, &rnd);
+ if (hal_result != HAL_OK) break;
+
+ // write value to fpga at address 0
+ ok = fmc_write_32(0, &rnd);
+ if (ok != 0) break;
+
+ // read value from fpga
+ ok = fmc_read_32(0, &buf);
+ if (ok != 0) break;
+
+ // compare (abort testing in case of error)
+ if (buf != rnd)
+ {
+ data_diff = buf;
+ data_diff ^= rnd;
+
+ uart_send_string("Data bus fail: expected ");
+ uart_send_binary(rnd, 32);
+ uart_send_string(", got ");
+ uart_send_binary(buf, 32);
+ uart_send_string(", diff ");
+ uart_send_binary(data_diff, 32);
+ uart_send_string("\r\n");
+
+ break;
+ }
+ }
+
+ // return number of successful tests
+ return c;
+}
+
+
+//------------------------------------------------------------------------------
+int test_fpga_address_bus(void)
+//------------------------------------------------------------------------------
+{
+ int c, ok;
+ uint32_t rnd, buf;
+ HAL_StatusTypeDef hal_result;
+
+ // run some rounds of address bus test
+ for (c=0; c<TEST_NUM_ROUNDS; c++)
+ {
+ addr_diff = 0;
+ // try to generate "random" number
+ hal_result = HAL_RNG_GenerateRandomNumber(&rng_inst, &rnd);
+ if (hal_result != HAL_OK) break;
+
+ // we only have 2^22 32-bit words
+ //rnd &= 0x00FFFFFC;
+ rnd &= 0x0007FFFC;
+
+ // don't test zero addresses (fpga will store data, not address)
+ if (rnd == 0) continue;
+
+ // write dummy value to fpga at some non-zero address
+ ok = fmc_write_32(rnd, &buf);
+ if (ok != 0) break;
+
+ // read value from fpga
+ ok = fmc_read_32(0, &buf);
+ if (ok != 0) break;
+
+ // fpga receives address of 32-bit word, while we need
+ // byte address here to compare
+ buf <<= 2;
+
+ // compare (abort testing in case of error)
+ if (buf != rnd)
+ {
+ addr_diff = buf;
+ addr_diff ^= rnd;
+
+ uart_send_string("Addr bus fail: expected ");
+ uart_send_binary(rnd, 32);
+ uart_send_string(", got ");
+ uart_send_binary(buf, 32);
+ uart_send_string(", diff ");
+ uart_send_binary(addr_diff, 32);
+ uart_send_string("\r\n");
+
+ break;
+ }
+ }
+
+ return c;
+}
+
+
+//------------------------------------------------------------------------------
+static void MX_RNG_Init(void)
+//------------------------------------------------------------------------------
+{
+ rng_inst.Instance = RNG;
+ HAL_RNG_Init(&rng_inst);
+}
+
+
+//------------------------------------------------------------------------------
+// EOF
+//------------------------------------------------------------------------------
diff --git a/projects/board-test/led-test.c b/projects/board-test/led-test.c
new file mode 100644
index 0000000..5e4401f
--- /dev/null
+++ b/projects/board-test/led-test.c
@@ -0,0 +1,33 @@
+/*
+ * Blink the four LEDs on the rev01 board in a pattern.
+ */
+#include "stm32f4xx_hal.h"
+#include "stm-init.h"
+#include "stm-led.h"
+
+#define DELAY() HAL_Delay(125)
+
+void toggle_led(uint32_t times, uint32_t led_pin)
+{
+ uint32_t i;
+
+ for (i = 0; i < times; i++) {
+ HAL_GPIO_TogglePin(LED_PORT, led_pin);
+ DELAY();
+ }
+}
+
+int
+main()
+{
+ stm_init();
+
+ while (1)
+ {
+ toggle_led(2, LED_BLUE);
+ toggle_led(2, LED_GREEN);
+ toggle_led(2, LED_YELLOW);
+ toggle_led(2, LED_RED);
+ }
+
+}
diff --git a/projects/board-test/short-test.c b/projects/board-test/short-test.c
new file mode 100644
index 0000000..27b8e7a
--- /dev/null
+++ b/projects/board-test/short-test.c
@@ -0,0 +1,205 @@
+/*
+ * Test code that just sends the letters 'a' to 'z' over and
+ * over again using USART2.
+ *
+ * Toggles the BLUE LED slowly and the RED LED for every
+ * character sent.
+ */
+#include "stm32f4xx_hal.h"
+#include "stm-init.h"
+#include "stm-led.h"
+#include "stm-uart.h"
+
+void test_for_shorts(char port, GPIO_TypeDef* GPIOx, uint16_t GPIO_Test_Pins);
+
+//------------------------------------------------------------------------------
+// Defines
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/* These are all the pins used by the FMC interface */
+#define GPIOB_PINS (GPIO_PIN_7)
+
+#define GPIOD_PINS (GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 \
+ |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15 \
+ |GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_3|GPIO_PIN_4 \
+ |GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7)
+
+#define GPIOE_PINS (GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7 \
+ |GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 \
+ |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15)
+
+#define GPIOF_PINS (GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 \
+ |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12|GPIO_PIN_13 \
+ |GPIO_PIN_14|GPIO_PIN_15)
+
+#define GPIOG_PINS (GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 \
+ |GPIO_PIN_4|GPIO_PIN_5)
+
+#define GPIOH_PINS (GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 \
+ |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15)
+
+#define GPIOI_PINS (GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_0|GPIO_PIN_1 \
+ |GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_6|GPIO_PIN_7)
+
+int
+main()
+{
+ stm_init();
+
+ // enable gpio clocks
+ __GPIOA_CLK_ENABLE();
+ __GPIOB_CLK_ENABLE();
+ __GPIOD_CLK_ENABLE();
+ __GPIOE_CLK_ENABLE();
+ __GPIOF_CLK_ENABLE();
+ __GPIOG_CLK_ENABLE();
+ __GPIOH_CLK_ENABLE();
+ __GPIOI_CLK_ENABLE();
+
+ while (1) {
+ HAL_GPIO_TogglePin(LED_PORT, LED_GREEN);
+ uart_send_string("\r\n\r\n\r\n\r\n\r\n");
+
+ test_for_shorts('B', GPIOB, GPIOB_PINS);
+ test_for_shorts('D', GPIOD, GPIOD_PINS);
+ test_for_shorts('E', GPIOE, GPIOE_PINS);
+ test_for_shorts('F', GPIOF, GPIOF_PINS);
+ test_for_shorts('G', GPIOG, GPIOG_PINS);
+ test_for_shorts('H', GPIOH, GPIOH_PINS);
+ test_for_shorts('I', GPIOI, GPIOI_PINS);
+ led_toggle(LED_BLUE);
+ HAL_Delay(2000);
+ }
+}
+
+void configure_all_as_input(GPIO_TypeDef* GPIOx, uint16_t GPIO_Test_Pins)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* Configure all pins as input. XXX do all pins (0xffff) instead of just GPIO_Test_Pins? */
+ GPIO_InitStruct.Pin = GPIO_Test_Pins;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
+ HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
+}
+
+uint8_t check_no_input(char port, GPIO_TypeDef* GPIOx, uint16_t GPIO_Test_Pins, char wrote_port, uint16_t wrote_value)
+{
+ uint16_t read;
+
+ /* Read all pins from port at once. XXX check all pins, not just GPIO_Test_Pins? */
+ read = (GPIOx->IDR & GPIO_Test_Pins);
+
+ if (! read) {
+ /* No unexpected pins read as HIGH */
+ return 0;
+ }
+
+ led_on(LED_RED);
+
+ uart_send_string("Wrote ");
+ uart_send_binary(wrote_value, 16);
+
+ uart_send_string(" to port GPIO");
+ uart_send_char(wrote_port);
+
+ uart_send_string(", read ");
+ uart_send_binary(read, 16);
+
+ uart_send_string(" from GPIO");
+ uart_send_char(port);
+
+ uart_send_string("\r\n");
+
+ return 1;
+}
+
+void test_for_shorts(char port, GPIO_TypeDef* GPIOx, uint16_t GPIO_Test_Pins)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+ uint16_t i, fail = 0, Test_Pin, read;
+
+ configure_all_as_input(GPIOB, GPIOB_PINS);
+ configure_all_as_input(GPIOD, GPIOD_PINS);
+ configure_all_as_input(GPIOE, GPIOE_PINS);
+ configure_all_as_input(GPIOF, GPIOF_PINS);
+ configure_all_as_input(GPIOG, GPIOG_PINS);
+ configure_all_as_input(GPIOH, GPIOH_PINS);
+ configure_all_as_input(GPIOI, GPIOI_PINS);
+
+ check_no_input('B', GPIOB, GPIOB_PINS, 'x', 0);
+ check_no_input('D', GPIOD, GPIOD_PINS, 'x', 0);
+ check_no_input('E', GPIOE, GPIOE_PINS, 'x', 0);
+ check_no_input('F', GPIOF, GPIOF_PINS, 'x', 0);
+ check_no_input('G', GPIOG, GPIOG_PINS, 'x', 0);
+ check_no_input('H', GPIOH, GPIOH_PINS, 'x', 0);
+ check_no_input('I', GPIOI, GPIOI_PINS, 'x', 0);
+
+ for (i = 0; i < 31; i++) {
+ Test_Pin = 1 << i;
+ if (! (GPIO_Test_Pins & Test_Pin)) continue;
+
+ configure_all_as_input(GPIOx, GPIO_Test_Pins);
+
+ /* Change one pin to output */
+ GPIO_InitStruct.Pin = Test_Pin;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
+ HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
+
+ HAL_GPIO_WritePin(GPIOx, Test_Pin, GPIO_PIN_SET);
+
+ /* Slight delay after setting the output pin. Without this, the Test_Pin
+ bit might read as zero, as it is only sampled once every AHB1 clock cycle.
+ Reference manual DM00031020 section 8.3.1.
+ */
+ HAL_Delay(1);
+
+ /* Read all input GPIOs from port at once. XXX check all pins, not just GPIO_Test_Pins? */
+ read = GPIOx->IDR & GPIO_Test_Pins;
+
+ if (read == Test_Pin) {
+ /* No unexpected pins read as HIGH */
+ led_toggle(LED_GREEN);
+ } else {
+ led_on(LED_RED);
+ uart_send_string("GPIO");
+ uart_send_char(port);
+
+ uart_send_string(" exp ");
+ uart_send_binary(Test_Pin, 16);
+
+ uart_send_string(" got ");
+ uart_send_binary(read, 16);
+
+ uart_send_string(" diff ");
+ uart_send_binary(read ^ Test_Pin, 16);
+
+ uart_send_string("\r\n");
+
+ fail++;
+ }
+
+ /* Check there is no input on any of the other GPIO ports (adjacent pins might live on different ports) */
+ if (port != 'B') fail += check_no_input('B', GPIOB, GPIOB_PINS, port, Test_Pin);
+ if (port != 'D') fail += check_no_input('D', GPIOD, GPIOD_PINS, port, Test_Pin);
+ if (port != 'E') fail += check_no_input('E', GPIOE, GPIOE_PINS, port, Test_Pin);
+ if (port != 'F') fail += check_no_input('F', GPIOF, GPIOF_PINS, port, Test_Pin);
+ if (port != 'G') fail += check_no_input('G', GPIOG, GPIOG_PINS, port, Test_Pin);
+ if (port != 'H') fail += check_no_input('H', GPIOH, GPIOH_PINS, port, Test_Pin);
+ if (port != 'I') fail += check_no_input('I', GPIOI, GPIOI_PINS, port, Test_Pin);
+
+ HAL_GPIO_WritePin(GPIOx, Test_Pin, GPIO_PIN_RESET);
+ }
+
+ if (fail) {
+ uart_send_string("\r\n");
+ }
+}
diff --git a/projects/board-test/uart-test.c b/projects/board-test/uart-test.c
new file mode 100644
index 0000000..8fe7795
--- /dev/null
+++ b/projects/board-test/uart-test.c
@@ -0,0 +1,34 @@
+/*
+ * Test code that just sends the letters 'a' to 'z' over and
+ * over again using USART2.
+ *
+ * Toggles the BLUE LED slowly and the RED LED for every
+ * character sent.
+ */
+#include "stm32f4xx_hal.h"
+#include "stm-init.h"
+#include "stm-led.h"
+#include "stm-uart.h"
+
+#define DELAY() HAL_Delay(100)
+
+int
+main()
+{
+ uint8_t c = 'a';
+
+ stm_init();
+
+ while (1)
+ {
+ HAL_GPIO_TogglePin(LED_PORT, LED_RED);
+
+ uart_send_char(c);
+ DELAY();
+
+ if (c++ == 'z') {
+ c = 'a';
+ HAL_GPIO_TogglePin(LED_PORT, LED_BLUE);
+ }
+ }
+}
diff --git a/projects/libhal-test/Makefile b/projects/libhal-test/Makefile
new file mode 100644
index 0000000..b0def35
--- /dev/null
+++ b/projects/libhal-test/Makefile
@@ -0,0 +1,33 @@
+TEST = cores test-bus test-trng test-hash test-aes-key-wrap test-pbkdf2 test-ecdsa test-rsa
+#TEST += test-rpc_hash test-rpc_pkey test-rpc_get_version test-rpc_get_random
+TEST += test-rpc_server
+
+CFLAGS += -I $(LIBHAL_DIR)
+LIBC_OBJS = printf.o gettimeofday.o
+LIBS += $(LIBHAL_DIR)/libhal.a $(LIBTFM_DIR)/libtfm.a
+
+all: $(TEST:=.elf)
+
+vpath %.c $(LIBHAL_DIR)/tests $(LIBHAL_DIR)/utils
+
+# .mo extension for files with main() that need to be wrapped as __main()
+%.mo: %.c
+ $(CC) -c $(CFLAGS) -Dmain=__main -o $@ $<
+
+%.elf: %.mo main.o $(BOARD_OBJS) $(LIBC_OBJS) $(LIBS)
+ $(CC) $(CFLAGS) $^ -o $*.elf -T$(LDSCRIPT) -g -Wl,-Map=$*.map
+ $(OBJCOPY) -O ihex $*.elf $*.hex
+ $(OBJCOPY) -O binary $*.elf $*.bin
+ $(OBJDUMP) -St $*.elf >$*.lst
+ $(SIZE) $*.elf
+
+# don't automatically delete objects, to avoid a lot of unnecessary rebuilding
+.SECONDARY: $(BOARD_OBJS) $(LIBC_OBJS)
+
+clean:
+ rm -f *.o *.mo
+ rm -f *.elf
+ rm -f *.hex
+ rm -f *.bin
+ rm -f *.map
+ rm -f *.lst
diff --git a/projects/libhal-test/gettimeofday.c b/projects/libhal-test/gettimeofday.c
new file mode 100644
index 0000000..b13485d
--- /dev/null
+++ b/projects/libhal-test/gettimeofday.c
@@ -0,0 +1,63 @@
+/*
+ * gettimeofday.c
+ * --------------
+ * A simple implementation of gettimeofday() for CMSIS.
+ * This assumes a 1ms SysTick. It obviously does not return the absolute time,
+ * just the time since boot, but it's only used to calculate elapsed time in
+ * code we're porting from unix.
+ *
+ * Copyright (c) 2015, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+
+#include "stm32f4xx_hal.h"
+
+/* Don't #include <sys/time.h> because of conflicting prototype in newlib. */
+
+/* from the manpage */
+struct timeval {
+ time_t tv_sec; /* seconds */
+ suseconds_t tv_usec; /* microseconds */
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of DST correction */
+};
+
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ uint32_t tick = HAL_GetTick(); /* uptime in ms */
+
+ tv->tv_sec = tick / 1000;
+ tv->tv_usec = (tick % 1000) * 1000;
+
+ return 0;
+}
diff --git a/projects/libhal-test/main.c b/projects/libhal-test/main.c
new file mode 100644
index 0000000..2776750
--- /dev/null
+++ b/projects/libhal-test/main.c
@@ -0,0 +1,61 @@
+/*
+ * main.c
+ * ------
+ * A wrapper for test programs that contain main() (currently libhal/tests).
+ * We compile them with -Dmain=__main, so we can do stm setup first.
+ *
+ * Copyright (c) 2015, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "stm-init.h"
+#include "stm-led.h"
+#include "stm-fmc.h"
+#include "stm-uart.h"
+
+extern void __main(void);
+
+int main(void)
+{
+ stm_init();
+
+ // Blink blue LED for six seconds to not upset the Novena at boot.
+ led_on(LED_BLUE);
+ for (int i = 0; i < 12; i++) {
+ HAL_Delay(500);
+ led_toggle(LED_BLUE);
+ }
+ fmc_init();
+ led_off(LED_BLUE);
+ led_on(LED_GREEN);
+
+ __main();
+
+ uart_send_string("Done.\r\n\r\n");
+ while(1);
+}
diff --git a/projects/libhal-test/printf.c b/projects/libhal-test/printf.c
new file mode 100644
index 0000000..5a15d12
--- /dev/null
+++ b/projects/libhal-test/printf.c
@@ -0,0 +1,453 @@
+/*****************************************************************************
+Stripped-down printf()
+Chris Giese <geezer@execpc.com> http://my.execpc.com/~geezer
+Release date: Dec 12, 2003
+This code is public domain (no copyright).
+You can do whatever you want with it.
+
+Revised Dec 12, 2003
+- fixed vsprintf() and sprintf() in test code
+
+Revised Jan 28, 2002
+- changes to make characters 0x80-0xFF display properly
+
+Revised June 10, 2001
+- changes to make vsprintf() terminate string with '\0'
+
+Revised May 12, 2000
+- math in DO_NUM is now unsigned, as it should be
+- %0 flag (pad left with zeroes) now works
+- actually did some TESTING, maybe fixed some other bugs
+
+%[flag][width][.prec][mod][conv]
+flag: - left justify, pad right w/ blanks DONE
+ 0 pad left w/ 0 for numerics DONE
+ + always print sign, + or - no
+ ' ' (blank) no
+ # (???) no
+
+width: (field width) DONE
+
+prec: (precision) DONE
+
+conv: d,i decimal int DONE
+ u decimal unsigned DONE
+ o octal DONE
+ x,X hex DONE
+ f,e,g,E,G float no
+ c char DONE
+ s string DONE
+ p ptr DONE
+
+mod: N near ptr DONE
+ F far ptr no
+ h short (16-bit) int DONE
+ l long (32-bit) int DONE
+ L/ll long long (64-bit) int no
+*****************************************************************************/
+#include <string.h> /* strlen() */
+#include <stdio.h> /* stdout, putchar(), fputs() (but not printf() :) */
+#undef putchar
+
+#include <stdarg.h> /* va_list, va_start(), va_arg(), va_end() */
+
+/* flags used in processing format string */
+#define PR_LJ 0x01 /* left justify */
+#define PR_CA 0x02 /* use A-F instead of a-f for hex */
+#define PR_SG 0x04 /* signed numeric conversion (%d vs. %u) */
+#define PR_32 0x08 /* long (32-bit) numeric conversion */
+#define PR_16 0x10 /* short (16-bit) numeric conversion */
+#define PR_WS 0x20 /* PR_SG set and num was < 0 */
+#define PR_LZ 0x40 /* pad left with '0' instead of ' ' */
+#define PR_FP 0x80 /* pointers are far */
+/* largest number handled is 2^64-1, lowest radix handled is 8.
+2^64-1 in base 8 has 22 digits (add 2 for trailing NUL and for slop) */
+#define PR_BUFLEN 24
+
+#ifndef max
+#define max(a,b) ((a > b) ? a : b)
+#endif
+
+typedef int (*fnptr_t)(unsigned c, void **helper);
+/*****************************************************************************
+name: do_printf
+action: minimal subfunction for ?printf, calls function
+ 'fn' with arg 'ptr' for each character to be output
+returns:total number of characters output
+*****************************************************************************/
+int do_printf(const char *fmt, va_list args, fnptr_t fn, void *ptr)
+{
+ unsigned flags, length, count, width, precision;
+ unsigned char *where, buf[PR_BUFLEN];
+ unsigned char state, radix;
+ long num;
+
+ state = flags = count = width = precision = 0;
+/* begin scanning format specifier list */
+ for(; *fmt; fmt++)
+ {
+ switch(state)
+ {
+/* STATE 0: AWAITING % */
+ case 0:
+ if(*fmt != '%') /* not %... */
+ {
+ fn(*fmt, &ptr); /* ...just echo it */
+ count++;
+ break;
+ }
+/* found %, get next char and advance state to check if next char is a flag */
+ state++;
+ fmt++;
+ /* FALL THROUGH */
+/* STATE 1: AWAITING FLAGS (%-0) */
+ case 1:
+ if(*fmt == '%') /* %% */
+ {
+ fn(*fmt, &ptr);
+ count++;
+ state = flags = width = precision = 0;
+ break;
+ }
+ if(*fmt == '-')
+ {
+ if(flags & PR_LJ)/* %-- is illegal */
+ state = flags = width = precision = 0;
+ else
+ flags |= PR_LJ;
+ break;
+ }
+/* not a flag char: advance state to check if it's field width */
+ state++;
+/* check now for '%0...' */
+ if(*fmt == '0')
+ {
+ flags |= PR_LZ;
+ fmt++;
+ }
+ /* FALL THROUGH */
+/* STATE 2: AWAITING (NUMERIC) FIELD WIDTH */
+ case 2:
+ if(*fmt >= '0' && *fmt <= '9')
+ {
+ width = 10 * width + (*fmt - '0');
+ break;
+ }
+/* not a field width: advance state to check if it's field precision */
+ state++;
+ /* FALL THROUGH */
+/* STATE 3: AWAITING (NUMERIC) FIELD PRECISION */
+ case 3:
+ if(*fmt == '.')
+ ++fmt;
+ if(*fmt >= '0' && *fmt <= '9')
+ {
+ precision = 10 * precision + (*fmt - '0');
+ break;
+ }
+/* not field precision: advance state to check if it's a modifier */
+ state++;
+ /* FALL THROUGH */
+/* STATE 4: AWAITING MODIFIER CHARS (FNlh) */
+ case 4:
+ if(*fmt == 'F')
+ {
+ flags |= PR_FP;
+ break;
+ }
+ if(*fmt == 'N')
+ break;
+ if(*fmt == 'l')
+ {
+ flags |= PR_32;
+ break;
+ }
+ if(*fmt == 'h')
+ {
+ flags |= PR_16;
+ break;
+ }
+/* not modifier: advance state to check if it's a conversion char */
+ state++;
+ /* FALL THROUGH */
+/* STATE 5: AWAITING CONVERSION CHARS (Xxpndiuocs) */
+ case 5:
+ where = buf + PR_BUFLEN - 1;
+ *where = '\0';
+ switch(*fmt)
+ {
+ case 'X':
+ flags |= PR_CA;
+ /* FALL THROUGH */
+/* xxx - far pointers (%Fp, %Fn) not yet supported */
+ case 'x':
+ case 'p':
+ case 'n':
+ radix = 16;
+ goto DO_NUM;
+ case 'd':
+ case 'i':
+ flags |= PR_SG;
+ /* FALL THROUGH */
+ case 'u':
+ radix = 10;
+ goto DO_NUM;
+ case 'o':
+ radix = 8;
+/* load the value to be printed. l=long=32 bits: */
+DO_NUM: if(flags & PR_32)
+ num = va_arg(args, unsigned long);
+/* h=short=16 bits (signed or unsigned) */
+ else if(flags & PR_16)
+ {
+ num = va_arg(args, int);
+ if(flags & PR_SG)
+ num = (short) num;
+ else
+ num = (unsigned short) num;
+ }
+/* no h nor l: sizeof(int) bits (signed or unsigned) */
+ else
+ {
+ if(flags & PR_SG)
+ num = va_arg(args, int);
+ else
+ num = va_arg(args, unsigned int);
+ }
+/* take care of sign */
+ if(flags & PR_SG)
+ {
+ if(num < 0)
+ {
+ flags |= PR_WS;
+ num = -num;
+ }
+ }
+/* convert binary to octal/decimal/hex ASCII
+OK, I found my mistake. The math here is _always_ unsigned */
+ do
+ {
+ unsigned long temp;
+
+ temp = (unsigned long)num % radix;
+ where--;
+ if(temp < 10)
+ *where = temp + '0';
+ else if(flags & PR_CA)
+ *where = temp - 10 + 'A';
+ else
+ *where = temp - 10 + 'a';
+ num = (unsigned long)num / radix;
+ }
+ while(num != 0);
+/* for integers, precision functions like width, but pads with zeros */
+ if (precision != 0)
+ {
+ width = max(width, precision);
+ if (precision > strlen(where))
+ flags |= PR_LZ;
+ precision = 0;
+ }
+ goto EMIT;
+ case 'c':
+/* disallow pad-left-with-zeroes for %c */
+ flags &= ~PR_LZ;
+ where--;
+ *where = (unsigned char)va_arg(args, int);
+ length = 1;
+ goto EMIT2;
+ case 's':
+/* disallow pad-left-with-zeroes for %s */
+ flags &= ~PR_LZ;
+ where = va_arg(args, unsigned char *);
+EMIT:
+ length = strlen((const char *)where);
+/* if string is longer than precision, truncate */
+ if ((precision != 0) && (precision < length))
+ {
+ length = precision;
+ precision = 0;
+ }
+ if(flags & PR_WS)
+ length++;
+/* if we pad left with ZEROES, do the sign now */
+ if((flags & (PR_WS | PR_LZ)) ==
+ (PR_WS | PR_LZ))
+ {
+ fn('-', &ptr);
+ count++;
+ }
+/* pad on left with spaces or zeroes (for right justify) */
+EMIT2: if((flags & PR_LJ) == 0)
+ {
+ while(width > length)
+ {
+ fn(flags & PR_LZ ?
+ '0' : ' ', &ptr);
+ count++;
+ width--;
+ }
+ }
+/* if we pad left with SPACES, do the sign now */
+ if((flags & (PR_WS | PR_LZ)) == PR_WS)
+ {
+ fn('-', &ptr);
+ count++;
+ }
+/* emit string/char/converted number */
+ for(int i = (flags & PR_WS) ? 1 : 0;
+ i < length; ++i)
+ {
+ fn(*where++, &ptr);
+ count++;
+ }
+/* pad on right with spaces (for left justify) */
+ if(width < length)
+ width = 0;
+ else width -= length;
+ for(; width; width--)
+ {
+ fn(' ', &ptr);
+ count++;
+ }
+ break;
+ default:
+ break;
+ }
+ default:
+ state = flags = width = precision = 0;
+ break;
+ }
+ }
+ return count;
+}
+
+/*****************************************************************************
+SPRINTF
+*****************************************************************************/
+static int vsprintf_help(unsigned c, void **ptr)
+{
+ char *dst;
+
+ dst = *ptr;
+ *dst++ = (char)c;
+ *ptr = dst;
+ return 0 ;
+}
+/*****************************************************************************
+*****************************************************************************/
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ int rv;
+
+ rv = do_printf(fmt, args, vsprintf_help, (void *)buf);
+ buf[rv] = '\0';
+ return rv;
+}
+/*****************************************************************************
+*****************************************************************************/
+int sprintf(char *buf, const char *fmt, ...)
+{
+ va_list args;
+ int rv;
+
+ va_start(args, fmt);
+ rv = vsprintf(buf, fmt, args);
+ va_end(args);
+ return rv;
+}
+/*****************************************************************************
+PRINTF
+You must write your own putchar()
+*****************************************************************************/
+int vprintf_help(unsigned c, void **ptr)
+{
+ putchar(c);
+ return 0 ;
+}
+/*****************************************************************************
+*****************************************************************************/
+int vprintf(const char *fmt, va_list args)
+{
+ return do_printf(fmt, args, vprintf_help, NULL);
+}
+/*****************************************************************************
+*****************************************************************************/
+int printf(const char *fmt, ...)
+{
+ va_list args;
+ int rv;
+
+ va_start(args, fmt);
+ rv = vprintf(fmt, args);
+ va_end(args);
+ return rv;
+}
+
+#if 0 /* testing */
+/*****************************************************************************
+*****************************************************************************/
+int main(void)
+{
+ char buf[64];
+
+ sprintf(buf, "%lu score and %i years ago...\n", 4L, -7);
+ fputs(buf, stdout); /* puts() adds newline */
+
+ sprintf(buf, "-1L == 0x%lX == octal %lo\n", -1L, -1L);
+ fputs(buf, stdout); /* puts() adds newline */
+
+ printf("<%-8s> and <%8s> justified strings\n", "left", "right");
+
+ printf("short signed: %hd, short unsigned: %hu\n\n", -1, -1);
+
+ char str[] = "abcdefghijklmnopqrstuvwxyz";
+ printf("%8s\n", str); /* abcdefghijklmnopqrstuvwxyz */
+ printf("%8.32s\n", str); /* abcdefghijklmnopqrstuvwxyz */
+ printf("%8.16s\n", str); /* abcdefghijklmnop */
+ printf("%8.8s\n", str); /* abcdefgh */
+ printf("%8.4s\n", str); /* abcd */
+ printf("%4.8s\n", str); /* abcdefgh */
+ printf("%.8s\n", str); /* abcdefgh */
+ printf("%8s\n", "abcd"); /* abcd */
+ printf("%8.8s\n", "abcd"); /* abcd */
+ printf("%4.8s\n", "abcd"); /* abcd */
+ printf("%.8s\n", "abcd"); /* abcd */
+ printf("%.0s\n", str); /* */
+ printf("\n");
+
+ int num = 123456;
+ printf("%016d\n", num); /* 0000000000123456 */
+ printf("%16d\n", num); /* 123456 */
+ printf("%8d\n", num); /* 123456 */
+ printf("%8.16d\n", num); /* 0000000000123456 */
+ printf("%8.8d\n", num); /* 00123456 */
+ printf("%8.4d\n", num); /* 123456 */
+ printf("%4.4d\n", num); /* 123456 */
+ printf("%.16d\n", num); /* 0000000000123456 */
+ printf("%.8d\n", num); /* 00123456 */
+ printf("%.4d\n", num); /* 123456 */
+
+ return 0;
+}
+#else
+
+/*****************************************************************************
+2015-10-29 pselkirk for cryptech
+*****************************************************************************/
+/* gcc decides that a plain string with no formatting is best handled by puts() */
+int puts(const char *s)
+{
+ return printf("%s\n", s);
+}
+
+/* transmit characters to the uart */
+#include "stm-uart.h"
+int putchar(int c)
+{
+ if (c == '\n')
+ uart_send_char('\r');
+ uart_send_char((uint8_t) c);
+ return c;
+}
+#endif