diff options
author | Paul Selkirk <paul@psgd.org> | 2016-04-11 14:44:44 -0400 |
---|---|---|
committer | Paul Selkirk <paul@psgd.org> | 2016-04-11 14:44:44 -0400 |
commit | 79b1ba7104dba52dbfacf11a07305702889f440b (patch) | |
tree | 75a08fdc6e3af427e953f319b3fdb0f9dcfdf80e /projects | |
parent | d5669dac8c7ab2fbf6bd3c7faed7ce050c94ee1a (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/Makefile | 18 | ||||
-rw-r--r-- | projects/board-test/fmc-perf.c | 126 | ||||
-rw-r--r-- | projects/board-test/fmc-test.c | 240 | ||||
-rw-r--r-- | projects/board-test/led-test.c | 33 | ||||
-rw-r--r-- | projects/board-test/short-test.c | 205 | ||||
-rw-r--r-- | projects/board-test/uart-test.c | 34 | ||||
-rw-r--r-- | projects/libhal-test/Makefile | 33 | ||||
-rw-r--r-- | projects/libhal-test/gettimeofday.c | 63 | ||||
-rw-r--r-- | projects/libhal-test/main.c | 61 | ||||
-rw-r--r-- | projects/libhal-test/printf.c | 453 |
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
|