Merge pull request #12153 from mprse/spi_fpga_test_extend

Hackathon: Increase coverage of the SPI master FPGA test
pull/12438/head
Kevin Bracey 2020-01-31 15:00:02 +02:00 committed by GitHub
commit ba5dd4d8c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 292 additions and 82 deletions

View File

@ -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<Specified symbol size is not supported on this platform> skipped ");
utest_printf("\n<Specified symbol size is not supported on this platform> skipped. ");
return false;
}
// SPI clock mode
if (!TEST_CAPABILITY_BIT(capabilities->clk_modes, spi_mode)) {
utest_printf("\n<Specified spi clock mode is not supported on this platform> skipped");
utest_printf("\n<Specified spi clock mode is not supported on this platform> skipped. ");
return false;
}
// Frequency
if (frequency != FREQ_MAX && frequency != FREQ_MIN && frequency < capabilities->minimum_frequency && frequency > capabilities->maximum_frequency) {
utest_printf("\n<Specified frequency is not supported on this platform> skipped ");
utest_printf("\n<Specified frequency is not supported on this platform> skipped. ");
return false;
}
// Async mode
if (transfer_type == TRANSFER_SPI_MASTER_TRANSFER_ASYNC && capabilities->async_mode == false) {
utest_printf("\n<Async mode is not supported on this platform> skipped ");
utest_printf("\n<Async mode is not supported on this platform> 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<RX length != TX length is not supported on this platform> 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<SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency, bool init_direct>
template<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>
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<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>
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<SPIPort, DefaultFormFactor, fpga_spi_test_init_free>),
Case("SPI - init/free test all pins", all_ports<SPINoCSPort, DefaultFormFactor, fpga_spi_test_init_free>),
// This will be run for all peripherals
Case("SPI - basic test", all_peripherals<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, false> >),
Case("SPI - basic test (direct init)", all_peripherals<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, true> >),
Case("SPI - basic test", all_peripherals<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - basic test (direct init)", all_peripherals<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, true> >),
// This will be run for single pin configuration
Case("SPI - mode testing (MODE_1)", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode1, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, false> >),
Case("SPI - mode testing (MODE_2)", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode2, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, false> >),
Case("SPI - mode testing (MODE_3)", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode3, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, false> >),
Case("SPI - symbol size testing (16)", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 16, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, false> >),
Case("SPI - frequency testing (500 kHz)", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_500_KHZ, false> >),
Case("SPI - frequency testing (2 MHz)", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_2_MHZ, false> >),
Case("SPI - block write", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, false> >),
Case("SPI - mode testing (MODE_1)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode1, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - mode testing (MODE_2)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode2, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - mode testing (MODE_3)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode3, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - symbol size testing (4)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 4, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - symbol size testing (12)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 12, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - symbol size testing (16)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 16, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - symbol size testing (24)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 24, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - symbol size testing (32)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 32, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - buffers tx > rx", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_TX_GT_RX, false, false> >),
Case("SPI - buffers tx < rx", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_TX_LT_RX, false, false> >),
Case("SPI - frequency testing (200 kHz)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_200_KHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - frequency testing (2 MHz)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_2_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - frequency testing (capabilities min)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_MIN, BUFFERS_COMMON, false, false> >),
Case("SPI - frequency testing (capabilities max)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_MAX, BUFFERS_COMMON, false, false> >),
Case("SPI - block write", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - block write(one sym)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_TX_ONE_SYM, false, false> >),
Case("SPI - hardware ss handling", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, true, false> >),
Case("SPI - hardware ss handling(block)", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, true, false> >),
#if DEVICE_SPI_ASYNCH
Case("SPI - async mode", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_TRANSFER_ASYNC, FREQ_1_MHZ, false> >)
Case("SPI - async mode (sw ss)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_TRANSFER_ASYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - async mode (hw ss)", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_TRANSFER_ASYNC, FREQ_1_MHZ, BUFFERS_COMMON, true, false> >)
#endif
};

View File

@ -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

View File

@ -56,6 +56,7 @@ MBED_WEAK void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t
cap->hw_cs_handle = false; // irrelevant in slave mode
cap->slave_delay_between_symbols_ns = 2500; // 2.5 us
cap->clk_modes = 0x0f; // all clock modes
cap->tx_rx_buffers_equal_length = true; // rx buffer size must be equal tx buffer size
#if DEVICE_SPI_ASYNCH
cap->async_mode = true;
#else
@ -69,6 +70,7 @@ MBED_WEAK void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t
cap->hw_cs_handle = false; // to be determined later based on ssel
cap->slave_delay_between_symbols_ns = 0; // irrelevant in master mode
cap->clk_modes = 0x0f; // all clock modes
cap->tx_rx_buffers_equal_length = true; // rx buffer size must be equal tx buffer size
#if DEVICE_SPI_ASYNCH
cap->async_mode = true;
#else

View File

@ -84,7 +84,7 @@ typedef struct {
bool support_slave_mode; /**< If true, the device can handle SPI slave mode using hardware management on the specified ssel pin. */
bool hw_cs_handle; /**< If true, in SPI master mode Chip Select can be handled by hardware. */
bool async_mode; /**< If true, in async mode is supported. */
bool tx_rx_buffers_equal_length; /**< If true, rx and tx buffers must have the same length. */
} spi_capabilities_t;
#ifdef __cplusplus
@ -96,41 +96,41 @@ extern "C" {
*
* # Defined behavior
* * ::spi_init initializes the spi_t control structure
* * ::spi_init configures the pins used by SPI
* * ::spi_get_capabilities() fills the given `spi_capabilities_t` instance
* * ::spi_get_capabilities() should consider the `ssel` pin when evaluation the `support_slave_mode` and `hw_cs_handle` capability
* * ::spi_get_capabilities(): if the given `ssel` pin cannot be managed by hardware, `support_slave_mode` and `hw_cs_handle` should be false
* * At least a symbol width of 8bit must be supported
* * The supported frequency range must include the range [0.2..2] MHz
* * ::spi_free returns the pins owned by the SPI object to their reset state
* * ::spi_format sets the number of bits per frame
* * ::spi_format configures clock polarity and phase
* * ::spi_format configures master/slave mode
* * ::spi_frequency sets the SPI baud rate
* * ::spi_master_write writes a symbol out in master mode and receives a symbol
* * ::spi_master_block_write writes `tx_length` words to the bus
* * ::spi_master_block_write reads `rx_length` words from the bus
* * ::spi_master_block_write returns the maximum of tx_length and rx_length
* * ::spi_master_block_write specifies the write_fill which is default data transmitted while performing a read
* * ::spi_get_module returns non-zero if a value is available to read from SPI channel, 0 otherwise
* * ::spi_slave_read returns a received value out of the SPI receive buffer in slave mode
* * ::spi_slave_read blocks until a value is available
* * ::spi_slave_write writes a value to the SPI peripheral in slave mode
* * ::spi_slave_write blocks until the SPI peripheral can be written to
* * ::spi_busy returns non-zero if the peripheral is currently transmitting, 0 otherwise
* * ::spi_master_transfer starts the SPI asynchronous transfer
* * ::spi_master_transfer writes `tx_len` words to the bus
* * ::spi_master_transfer reads `rx_len` words from the bus
* * ::spi_master_transfer specifies the bit width of buffer words
* * The callback given to ::spi_master_transfer is invoked when the transfer completes (with a success or an error)
* * ::spi_master_transfer specifies the logical OR of events to be registered
* * The ::spi_master_transfer function may use the `DMAUsage` hint to select the appropriate async algorithm
* * ::spi_irq_handler_asynch reads the received values out of the RX FIFO
* * ::spi_irq_handler_asynch writes values into the TX FIFO
* * ::spi_irq_handler_asynch checks for transfer termination conditions, such as buffer overflows or transfer complete
* * ::spi_irq_handler_asynch returns event flags if a transfer termination condition was met, otherwise 0
* * ::spi_abort_asynch aborts an on-going async transfer
* * ::spi_active returns non-zero if the SPI port is active or zero if it is not
* * ::spi_init configures the pins used by SPI - Verified by ::fpga_spi_test_init_free, ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_get_capabilities() fills the given `spi_capabilities_t` instance - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_get_capabilities() should consider the `ssel` pin when evaluation the `support_slave_mode` and `hw_cs_handle` capability - TBD (basic test)
* * ::spi_get_capabilities(): if the given `ssel` pin cannot be managed by hardware, `support_slave_mode` and `hw_cs_handle` should be false - TBD (basic test)
* * At least a symbol width of 8bit must be supported - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * The supported frequency range must include the range [0.2..2] MHz - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_free returns the pins owned by the SPI object to their reset state - Verified by ::fpga_spi_test_init_free
* * ::spi_format sets the number of bits per frame - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_format configures clock polarity and phase - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_format configures master/slave mode - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common; slave mode - TBD
* * ::spi_frequency sets the SPI baud rate - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_master_write writes a symbol out in master mode and receives a symbol - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_master_block_write writes `tx_length` words to the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_master_block_write reads `rx_length` words from the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_master_block_write returns the maximum of tx_length and rx_length - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_master_block_write specifies the write_fill which is default data transmitted while performing a read - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_get_module returns the SPI module number - TBD (basic test)
* * ::spi_slave_read returns a received value out of the SPI receive buffer in slave mode - TBD (SPI slave test)
* * ::spi_slave_read blocks until a value is available - TBD (SPI slave test)
* * ::spi_slave_write writes a value to the SPI peripheral in slave mode - TBD (SPI slave test)
* * ::spi_slave_write blocks until the SPI peripheral can be written to - TBD (SPI slave test)
* * ::spi_busy returns non-zero if the peripheral is currently transmitting, 0 otherwise - TBD (basic test)
* * ::spi_master_transfer starts the SPI asynchronous transfer - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_master_transfer writes `tx_len` words to the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_master_transfer reads `rx_len` words from the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_master_transfer specifies the bit width of buffer words - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * The callback given to ::spi_master_transfer is invoked when the transfer completes (with a success or an error) - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_master_transfer specifies the logical OR of events to be registered - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * The ::spi_master_transfer function may use the `DMAUsage` hint to select the appropriate async algorithm - Not testable
* * ::spi_irq_handler_asynch reads the received values out of the RX FIFO - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_irq_handler_asynch writes values into the TX FIFO - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_irq_handler_asynch checks for transfer termination conditions, such as buffer overflows or transfer complete - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_irq_handler_asynch returns event flags if a transfer termination condition was met, otherwise 0 - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common
* * ::spi_abort_asynch aborts an on-going async transfer - TBD (basic test)
* * ::spi_active returns non-zero if the SPI port is active or zero if it is not - TBD (basic test)
*
* # Undefined behavior
* * Calling ::spi_init multiple times on the same `spi_t` without ::spi_free

View File

@ -138,6 +138,7 @@ void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap)
cap->hw_cs_handle = false; // irrelevant in slave mode
cap->slave_delay_between_symbols_ns = 2500; // 2.5 us
cap->clk_modes = 0x0f; // all clock modes
cap->tx_rx_buffers_equal_length = false; // rx/tx buffers can have different sizes
#if DEVICE_SPI_ASYNCH
cap->async_mode = true;
#else
@ -151,6 +152,7 @@ void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap)
cap->hw_cs_handle = false; // to be determined later based on ssel
cap->slave_delay_between_symbols_ns = 0; // irrelevant in master mode
cap->clk_modes = 0x0f; // all clock modes
cap->tx_rx_buffers_equal_length = false; // rx/tx buffers can have different sizes
#if DEVICE_SPI_ASYNCH
cap->async_mode = true;
#else

View File

@ -71,6 +71,53 @@
extern HAL_StatusTypeDef HAL_SPIEx_FlushRxFifo(SPI_HandleTypeDef *hspi);
#endif
void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap)
{
if (slave) {
cap->minimum_frequency = 200000; // 200 kHz
cap->maximum_frequency = 2000000; // 2 MHz
cap->word_length = 0x00008080; // 8 and 16 bit symbols
cap->support_slave_mode = false; // to be determined later based on ssel
cap->hw_cs_handle = false; // irrelevant in slave mode
cap->slave_delay_between_symbols_ns = 2500; // 2.5 us
cap->clk_modes = 0x0f; // all clock modes
cap->tx_rx_buffers_equal_length = false; // rx/tx buffers can have different sizes
#if DEVICE_SPI_ASYNCH
cap->async_mode = true;
#else
cap->async_mode = false;
#endif
} else {
cap->minimum_frequency = 200000; // 200 kHz
cap->maximum_frequency = 2000000; // 2 MHz
cap->word_length = 0x00008080; // 8 and 16 bit symbols
cap->support_slave_mode = false; // to be determined later based on ssel
cap->hw_cs_handle = false; // to be determined later based on ssel
cap->slave_delay_between_symbols_ns = 0; // irrelevant in master mode
cap->clk_modes = 0x0f; // all clock modes
cap->tx_rx_buffers_equal_length = false; // rx/tx buffers can have different sizes
#if DEVICE_SPI_ASYNCH
cap->async_mode = true;
#else
cap->async_mode = false;
#endif
}
// check if given ssel pin is in the cs pinmap
const PinMap *cs_pins = spi_master_cs_pinmap();
PinName pin = NC;
while (cs_pins->pin != NC) {
if (cs_pins->pin == ssel) {
#if DEVICE_SPISLAVE
cap->support_slave_mode = true;
#endif
cap->hw_cs_handle = true;
break;
}
cs_pins++;
}
}
void init_spi(spi_t *obj)
{
struct spi_s *spiobj = SPI_S(obj);