From 4b6c844be9574ae9177eaf28549f505083d62356 Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Fri, 20 Dec 2019 11:21:53 +0100 Subject: [PATCH] Extend FPGA-Test-Shield SPI master test Increase coverage of the SPI master FPGA test: - check supported frequencies (based on the device capabilities), - add support for manual CS handling and test cases, - add test cases for rx/tx buffers with different length (based on the device capabilities), - add test case for one symbol transmission, - add test cases for different symbol sizes (based on the device capabilities). --- .../mbed_hal_fpga_ci_test_shield/spi/main.cpp | 238 ++++++++++++++---- .../spi/spi_fpga_test.h | 13 +- 2 files changed, 205 insertions(+), 46 deletions(-) diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp index 7fde81864f..0fc4d26dbf 100644 --- a/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp +++ b/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp @@ -35,18 +35,31 @@ using namespace utest::v1; - typedef enum { TRANSFER_SPI_MASTER_WRITE_SYNC, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, TRANSFER_SPI_MASTER_TRANSFER_ASYNC } transfer_type_t; -#define FREQ_500_KHZ 500000 -#define FREQ_1_MHZ 1000000 -#define FREQ_2_MHZ 2000000 +typedef enum { + BUFFERS_COMMON, // common case rx/tx buffers are defined and have the same size + BUFFERS_TX_GT_RX, // tx buffer length is greater than rx buffer length + BUFFERS_TX_LT_RX, // tx buffer length is less than rx buffer length + BUFFERS_TX_ONE_SYM, // one symbol only is transmitted in both directions +} test_buffers_t; + +#define FREQ_200_KHZ (200000ull) +#define FREQ_500_KHZ (500000) +#define FREQ_1_MHZ (1000000) +#define FREQ_2_MHZ (2000000) +#define FREQ_10_MHZ (10000000ull) #define FREQ_MIN ((uint32_t)0) #define FREQ_MAX ((uint32_t)-1) +#define FILL_SYM (0xF5F5F5F5) +#define DUMMY_SYM (0xD5D5D5D5) + +#define SS_ASSERT (0) +#define SS_DEASSERT (!(SS_ASSERT)) #define TEST_CAPABILITY_BIT(MASK, CAP) ((1 << CAP) & (MASK)) @@ -67,57 +80,144 @@ void spi_async_handler() } #endif +/* Function finds SS pin for manual SS handling. */ +static PinName find_ss_pin(PinName mosi, PinName miso, PinName sclk) +{ + const PinList *ff_pins_list = pinmap_ff_default_pins(); + const PinList *restricted_pins_list = pinmap_restricted_pins(); + uint32_t cs_pin_idx; + + for (cs_pin_idx = 0; cs_pin_idx < ff_pins_list->count; cs_pin_idx++) { + if (ff_pins_list->pins[cs_pin_idx] == mosi || + ff_pins_list->pins[cs_pin_idx] == miso || + ff_pins_list->pins[cs_pin_idx] == sclk) { + continue; + } + + bool restricted_pin = false; + for (uint32_t i = 0; i < restricted_pins_list->count ; i++) { + if (ff_pins_list->pins[cs_pin_idx] == restricted_pins_list->pins[i]) { + restricted_pin = true; + } + } + + if (restricted_pin) { + continue; + } else { + break; + } + } + + PinName ssel = (cs_pin_idx == ff_pins_list->count ? NC : ff_pins_list->pins[cs_pin_idx]); + + TEST_ASSERT_MESSAGE(ssel != NC, "Unable to find pin for Chip Select"); + + return ssel; +} + +/* Function handles ss line if ss is specified. */ +static void handle_ss(DigitalOut *ss, bool select) +{ + if (ss) { + if (select) { + *ss = SS_ASSERT; + } else { + *ss = SS_DEASSERT; + } + } +} + /* Auxiliary function to check platform capabilities against test case. */ -static bool check_capabilities(const spi_capabilities_t *capabilities, SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency) +static bool check_capabilities(const spi_capabilities_t *capabilities, SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency, test_buffers_t test_buffers) { // Symbol size if (!TEST_CAPABILITY_BIT(capabilities->word_length, (sym_size - 1))) { - utest_printf("\n skipped "); + utest_printf("\n skipped. "); return false; } // SPI clock mode if (!TEST_CAPABILITY_BIT(capabilities->clk_modes, spi_mode)) { - utest_printf("\n skipped"); + utest_printf("\n skipped. "); return false; } // Frequency if (frequency != FREQ_MAX && frequency != FREQ_MIN && frequency < capabilities->minimum_frequency && frequency > capabilities->maximum_frequency) { - utest_printf("\n skipped "); + utest_printf("\n skipped. "); return false; } // Async mode if (transfer_type == TRANSFER_SPI_MASTER_TRANSFER_ASYNC && capabilities->async_mode == false) { - utest_printf("\n skipped "); + utest_printf("\n skipped. "); + return false; + } + + if ((test_buffers == BUFFERS_TX_GT_RX || test_buffers == BUFFERS_TX_LT_RX) && capabilities->tx_rx_buffers_equal_length == true) { + utest_printf("\n skipped. "); return false; } return true; } -void fpga_spi_test_init_free(PinName mosi, PinName miso, PinName sclk, PinName ssel) +void fpga_spi_test_init_free(PinName mosi, PinName miso, PinName sclk) { - spi_init(&spi, mosi, miso, sclk, ssel); - spi_format(&spi, 8, SPITester::Mode0, 0); + spi_init(&spi, mosi, miso, sclk, NC); + spi_format(&spi, 8, 0, 0); spi_frequency(&spi, 1000000); spi_free(&spi); } -void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel, SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency, bool init_direct) +void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel, SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency, test_buffers_t test_buffers, bool auto_ss, bool init_direct) { spi_capabilities_t capabilities; - + uint32_t freq = frequency; + uint32_t tx_cnt = TRANSFER_COUNT; + uint32_t rx_cnt = TRANSFER_COUNT; + uint8_t fill_symbol = (uint8_t)FILL_SYM; + PinName ss_pin = (auto_ss ? ssel : NC); + DigitalOut *ss = NULL; spi_get_capabilities(ssel, false, &capabilities); - if (check_capabilities(&capabilities, spi_mode, sym_size, transfer_type, frequency) == false) { + if (check_capabilities(&capabilities, spi_mode, sym_size, transfer_type, frequency, test_buffers) == false) { return; } uint32_t sym_mask = ((1 << sym_size) - 1); + switch (frequency) { + case (FREQ_MIN): + freq = capabilities.minimum_frequency; + break; + case (FREQ_MAX): + freq = capabilities.maximum_frequency; + break; + default: + break; + } + + switch (test_buffers) { + case (BUFFERS_COMMON): + // nothing to change + break; + case (BUFFERS_TX_GT_RX): + rx_cnt /= 2; + break; + case (BUFFERS_TX_LT_RX): + tx_cnt /= 2; + break; + case (BUFFERS_TX_ONE_SYM): + tx_cnt = 1; + rx_cnt = 1; + break; + + default: + break; + } + // Remap pins for test tester.reset(); tester.pin_map_set(mosi, MbedTester::LogicalPinSPIMosi); @@ -125,17 +225,20 @@ void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel tester.pin_map_set(sclk, MbedTester::LogicalPinSPISclk); tester.pin_map_set(ssel, MbedTester::LogicalPinSPISsel); - // Initialize mbed SPI pins + // Manually handle SS pin + if (!auto_ss) { + ss = new DigitalOut(ssel, SS_DEASSERT); + } if (init_direct) { - const spi_pinmap_t pinmap = get_spi_pinmap(mosi, miso, sclk, ssel); + const spi_pinmap_t pinmap = get_spi_pinmap(mosi, miso, sclk, ss_pin); spi_init_direct(&spi, &pinmap); } else { - spi_init(&spi, mosi, miso, sclk, ssel); + spi_init(&spi, mosi, miso, sclk, ss_pin); } spi_format(&spi, sym_size, spi_mode, 0); - spi_frequency(&spi, frequency); + spi_frequency(&spi, freq); // Configure spi_slave module tester.set_mode(spi_mode); @@ -147,6 +250,7 @@ void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel tester.select_peripheral(SPITester::PeripheralSPI); uint32_t checksum = 0; + uint32_t sym_count = TRANSFER_COUNT; int result = 0; uint8_t tx_buf[TRANSFER_COUNT] = {0}; uint8_t rx_buf[TRANSFER_COUNT] = {0}; @@ -154,27 +258,55 @@ void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel // Send and receive test data switch (transfer_type) { case TRANSFER_SPI_MASTER_WRITE_SYNC: + handle_ss(ss, true); for (int i = 0; i < TRANSFER_COUNT; i++) { uint32_t data = spi_master_write(&spi, (0 - i) & sym_mask); TEST_ASSERT_EQUAL(i & sym_mask, data); - checksum += (0 - i) & sym_mask; } + handle_ss(ss, false); break; case TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC: for (int i = 0; i < TRANSFER_COUNT; i++) { tx_buf[i] = (0 - i) & sym_mask; - checksum += (0 - i) & sym_mask; - rx_buf[i] = 0xAA; + rx_buf[i] = 0xFF; + + switch (test_buffers) { + case (BUFFERS_COMMON): + case (BUFFERS_TX_GT_RX): + checksum += ((0 - i) & sym_mask); + break; + case (BUFFERS_TX_LT_RX): + if (i < tx_cnt) { + checksum += ((0 - i) & sym_mask); + } else { + checksum += (fill_symbol & sym_mask); + } + break; + case (BUFFERS_TX_ONE_SYM): + tx_buf[0] = 0xAA; + checksum = 0xAA; + sym_count = 1; + break; + default: + break; + } } - result = spi_master_block_write(&spi, (const char *)tx_buf, TRANSFER_COUNT, (char *)rx_buf, TRANSFER_COUNT, 0xF5); + handle_ss(ss, true); + result = spi_master_block_write(&spi, (const char *)tx_buf, tx_cnt, (char *)rx_buf, rx_cnt, 0xF5); + handle_ss(ss, false); - for (int i = 0; i < TRANSFER_COUNT; i++) { + for (int i = 0; i < rx_cnt; i++) { TEST_ASSERT_EQUAL(i & sym_mask, rx_buf[i]); } - TEST_ASSERT_EQUAL(TRANSFER_COUNT, result); + + for (int i = rx_cnt; i < TRANSFER_COUNT; i++) { + TEST_ASSERT_EQUAL(0xFF, rx_buf[i]); + } + + TEST_ASSERT_EQUAL(sym_count, result); break; #if DEVICE_SPI_ASYNCH @@ -187,8 +319,11 @@ void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel async_trasfer_done = false; + handle_ss(ss, true); spi_master_transfer(&spi, tx_buf, TRANSFER_COUNT, rx_buf, TRANSFER_COUNT, 8, (uint32_t)spi_async_handler, SPI_EVENT_COMPLETE, DMA_USAGE_NEVER); + while (!async_trasfer_done); + handle_ss(ss, false); for (int i = 0; i < TRANSFER_COUNT; i++) { TEST_ASSERT_EQUAL(i & sym_mask, rx_buf[i]); @@ -196,7 +331,6 @@ void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel break; #endif - default: TEST_ASSERT_MESSAGE(0, "Unsupported transfer type."); break; @@ -204,41 +338,57 @@ void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel } // Verify that the transfer was successful - TEST_ASSERT_EQUAL(TRANSFER_COUNT, tester.get_transfer_count()); + TEST_ASSERT_EQUAL(sym_count, tester.get_transfer_count()); TEST_ASSERT_EQUAL(checksum, tester.get_receive_checksum()); spi_free(&spi); tester.reset(); } -template +template void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel) { - fpga_spi_test_common(mosi, miso, sclk, ssel, spi_mode, sym_size, transfer_type, frequency, init_direct); + fpga_spi_test_common(mosi, miso, sclk, ssel, spi_mode, sym_size, transfer_type, frequency, test_buffers, auto_ss, init_direct); +} + +template +void fpga_spi_test_common_no_ss(PinName mosi, PinName miso, PinName sclk) +{ + PinName ssel = find_ss_pin(mosi, miso, sclk); + + fpga_spi_test_common(mosi, miso, sclk, ssel, spi_mode, sym_size, transfer_type, frequency, test_buffers, auto_ss, init_direct); } Case cases[] = { // This will be run for all pins - Case("SPI - init/free test all pins", all_ports), + Case("SPI - init/free test all pins", all_ports), // This will be run for all peripherals - Case("SPI - basic test", all_peripherals >), - Case("SPI - basic test (direct init)", all_peripherals >), + Case("SPI - basic test", all_peripherals >), + Case("SPI - basic test (direct init)", all_peripherals >), // This will be run for single pin configuration - Case("SPI - mode testing (MODE_1)", one_peripheral >), - Case("SPI - mode testing (MODE_2)", one_peripheral >), - Case("SPI - mode testing (MODE_3)", one_peripheral >), - - Case("SPI - symbol size testing (16)", one_peripheral >), - - Case("SPI - frequency testing (500 kHz)", one_peripheral >), - Case("SPI - frequency testing (2 MHz)", one_peripheral >), - - Case("SPI - block write", one_peripheral >), - + Case("SPI - mode testing (MODE_1)", one_peripheral >), + Case("SPI - mode testing (MODE_2)", one_peripheral >), + Case("SPI - mode testing (MODE_3)", one_peripheral >), + Case("SPI - symbol size testing (4)", one_peripheral >), + Case("SPI - symbol size testing (12)", one_peripheral >), + Case("SPI - symbol size testing (16)", one_peripheral >), + Case("SPI - symbol size testing (24)", one_peripheral >), + Case("SPI - symbol size testing (32)", one_peripheral >), + Case("SPI - buffers tx > rx", one_peripheral >), + Case("SPI - buffers tx < rx", one_peripheral >), + Case("SPI - frequency testing (200 kHz)", one_peripheral >), + Case("SPI - frequency testing (2 MHz)", one_peripheral >), + Case("SPI - frequency testing (capabilities min)", one_peripheral >), + Case("SPI - frequency testing (capabilities max)", one_peripheral >), + Case("SPI - block write", one_peripheral >), + Case("SPI - block write(one sym)", one_peripheral >), + Case("SPI - hardware ss handling", one_peripheral >), + Case("SPI - hardware ss handling(block)", one_peripheral >), #if DEVICE_SPI_ASYNCH - Case("SPI - async mode", one_peripheral >) + Case("SPI - async mode (sw ss)", one_peripheral >), + Case("SPI - async mode (hw ss)", one_peripheral >) #endif }; diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/spi/spi_fpga_test.h b/TESTS/mbed_hal_fpga_ci_test_shield/spi/spi_fpga_test.h index 81d7d380e9..14a2306398 100644 --- a/TESTS/mbed_hal_fpga_ci_test_shield/spi/spi_fpga_test.h +++ b/TESTS/mbed_hal_fpga_ci_test_shield/spi/spi_fpga_test.h @@ -37,15 +37,24 @@ extern "C" { */ void fpga_spi_test_init_free(PinName mosi, PinName miso, PinName sclk, PinName ssel); -/** Test that the SPI-Master transfer can be performed in various configurations. +/** Test that the SPI-Master transfer can be performed in various configurations (SSEL handled by hardware). * * Given board provides SPI-Master support. * When SPI transmission is performed using different settings. - * Then data is successfully transfered. + * Then data is successfully transferred. * */ void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel); +/** Test that the SPI-Master transfer can be performed in various configurations (SSEL handled manually). + * + * Given board provides SPI-Master support. + * When SPI transmission is performed using different settings. + * Then data is successfully transferred. + * + */ +void fpga_spi_test_common_no_ss(PinName mosi, PinName miso, PinName sclk); + /**@}*/ #ifdef __cplusplus