From 5124fa3baa02fab9ecdb154e888755c5598af285 Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Thu, 29 Nov 2018 13:19:20 +0100 Subject: [PATCH 1/5] Add one board Green Tea SPI Communication Test --- TESTS/mbed_hal/spi_com/README.md | 157 ++++++ TESTS/mbed_hal/spi_com/com_test.png | Bin 0 -> 10460 bytes TESTS/mbed_hal/spi_com/main.cpp | 527 ++++++++++++++++++ TESTS/mbed_hal/spi_com/spi_com_test.h | 49 ++ .../spi_com/spi_ob_wire_connection.png | Bin 0 -> 6255 bytes 5 files changed, 733 insertions(+) create mode 100644 TESTS/mbed_hal/spi_com/README.md create mode 100644 TESTS/mbed_hal/spi_com/com_test.png create mode 100644 TESTS/mbed_hal/spi_com/main.cpp create mode 100644 TESTS/mbed_hal/spi_com/spi_com_test.h create mode 100644 TESTS/mbed_hal/spi_com/spi_ob_wire_connection.png diff --git a/TESTS/mbed_hal/spi_com/README.md b/TESTS/mbed_hal/spi_com/README.md new file mode 100644 index 00000000000..7804efbe1f9 --- /dev/null +++ b/TESTS/mbed_hal/spi_com/README.md @@ -0,0 +1,157 @@ +One Board SPI Communication Test +============= + +### tests-mbed_hal-spi_com + +Overview +---------------- +This is the SPI communication test which verifies various SPI configuration variants. The test is based on Green Tea framework. The test transfers data between SPI master and SPI slave on the same device. + +Test Setup +---------------- +1. **Pre-requirements** + - One Mbed board with SPI support + - Board must have two SPI peripherals available + - Board must support SPI slave mode + - Wire connection between SPI interfaces + + ![alt text](spi_ob_wire_connection.png) + +2. **Running the test** + - Test assumes that SPI pins are defined in target's `PinNames.h` file: + - `SPI0_MOSI`, `SPI0_MISO`, `SPI0_SCK`, `SPI0_CS` + - `SPI1_MOSI`, `SPI1_MISO`, `SPI1_SCK`, `SPI1_CS` + - Wire the 4 pins for each peripheral. + - Set `MANUAL_TEST` macro in the test to `1`. + - Run the test using the following command: + `mbed test -t TOOLCHAIN -m BOARD -n tests-mbed_hal-spi_com` + +Test scenario +---------------- +Typical SPI transmission schema during the test is shown below: + +![alt text](com_test.png) + +Five predefined(different) symbols are sent in both directions using different SPI configurations. + +- Test for synchronous API + - CS is asserted high (inactive state). + - Configuration is validated against device capabilities. + - If master or slave cannot handle this configuration the test case is skipped. + - Format configuration is set for both master and slave. + - Frequency configuration is set on the master peripheral. + - Reception buffers and semaphores are reinitialized. + - A thread is started for the slave side. + - A thread is started for the master side. + - The master thread asserts CS to 0 (active state), performs the transfer and asserts CS back to 1. + - The test thread (main) waits until either the semaphore is given twice or we it reaches a timeout. + - Master & slave rx buffers are respectively compared to slave & master tx buffers. + - If a buffer do not match, then the test fails. + - Both SPI peripheral are freed and the next test starts. + +**Note:** +On master side data is transferred symbol by symbol (i.e. when 5 symbols is to be transferred, then transfer routine is called 5 times in loop). This is the limitation of the one board SPI communication test. + +- Test for asynchronous API + - CS is asserted high (inactive state). + - Configuration is validated against device capabilities + - If master or slave cannot handle this configuration the test case is skipped. + - Format configuration is set for both master and slave. + - Frequency configuration is set on the master peripheral. + - Reception buffers and semaphores are reinitialized. + - The spi_transfer_async() function is called for the slave peripheral. + - The CS is asserted to 0 (active state). + - spi_trasnfer_async() is called for the master peripheral. + - The CS is asserted back to 1 (inactive state). + - Master & slave rx buffers are respectively compared to slave & master tx buffers. + - If a buffer do not match, then the test fails. + - Both SPI peripheral are freed and the next test starts. + +What is verified by the test? +---------------- +| | Test case | Testing | Description | +|-----|----------------------------------------------------------------|---------------------------|----------------------------------------------------------| +| 1 | **SPI master-slave sync com - default config** | Sync/General | Verifies most commonly used SPI configuration* | +| 2 | SPI master-slave sync com - symbol size: 1 | Sync/Symbol sizes | Symbol size is equal to 1 | +| 3 | SPI master-slave sync com - symbol size: 7 | Sync/Symbol sizes | Symbol size is equal to 7 | +| 4 | SPI master-slave sync com - symbol size: 9 | Sync/Symbol sizes | Symbol size is equal to 9 | +| 5 | SPI master-slave sync com - symbol size: 15 | Sync/Symbol sizes | Symbol size is equal to 15 | +| 6 | SPI master-slave sync com - symbol size: 16 | Sync/Symbol sizes | Symbol size is equal to 16 | +| 7 | SPI master-slave sync com - symbol size: 17 | Sync/Symbol sizes | Symbol size is equal to 17 | +| 8 | SPI master-slave sync com - symbol size: 31 | Sync/Symbol sizes | Symbol size is equal to 31 | +| 9 | SPI master-slave sync com - symbol size: 32 | Sync/Symbol sizes | Symbol size is equal to 32 | +| 10 | SPI master-slave sync com - mode: idle low, sample second edge | Sync/Clock polarity/phase | Clock idle high/sampling on the first edge | +| 11 | SPI master-slave sync com - mode: idle high, sample first edge | Sync/Clock polarity/phase | Clock idle high/sampling on the second edge | +| 12 | SPI master-slave sync com - mode: idle high, sample second edge| Sync/Clock polarity/phase | Clock idle low/sampling on the first edge | +| 13 | SPI master-slave sync com - bit ordering: LSB first | Sync/Bit order | LSB transmitted first | +| 14 | SPI master-slave sync com - master: manual ss | Sync/SS handling | Internal SS handling by master | +| 15 | SPI master-slave sync com - freq testing: 200 KHz | Sync/Frequency | Minimum required frequency (200 kHz) | +| 16 | SPI master-slave sync com - freq testing: 2 MHz | Sync/Frequency | Maximum required frequency (2 MHz) | +| 17 | SPI master-slave sync com - freq testing: min defined | Sync/Frequency | Minimum frequency specified in capabilities | +| 18 | SPI master-slave sync com - freq testing: max defined | Sync/Frequency | Maximum frequency specified in capabilities | +| 19 | SPI master-slave sync com - master: TX undefined | Sync/Buffers | Master TX buffer is undefined (NULL) | +| 20 | SPI master-slave sync com - master: RX undefined | Sync/Buffers | Master RX buffer is undefined (NULL) | +| 21 | SPI master-slave sync com - slave: TX undefined | Sync/Buffers | Slave TX buffer is undefined (NULL) | +| 22 | SPI master-slave sync com - slave: RX undefined | Sync/Buffers | Slave RX buffer is undefined (NULL) | +| 23 | SPI master-slave sync com - master: TX > RX | Sync/Buffers | Master TX buffer size is greater than RX buffer size | +| 24 | SPI master-slave sync com - master: TX < RX | Sync/Buffers | Master TX buffer size is less than RX buffer size | +| 25 | SPI master-slave sync com - slave: TX > RX | Sync/Buffers | SLAVE TX buffer size is greater than RX buffer size | +| 26 | SPI master-slave sync com - slave: TX < RX | Sync/Buffers | SLAVE TX buffer size is less than RX buffer size | +| 27 | SPI master-slave sync com - one symbol | Sync/Buffers | 1 symbol is transmitted | +| 28 | SPI master-slave sync com - long buffer | Sync/Buffers | 64 symbols are transmitted | +| 29 | SPI master-slave async com - default config | Aync/General | Verifies most commonly used SPI configuration | +| 30 | SPI master-slave sync com - symbol size: 1 | Aync/Symbol sizes | Symbol size is equal to 1 | +| 31 | SPI master-slave sync com - symbol size: 7 | Aync/Symbol sizes | Symbol size is equal to 7 | +| 32 | SPI master-slave sync com - symbol size: 9 | Aync/Symbol sizes | Symbol size is equal to 9 | +| 33 | SPI master-slave sync com - symbol size: 15 | Aync/Symbol sizes | Symbol size is equal to 15 | +| 34 | SPI master-slave sync com - symbol size: 16 | Aync/Symbol sizes | Symbol size is equal to 16 | +| 35 | SPI master-slave sync com - symbol size: 17 | Aync/Symbol sizes | Symbol size is equal to 17 | +| 36 | SPI master-slave sync com - symbol size: 31 | Aync/Symbol sizes | Symbol size is equal to 31 | +| 37 | SPI master-slave sync com - symbol size: 32 | Aync/Symbol sizes | Symbol size is equal to 32 | +| 38 | SPI master-slave sync com - mode: idle low, sample second edge | Aync/Clock polarity/phase | Clock idle high/sampling on the first edge | +| 39 | SPI master-slave sync com - mode: idle high, sample first edge | Aync/Clock polarity/phase | Clock idle high/sampling on the second edge | +| 40 | SPI master-slave sync com - mode: idle high, sample second edge| Aync/Clock polarity/phase | Clock idle low/sampling on the first edge | +| 41 | SPI master-slave sync com - bit ordering: LSB first | Aync/Bit order | LSB transmitted first | +| 42 | SPI master-slave sync com - freq testing: 200 KHz | Aync/Frequency | Minimum required frequency (200 kHz) | +| 43 | SPI master-slave sync com - freq testing: 2 MHz | Aync/Frequency | Maximum required frequency (2 MHz) | +| 44 | SPI master-slave sync com - master: manual ss | Aync/SS handling | Internal SS handling by master | +| 45 | SPI master-slave sync com - one symbol | Aync/Buffers | 1 symbol is transmitted | +| 46 | SPI master-slave sync com - long buffer | Aync/Buffers | 32 symbols are transmitted | + +Synchronous and asynchronous modes are tested separately. + + `*` - `default config` test case verifies the most typical SPI configuration which is: +- Symbol size: 8 bits +- Clock polarity/phase: Clock idle low/sampling on the first edge +- Bit order: MSB first +- SS handling: external (manual) +- Duplex: Full duplex +- Frequency: 1 MHz +- Synchronous mode (blocking) +- RX, TX buffers defined +- RX buffer length is equal to TX buffer length (5 symbols are transmitted in both directions) + +Other test cases differs from the `default config` always only by one setting (e.g. `symbol size: 16` test case has the same scenario, but 16 bit symbols are transmitted). + +Test Limitations +---------------- + +Synchronous mode: + +- Test uses two threads in to handle master-slave data transfer, because of that master is sending symbols one by one (when five symbols are to be sent, then spi_transfer() function is called five times and in each call one symbol is transferred). This will allow slave thread to read transmitted symbols. +- Half-Duplex mode cannot be tested. + +Asynchronous mode: + +**Note:** +In async mode cases when rx buffer size is different than tx buffer size and half-duplex mode are not supported. + +- Undefined RX/TX buffers(NULL) cannot be tested. +- High frequencies cannot be tested. + + +It is recommended to use Ice Tea version of the SPI communication test which do not have such limitations and is more reliable. + +Expected result +---------------- +The test exits without errors. diff --git a/TESTS/mbed_hal/spi_com/com_test.png b/TESTS/mbed_hal/spi_com/com_test.png new file mode 100644 index 0000000000000000000000000000000000000000..ba7da3ecd2d1acdae4c4510f875ba2439e6374f3 GIT binary patch literal 10460 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 + +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include "spi_com_test.h" + +#if DEVICE_SPI_SLAVE +#error [NOT_SUPPORTED] This test can only be run on device that support SPI Master AND Slave. +#endif +#if DEVICE_SPI_COUNT < 2 +#error [NOT_SUPPORTED] This test can only be run on device with at least two SPI peripherals. +#endif + +using namespace utest::v1; + +/* Enable debug mode to dump rx/tx buffers.*/ +#define DEBUG 0 + +/* This must be changed if SS active state is 1. */ +#define SS_ACTIVE (0) +#define SS_INACTIVE (!SS_ACTIVE) + +#define FREQ_200KHZ (200000) +#define FREQ_1MHZ (1000000) +#define FREQ_2MHZ (2000000) +#define FREQ_MIN (0) +#define FREQ_MAX (0xFFFFFFFF) + +#define TEST_SYM_CNT 5 + +#ifndef MIN +#define MIN(a, b) (((a)>(b))?(b):(a)) +#endif + +#ifndef MAX +#define MAX(a, b) ((a>b)?(a):(b)) +#endif + +typedef enum { + FULL_DUPLEX, HALF_DUPLEX +} duplex_t; + +/* Test context structure. */ +typedef struct { + const void *tx; + uint32_t tx_len; + void *rx; + uint32_t rx_len; + void *fill_symbol; + DigitalOut *ss; + uint8_t bits; + volatile uint32_t count; // test output + volatile bool has_error; +} test_context_t; + +/* SPI test configuration. */ +typedef struct { + uint8_t symbol_size; + spi_mode_t mode; + spi_bit_ordering_t bit_ordering; + uint32_t freq_hz; + uint32_t master_tx_cnt; + uint32_t master_rx_cnt; + uint32_t slave_tx_cnt; + uint32_t slave_rx_cnt; + bool master_tx_defined; + bool master_rx_defined; + bool slave_tx_defined; + bool slave_rx_defined; + bool auto_ss; + duplex_t duplex; + bool sync; +} config_test_case_t; + +/* Semaphore used to control master/slave SPI communication */ +Semaphore join(0, 2); +Timer t; + +static spi_t slave = {0}; +static spi_t master = {0}; + +static const uint8_t tx_master[] = "0123456789abcdefghijklmnopqrstuvwxyz=+/-*!?"; +static const uint8_t tx_slave[] = "zyxwvutsrqponmlkjihgfedcba9876543210=+/-*!?"; + +static uint8_t rx_slave[sizeof(tx_master) + 1] = {0}; +static uint8_t rx_master[sizeof(tx_slave) + 1] = {0}; +static uint8_t rx_pattern_slave[sizeof(tx_master) + 1] = {0}; +static uint8_t rx_pattern_master[sizeof(tx_slave) + 1] = {0}; + +/* Array witch test cases which represents different SPI configurations for testing. */ +static config_test_case_t test_cases[] = { + /* default config: 8 bit symbol\sync mode\full duplex\clock idle low\sample on the first clock edge\MSB first\200 KHz clock\manual SS handling */ + /* 00 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* symbol size testing */ + /* 01 */{1, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 02 */{7, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 03 */{9, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 04 */{15, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 05 */{16, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 06 */{17, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 07 */{31, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 08 */{32, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* mode testing */ + /* 09 */{8, SPI_MODE_IDLE_LOW_SAMPLE_SECOND_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 10 */{8, SPI_MODE_IDLE_HIGH_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 11 */{8, SPI_MODE_IDLE_HIGH_SAMPLE_SECOND_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* bit ordering testing */ + /* 12 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_LSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* freq testing */ + /* 13 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 14 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_2MHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 15 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_MIN, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* 16 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_MAX, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* master: TX > RX */ + /* 17 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT - 2, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* master: TX < RX */ + /* 18 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT - 2, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* slave: TX > RX */ + /* 19 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT - 2, true, true, true, true, false, FULL_DUPLEX }, + /* slave: TX < RX */ + /* 20 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT - 2, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* master tx buffer undefined */ + /* 21 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, false, true, true, true, false, FULL_DUPLEX }, + /* master rx buffer undefined */ + /* 22 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, false, true, true, false, FULL_DUPLEX }, + /* slave tx buffer undefined */ + /* 23 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, false, true, false, FULL_DUPLEX }, + /* slave rx buffer undefined */ + /* 24 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, false, false, FULL_DUPLEX }, + /* auto ss hadling by master */ + /* 25 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, TEST_SYM_CNT, true, true, true, true, false, FULL_DUPLEX }, + /* one symbol */ + /* 26 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, 1, 1, 1, 1, true, true, true, true, false, FULL_DUPLEX }, + /* long buffer */ + /* 27 */{8, SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE, SPI_BIT_ORDERING_MSB_FIRST, FREQ_200KHZ, 32, 32, 32, 32, true, true, true, true, false, FULL_DUPLEX }, +}; + +/* Function returns true if configuration is consistent with the capabilities of + * the SPI peripheral, false otherwise. */ +static bool check_capabilities(spi_capabilities_t *p_cabs, uint32_t symbol_size, bool slave, bool half_duplex) +{ + if (!(p_cabs->word_length & (1 << (symbol_size - 1))) || + (slave && !p_cabs->support_slave_mode)) { + return false; + } + return true; +} + +/* Function sets Slave Select signal. */ +static void toggle_ss(DigitalOut *pin, bool value) +{ + if (pin != NULL) { + *pin = value; + } +} + +/* Slave thread used for communication test. */ +static void fn_slave(void *vctx) +{ + test_context_t *ctx = (test_context_t *)vctx; + ctx->count = 0; + ctx->count = spi_transfer(&slave, ctx->tx, ctx->tx_len, ctx->rx, ctx->rx_len, ctx->fill_symbol); + join.release(); +} + +/* Master thread used for communication test. */ +static void fn_master(void *vctx) +{ + test_context_t *ctx = (test_context_t *)vctx; + uint32_t factor = 1; + if (ctx->bits > 16) { + factor = 4; + } else if (ctx->bits > 8) { + factor = 2; + } + + const uint8_t *tx = (const uint8_t *)ctx->tx; + uint8_t *rx = (uint8_t *)ctx->rx; + uint8_t *rx_ptr = NULL; + uint32_t rx_len = 0; + ctx->count = 0; + + toggle_ss(ctx->ss, SS_ACTIVE); + for (uint32_t i = 0; i < ctx->tx_len; i++) { + if (i < ctx->rx_len && rx) { + rx_ptr = &rx[i * factor]; + rx_len = 1; + } else { + rx_ptr = NULL; + rx_len = 0; + } + ctx->count += spi_transfer(&master, &tx[i * factor], 1, rx_ptr, rx_len, ctx->fill_symbol); + wait_ms(3); + } + if (ctx->tx_len < ctx->rx_len) { + for (uint32_t i = ctx->tx_len; i < ctx->rx_len; i++) { + ctx->count += spi_transfer(&master, NULL, 0, &rx[i * factor], 1, ctx->fill_symbol); + wait_ms(3); + } + } + toggle_ss(ctx->ss, SS_INACTIVE); + + join.release(); +} + +/* Slave interrupt handler for async transfer. */ +static void slave_handler(spi_t *obj, void *vctx, spi_async_event_t *event) +{ + test_context_t *ctx = (test_context_t *)vctx; + ctx->count = event->transfered; + ctx->has_error = event->error; + + if (ctx->has_error) { + printf("Slave error: %d \n", event->error); + printf("Slave transfered: %lu \n", event->transfered); + } + + join.release(); +} + +/* Master interrupt handler for async transfer. */ +static void master_handler(spi_t *obj, void *vctx, spi_async_event_t *event) +{ + test_context_t *ctx = (test_context_t *)vctx; + ctx->count = event->transfered; + ctx->has_error = event->error; + + if (ctx->has_error) { + printf("Master error: %d \n", event->error); + printf("Master transfered: %lu \n", event->transfered); + } + + join.release(); +} + +/* Function compares transmission buffers and returns true on success, false otherwise. */ +template bool check_buffer(const T *a, const T *b, T fill, uint32_t a_len, uint32_t b_len) +{ + static bool res = memcmp(a, b, a_len * sizeof(T)) == 0; + for (uint32_t i = a_len; (i < b_len) && res; i++) { + res &= b[i] == fill; + } + return res; +} + +/* Function which perform SPI transfer test using specified config. */ +template +void test_spi_transfer() +{ + DigitalOut *mcs_pin = NULL; + PinName mcs = SPI_TEST_MASTER_PIN(CS); + PinName mmclk = SPI_TEST_MASTER_PIN(SCK); + PinName mmiso = SPI_TEST_MASTER_PIN(MISO); + PinName mmosi = SPI_TEST_MASTER_PIN(MOSI); + PinName scs = SPI_TEST_SLAVE_PIN(CS); + PinName smclk = SPI_TEST_SLAVE_PIN(SCK); + PinName smiso = SPI_TEST_SLAVE_PIN(MISO); + PinName smosi = SPI_TEST_SLAVE_PIN(MOSI); + uint32_t freq_hz = test_cases[tc_id].freq_hz; + T symbol_mask = (T)((1 << test_cases[tc_id].symbol_size) - 1); + + uint32_t master_symbols_clocked = MAX(test_cases[tc_id].master_tx_cnt, test_cases[tc_id].master_rx_cnt); + uint32_t slave_symbols_clocked = MAX(test_cases[tc_id].slave_tx_cnt, test_cases[tc_id].slave_rx_cnt); + + spi_capabilities_t master_capab = { 0 }; + spi_capabilities_t slave_capab = { 0 }; + + Thread *tmaster; + Thread *tslave; + test_context_t master_ctx = { 0 }; + test_context_t slave_ctx = { 0 }; + + T *p_tx_master = (T *)tx_master; + T *p_rx_master = (T *)rx_master; + T *p_tx_slave = (T *)tx_slave; + T *p_rx_slave = (T *)rx_slave; + T *p_rx_pattern_slave = (T *)rx_pattern_slave; + T *p_rx_pattern_master = (T *)rx_pattern_master; + T master_fill = (T)0x58585858; // X + T slave_fill = (T)0x59595959; // Y + + memset(rx_slave, 0, sizeof(rx_slave)); + memset(rx_master, 0, sizeof(rx_master)); + + memcpy(rx_pattern_slave, tx_master, sizeof(tx_master)); + memcpy(rx_pattern_master, tx_slave, sizeof(tx_slave)); + + for (uint32_t i = 0; i < test_cases[tc_id].slave_rx_cnt; i++) { + p_rx_pattern_slave[i] &= symbol_mask; + } + + for (uint32_t i = 0; i < test_cases[tc_id].master_rx_cnt; i++) { + p_rx_pattern_master[i] &= symbol_mask; + } + + if (!test_cases[tc_id].master_tx_defined) { + p_tx_master = NULL; + } + if (!test_cases[tc_id].master_rx_defined) { + p_rx_master = NULL; + } + + spi_get_capabilities( + spi_get_module(mmosi, mmiso, mmclk), + NC, + &master_capab + ); + spi_get_capabilities( + spi_get_module(smosi, smiso, smclk), + NC, + &slave_capab + ); + if (!check_capabilities(&master_capab, test_cases[tc_id].symbol_size, false, test_cases[tc_id].duplex) || + !check_capabilities(&slave_capab, test_cases[tc_id].symbol_size, false, test_cases[tc_id].duplex)) { + TEST_SKIP_MESSAGE("Configuration not supported. Skipping. \n"); + } + + /* Adapt min/max frequency for testing based of capabilities. */ + switch (freq_hz) { + case FREQ_MIN: + freq_hz = master_capab.minimum_frequency; + break; + case FREQ_MAX: + freq_hz = master_capab.maximum_frequency; + break; + default: + break; + } + + /* Adapt manual/auto SS handling by master. */ + if (!test_cases[tc_id].auto_ss) { + mcs_pin = new DigitalOut(mcs); + mcs = NC; + *mcs_pin = SS_INACTIVE; + } + + spi_init(&slave, true, smosi, smiso, smclk, scs); + spi_init(&master, false, mmosi, mmiso, mmclk, mcs); + + spi_format(&slave, test_cases[tc_id].symbol_size, test_cases[tc_id].mode, test_cases[tc_id].bit_ordering); + spi_format(&master, test_cases[tc_id].symbol_size, test_cases[tc_id].mode, test_cases[tc_id].bit_ordering); + + spi_frequency(&master, freq_hz); + + t.reset(); + t.start(); + + slave_ctx.tx = p_tx_slave; + slave_ctx.tx_len = test_cases[tc_id].slave_tx_cnt; + slave_ctx.rx = p_rx_slave; + slave_ctx.rx_len = test_cases[tc_id].slave_rx_cnt; + slave_ctx.fill_symbol = &slave_fill; + slave_ctx.ss = NULL; + slave_ctx.bits = test_cases[tc_id].symbol_size; + + master_ctx.tx = p_tx_master; + master_ctx.tx_len = test_cases[tc_id].master_tx_cnt; + master_ctx.rx = p_rx_master; + master_ctx.rx_len = test_cases[tc_id].master_rx_cnt; + master_ctx.fill_symbol = &master_fill; + master_ctx.ss = mcs_pin; + master_ctx.bits = test_cases[tc_id].symbol_size; + + /* In sync mode use two threads to handle SPI transmission. */ + if (sync) { + tmaster = new Thread(); + MBED_ASSERT(tmaster != NULL); + + tslave = new Thread(); + MBED_ASSERT(tslave != NULL); + + tslave->start(callback(fn_slave, &slave_ctx)); + tmaster->start(callback(fn_master, &master_ctx)); + } else { + spi_transfer_async(&slave, + p_tx_slave, slave_ctx.tx_len, + p_rx_slave, slave_ctx.rx_len, + &slave_fill, slave_handler, &slave_ctx, DMA_USAGE_OPPORTUNISTIC); + + toggle_ss(mcs_pin, SS_ACTIVE); + spi_transfer_async(&master, + p_tx_master, master_ctx.tx_len, + p_rx_master, master_ctx.rx_len, + &master_fill, master_handler, &master_ctx, DMA_USAGE_OPPORTUNISTIC); + } + uint32_t i = 0; + uint64_t cnt = 0; + + /* Try to perform test within 2 sec timeout. */ + while ((i < 2) && (t.read_ms() < 2000)) { + if (join.wait(0) != 0) { + i += 1; + } + cnt += 1; + } + + if (sync) { + tmaster->terminate(); + delete tmaster; + tslave->terminate(); + delete tslave; + } + + t.stop(); + toggle_ss(mcs_pin, SS_INACTIVE); + spi_free(&master); + spi_free(&slave); + +#if DEBUG + printf("Test context:\n"); + printf("Master: tx_sym_cnt: %lu tx:%.*s rx_sym_cnt: %lu\n", master_ctx.tx_len, (int)master_ctx.tx_len * sizeof(T), (char *)master_ctx.tx, master_ctx.rx_len); + printf("Slave: tx_sym_cnt: %lu tx:%.*s rx_sym_cnt: %lu\n", slave_ctx.tx_len, (int)slave_ctx.tx_len * sizeof(T), (char *)slave_ctx.tx, slave_ctx.rx_len); + printf("Ran in %d ms (cnt = %llu) : %f\n", t.read_ms(), cnt, (float)cnt / (float)t.read_ms()); + printf("Slave sent : %.*s\n", (int)slave_ctx.tx_len * sizeof(T), (char *)tx_slave); + printf("Master recved: %.*s\n", (int)master_ctx.rx_len * sizeof(T), (char *)rx_master); + printf("Master sent : %.*s\n", (int)master_ctx.tx_len * sizeof(T), (char *)tx_master); + printf("Slave recved: %.*s\n", (int)slave_ctx.rx_len * sizeof(T), (char *)rx_slave); +#endif + + TEST_ASSERT(!master_ctx.has_error); + TEST_ASSERT(!slave_ctx.has_error); + TEST_ASSERT_EQUAL(master_symbols_clocked, master_ctx.count); + TEST_ASSERT_EQUAL(slave_symbols_clocked, slave_ctx.count); + + if ((p_tx_slave != NULL) && (p_rx_master != NULL)) { + uint32_t n = MIN(slave_ctx.tx_len, master_ctx.rx_len); + TEST_ASSERT_EQUAL(1, check_buffer((T *)rx_pattern_master, p_rx_master, slave_fill, n, master_ctx.rx_len)); + } + if ((p_tx_master != NULL) && (p_rx_slave != NULL)) { + uint32_t n = MIN(slave_ctx.rx_len, master_ctx.tx_len); + TEST_ASSERT_EQUAL(1, check_buffer((T *)rx_pattern_slave, p_rx_slave, master_fill, n, slave_ctx.rx_len)); + } + if (mcs_pin != NULL) { + delete mcs_pin; + } +} + +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(40, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("SPI master-slave sync com - default config", test_spi_transfer), + Case("SPI master-slave sync com - symbol size: 1", test_spi_transfer), + Case("SPI master-slave sync com - symbol size: 7", test_spi_transfer), + Case("SPI master-slave sync com - symbol size: 9", test_spi_transfer), + Case("SPI master-slave sync com - symbol size: 15", test_spi_transfer), + Case("SPI master-slave sync com - symbol size: 16", test_spi_transfer), + Case("SPI master-slave sync com - symbol size: 17", test_spi_transfer), + Case("SPI master-slave sync com - symbol size: 31", test_spi_transfer), + Case("SPI master-slave sync com - symbol size: 32", test_spi_transfer), + Case("SPI master-slave sync com - mode: idle low, sample second edge", test_spi_transfer), + Case("SPI master-slave sync com - mode: idle high, sample first edge", test_spi_transfer), + Case("SPI master-slave sync com - mode: idle high, sample second edge", test_spi_transfer), + Case("SPI master-slave sync com - bit ordering: LSB first", test_spi_transfer), + Case("SPI master-slave sync com - freq testing: 200 KHz", test_spi_transfer), + Case("SPI master-slave sync com - freq testing: 2 MHz", test_spi_transfer), + Case("SPI master-slave sync com - freq testing: min defined", test_spi_transfer), + Case("SPI master-slave sync com - freq testing: max defined", test_spi_transfer), + Case("SPI master-slave sync com - master: TX > RX", test_spi_transfer), + Case("SPI master-slave sync com - master: TX < RX", test_spi_transfer), + Case("SPI master-slave sync com - slave: TX > RX", test_spi_transfer), + Case("SPI master-slave sync com - slave: TX < RX", test_spi_transfer), + Case("SPI master-slave sync com - master: TX undefined", test_spi_transfer), + Case("SPI master-slave sync com - master: RX undefined", test_spi_transfer), + Case("SPI master-slave sync com - slave: TX undefined", test_spi_transfer), + Case("SPI master-slave sync com - slave: RX undefined", test_spi_transfer), + Case("SPI master-slave sync com - master: manual ss", test_spi_transfer), + Case("SPI master-slave sync com - one symbol", test_spi_transfer), + Case("SPI master-slave sync com - long buffer", test_spi_transfer), +#ifdef DEVICE_SPI_ASYNCH + Case("SPI master-slave async com - default config", test_spi_transfer), + Case("SPI master-slave async com - symbol size: 1", test_spi_transfer), + Case("SPI master-slave async com - symbol size: 7", test_spi_transfer), + Case("SPI master-slave async com - symbol size: 9", test_spi_transfer), + Case("SPI master-slave async com - symbol size: 15", test_spi_transfer), + Case("SPI master-slave async com - symbol size: 16", test_spi_transfer), + Case("SPI master-slave async com - symbol size: 17", test_spi_transfer), + Case("SPI master-slave async com - symbol size: 31", test_spi_transfer), + Case("SPI master-slave async com - symbol size: 32", test_spi_transfer), + Case("SPI master-slave async com - mode: idle low, sample second edge", test_spi_transfer), + Case("SPI master-slave async com - mode: idle high, sample first edge", test_spi_transfer), + Case("SPI master-slave async com - mode: idle high, sample second edge", test_spi_transfer), + Case("SPI master-slave async com - bit ordering: LSB first", test_spi_transfer), + Case("SPI master-slave async com - freq testing: 200 KHz", test_spi_transfer), + Case("SPI master-slave async com - freq testing: 2 MHz", test_spi_transfer), + Case("SPI master-slave async com - master: manual ss", test_spi_transfer), + Case("SPI master-slave async com - one symbol", test_spi_transfer), + Case("SPI master-slave async com - long buffer", test_spi_transfer), +#endif +}; + +Specification specification(test_setup, cases); + +int main() +{ + return !Harness::run(specification); +} diff --git a/TESTS/mbed_hal/spi_com/spi_com_test.h b/TESTS/mbed_hal/spi_com/spi_com_test.h new file mode 100644 index 00000000000..a30587d4c8b --- /dev/null +++ b/TESTS/mbed_hal/spi_com/spi_com_test.h @@ -0,0 +1,49 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** \addtogroup hal_spi_tests + * @{ + */ + +#ifndef MBED_SPI_COM_TEST_H +#define MBED_SPI_COM_TEST_H + +#if DEVICE_SPI + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test that the SPI transfer can be performed in various configurations. + * + * Given board provides at least 2 SPI peripherals, SPI slave and master mode. + * When SPI transmission is performed using specified configuration. + * Then data is successfully transfered. + * + */ +void test_spi_transfer(); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/TESTS/mbed_hal/spi_com/spi_ob_wire_connection.png b/TESTS/mbed_hal/spi_com/spi_ob_wire_connection.png new file mode 100644 index 0000000000000000000000000000000000000000..dc1a54c9c458908ec2fa60642c5fd7243e630c4c GIT binary patch literal 6255 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 RBf^gaKuKN|U4b$W{VzI?c;Wy6 literal 0 HcmV?d00001 From fc217ed3be12b8860f76a69fae38081c6b6c25a9 Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Fri, 5 Apr 2019 10:21:22 +0200 Subject: [PATCH 2/5] ARM_CM3DS_MPS2: Disable ANALOGIN support ANALOGIN is related to SPI. If SPI is not supported, then ANALOGIN also. This change should fix: ARM_CM3DS_MPS2::ARMC6::TESTS-MBED_HAL-PINMAP [Error] @0,0: L6218E: Undefined symbol analogin_pinmap (referred from BUILD/tests/ARM_CM3DS_MPS2/ARMC6/TESTS/mbed_hal/pinmap/TESTS/mbed_hal/pinmap/main.o). --- targets/targets.json | 1 - 1 file changed, 1 deletion(-) diff --git a/targets/targets.json b/targets/targets.json index 4e2f559f5b6..422ff825200 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -5213,7 +5213,6 @@ "OUTPUT_EXT": "elf", "macros": ["CMSDK_CM3DS"], "device_has": [ - "ANALOGIN", "EMAC", "FLASH", "I2C", From 505a2937f999812e1ac3a96baef9f526bcbf0151 Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Fri, 5 Apr 2019 10:32:55 +0200 Subject: [PATCH 3/5] FVP_MPS2 family: Disable SERIAL_FC Looks like `FVP_MPS2 family` has SERIAL_FC feature enabled, but does not provide pins definition for `PinMap_UART_CTS`, `PinMap_UART_RTS`. This should fix the following failures: ARMC6::FVP_MPS2_M0 ARMC6::FVP_MPS2_M0P ARMC6::FVP_MPS2_M3 ARMC6::FVP_MPS2_M4 ARMC6::FVP_MPS2_M7 [Error] serial_api.c@403,12: use of undeclared identifier 'PinMap_UART_CTS'; did you mean 'PinMap_UART_TX'? --- targets/targets.json | 1 - 1 file changed, 1 deletion(-) diff --git a/targets/targets.json b/targets/targets.json index 422ff825200..bae384bc6e3 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -7659,7 +7659,6 @@ "PORTINOUT", "PORTOUT", "SERIAL", - "SERIAL_FC", "TSC", "USTICKER" ], From d14c50ac539c0127dac0fd1f891d764cc882a069 Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Fri, 5 Apr 2019 10:38:25 +0200 Subject: [PATCH 4/5] Disable mbed-os-example-attestation, mbed-os-example-blockdevice examples. Not supported on the spi feature branch. --- tools/test/examples/examples.json | 32 ------------------------------- 1 file changed, 32 deletions(-) diff --git a/tools/test/examples/examples.json b/tools/test/examples/examples.json index 8cb7be626bb..571bc97938c 100644 --- a/tools/test/examples/examples.json +++ b/tools/test/examples/examples.json @@ -314,19 +314,6 @@ "export": false, "auto-update" : true }, - { - "name": "mbed-os-example-blockdevice", - "github":"https://github.com/armmbed/mbed-os-example-blockdevice", - "mbed": [], - "test-repo-source": "github", - "features" : [], - "targets" : ["K64F"], - "toolchains" : [], - "exporters": [], - "compile" : true, - "export": true, - "auto-update" : true - }, { "name": "mbed-os-example-kvstore", "github":"https://github.com/ARMmbed/mbed-os-example-kvstore", @@ -352,25 +339,6 @@ "compile" : true, "export": true, "auto-update" : true - }, - { - "name": "mbed-os-example-attestation", - "github": "https://github.com/ARMmbed/mbed-os-example-attestation", - "mbed": [], - "test-repo-source": "github", - "features" : [], - "targets" : ["CY8CKIT_062_WIFI_BT_PSA", - "K64F", - "K66F", - "NUCLEO_F429ZI", - "UBLOX_ODIN_EVK_W2", - "LPC55S69_NS" - ], - "toolchains" : [], - "exporters": [], - "compile" : true, - "export": true, - "auto-update" : true } ] } From 16762433e3b2c0fa30e9c2cf78676a1685ce8f7f Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Fri, 12 Apr 2019 12:50:00 +0200 Subject: [PATCH 5/5] K64F: Adapt spi driver to the new HAL API, enable SPI --- .../TARGET_FRDM/PeripheralNames.h | 6 + .../TARGET_FRDM/PeripheralPins.c | 4 +- .../TARGET_MCU_K64F/TARGET_FRDM/PinNames.h | 22 +- .../TARGET_MCU_K64F/spi_api.c | 841 ++++++++++-------- targets/targets.json | 16 +- 5 files changed, 530 insertions(+), 359 deletions(-) diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PeripheralNames.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PeripheralNames.h index 66aee9d7b14..0c2861a75a4 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PeripheralNames.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PeripheralNames.h @@ -130,6 +130,12 @@ typedef enum { SPI_2 = 2, } SPIName; +/* Specify master/slave interfaces for testing purposes. */ +#define SPI_TEST_MASTER SPI_2 +#define SPI_TEST_SLAVE SPI_0 +#define SPI_TEST_MASTER_PIN(SPI_PIN) SPI_2##_##SPI_PIN +#define SPI_TEST_SLAVE_PIN(SPI_PIN) SPI_0##_##SPI_PIN + #ifdef __cplusplus } #endif diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PeripheralPins.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PeripheralPins.c index c2bb8f627e2..6ae3c53e4a2 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PeripheralPins.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PeripheralPins.c @@ -158,7 +158,7 @@ const PinMap PinMap_SPI_SCLK[] = { {NC , NC , 0} }; -const PinMap PinMap_SPI_MOSI[] = { +const PinMap PinMap_SPI_SOUT[] = { {PTD2 , SPI_0, 2}, {PTE1 , SPI_1, 2}, {PTE3 , SPI_1, 7}, @@ -170,7 +170,7 @@ const PinMap PinMap_SPI_MOSI[] = { {NC , NC , 0} }; -const PinMap PinMap_SPI_MISO[] = { +const PinMap PinMap_SPI_SIN[] = { {PTD3 , SPI_0, 2}, {PTE1 , SPI_1, 7}, {PTE3 , SPI_1, 2}, diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PinNames.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PinNames.h index a2a388eb10e..b0708825912 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PinNames.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/PinNames.h @@ -229,7 +229,7 @@ typedef enum { D13 = PTD1, D14 = PTE25, D15 = PTE24, - + I2C_SCL = D15, I2C_SDA = D14, @@ -243,6 +243,26 @@ typedef enum { DAC0_OUT = 0xFEFE, /* DAC does not have Pin Name in RM */ //SPI Pins configuration + /* Note: + This board does not provide SPI MOSI/MISO pins, instead we have SIN/SOUT pins which can be used + as SPI MOSI/MISO lines depending on SPI operation mode(master or slave): + master: SIN ---> MISO + SOUT ---> MOSI + slave: SIN ---> MOSI + SOUT ---> MISO + + SPI_0 interface represents SPI pins configuration for slave and SPI_2 respresents spi configuration + for master. + */ + SPI_0_MOSI = PTD3, + SPI_0_MISO = PTD2, + SPI_0_SCK = PTD1, + SPI_0_CS = PTD0, + SPI_2_MOSI = PTB22, + SPI_2_MISO = PTB23, + SPI_2_SCK = PTB21, + SPI_2_CS = PTB20, + SPI_MOSI = PTE3, SPI_MISO = PTE1, SPI_SCK = PTE2, diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/spi_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/spi_api.c index d7d9c9f6ac5..63012a902a5 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/spi_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/spi_api.c @@ -25,458 +25,593 @@ #include "mbed_error.h" #include "fsl_dspi.h" #include "peripheral_clock_defines.h" -#include "dma_reqs.h" #include "PeripheralPins.h" +#include "device.h" /* Array of SPI peripheral base address. */ static SPI_Type *const spi_address[] = SPI_BASE_PTRS; /* Array of SPI bus clock frequencies */ static clock_name_t const spi_clocks[] = SPI_CLOCK_FREQS; -SPIName spi_get_peripheral_name(PinName mosi, PinName miso, PinName sclk) +void wait_cycles(volatile int cycles) { - SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI); - SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO); - SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK); + while(cycles--); +} + +status_t DSPI_TransferBlockingLimit(SPI_Type *base, dspi_transfer_t *transfer, uint32_t tx_limit, uint32_t rx_limit, uint32_t dummy) +{ + assert(transfer); - SPIName spi_per; + uint16_t wordToSend = 0; + uint16_t wordReceived = 0; + uint8_t dummyData = (uint8_t)dummy; + uint8_t bitsPerFrame; - // If 3 wire SPI is used, the miso is not connected. - if (miso == NC) { - spi_per = (SPIName)pinmap_merge(spi_mosi, spi_sclk); - } else { - SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso); - spi_per = (SPIName)pinmap_merge(spi_data, spi_sclk); + uint32_t command; + uint32_t lastCommand; + + uint8_t *txData; + uint8_t *rxData; + uint32_t remainingSendByteCount; + uint32_t remainingReceiveByteCount; + + uint32_t fifoSize; + dspi_command_data_config_t commandStruct; + + /* If the transfer count is zero, then return immediately.*/ + if (transfer->dataSize == 0) + { + return kStatus_InvalidArgument; + } + + DSPI_StopTransfer(base); + DSPI_DisableInterrupts(base, kDSPI_AllInterruptEnable); + DSPI_FlushFifo(base, true, true); + DSPI_ClearStatusFlags(base, kDSPI_AllStatusFlag); + + /*Calculate the command and lastCommand*/ + commandStruct.whichPcs = + (dspi_which_pcs_t)(1U << ((transfer->configFlags & DSPI_MASTER_PCS_MASK) >> DSPI_MASTER_PCS_SHIFT)); + commandStruct.isEndOfQueue = false; + commandStruct.clearTransferCount = false; + commandStruct.whichCtar = + (dspi_ctar_selection_t)((transfer->configFlags & DSPI_MASTER_CTAR_MASK) >> DSPI_MASTER_CTAR_SHIFT); + commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterPcsContinuous); + + command = DSPI_MasterGetFormattedCommand(&(commandStruct)); + + commandStruct.isEndOfQueue = true; + commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterActiveAfterTransfer); + lastCommand = DSPI_MasterGetFormattedCommand(&(commandStruct)); + + /*Calculate the bitsPerFrame*/ + bitsPerFrame = ((base->CTAR[commandStruct.whichCtar] & SPI_CTAR_FMSZ_MASK) >> SPI_CTAR_FMSZ_SHIFT) + 1; + + txData = transfer->txData; + rxData = transfer->rxData; + remainingSendByteCount = transfer->dataSize; + remainingReceiveByteCount = transfer->dataSize; + + if ((base->MCR & SPI_MCR_DIS_RXF_MASK) || (base->MCR & SPI_MCR_DIS_TXF_MASK)) + { + fifoSize = 1; + } + else + { + fifoSize = FSL_FEATURE_DSPI_FIFO_SIZEn(base); + } + + DSPI_StartTransfer(base); + + if (bitsPerFrame <= 8) + { + while (remainingSendByteCount > 0) + { + if (remainingSendByteCount == 1) + { + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + + if (txData != NULL && tx_limit) + { + base->PUSHR = (*txData) | (lastCommand); + txData++; + tx_limit--; + } + else + { + base->PUSHR = (lastCommand) | (dummyData); + } + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + remainingSendByteCount--; + + while (remainingReceiveByteCount > 0) + { + if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + if (rxData != NULL && rx_limit) + { + /* Read data from POPR*/ + if (remainingReceiveByteCount == 1) wait_cycles(100); // workaround for last sym issue on slave + *(rxData) = DSPI_ReadData(base); + rxData++; + rx_limit--; + } + else + { + DSPI_ReadData(base); + } + remainingReceiveByteCount--; + + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + } + } + } + else + { + /*Wait until Tx Fifo is not full*/ + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + if (txData != NULL && tx_limit) + { + base->PUSHR = command | (uint16_t)(*txData); + txData++; + tx_limit--; + } + else + { + base->PUSHR = command | dummyData; + } + remainingSendByteCount--; + + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + + while ((remainingReceiveByteCount - remainingSendByteCount) >= fifoSize) + { + if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + if (rxData != NULL && rx_limit) + { + *(rxData) = DSPI_ReadData(base); + rxData++; + rx_limit--; + } + else + { + DSPI_ReadData(base); + } + remainingReceiveByteCount--; + + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + } + } + } + } + } + else + { + while (remainingSendByteCount > 0) + { + if (remainingSendByteCount <= 2) + { + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + + if (txData != NULL && tx_limit) + { + wordToSend = *(txData); + ++txData; + + if (remainingSendByteCount > 1) + { + wordToSend |= (unsigned)(*(txData)) << 8U; + ++txData; + tx_limit--; + } + } + else + { + wordToSend = dummyData; + } + + base->PUSHR = lastCommand | wordToSend; + + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + remainingSendByteCount = 0; + + while (remainingReceiveByteCount > 0) + { + if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + if (remainingReceiveByteCount == 2) wait_cycles(100); // workaround for last sym issue on slave + wordReceived = DSPI_ReadData(base); + + if (remainingReceiveByteCount != 1) + { + if (rxData != NULL && rx_limit) + { + *(rxData) = wordReceived; + ++rxData; + *(rxData) = wordReceived >> 8; + ++rxData; + rx_limit--; + } + remainingReceiveByteCount -= 2; + } + else + { + if (rxData != NULL && rx_limit) + { + *(rxData) = wordReceived; + ++rxData; + rx_limit--; + } + remainingReceiveByteCount--; + } + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + } + } + } + else + { + /*Wait until Tx Fifo is not full*/ + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + + if (txData != NULL && tx_limit) + { + wordToSend = *(txData); + ++txData; + wordToSend |= (unsigned)(*(txData)) << 8U; + ++txData; + tx_limit--; + } + else + { + wordToSend = dummyData; + } + base->PUSHR = command | wordToSend; + remainingSendByteCount -= 2; + + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + + while (((remainingReceiveByteCount - remainingSendByteCount) / 2) >= fifoSize) + { + if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + wordReceived = DSPI_ReadData(base); + + if (rxData != NULL && rx_limit) + { + *rxData = wordReceived; + ++rxData; + *rxData = wordReceived >> 8; + ++rxData; + rx_limit--; + } + remainingReceiveByteCount -= 2; + + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + } + } + } + } } - return spi_per; + return kStatus_Success; } -void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) +void spi_get_capabilities(SPIName name, PinName ssel, spi_capabilities_t *cap) +{ + cap->word_length = 0x00008080; + cap->support_slave_mode = true; + cap->half_duplex = true; + + cap->minimum_frequency = 200000; + cap->maximum_frequency = 4000000; +} + +SPIName spi_get_module(PinName mosi, PinName miso, PinName sclk) { + int32_t spi_mosi = pinmap_find_peripheral(mosi, PinMap_SPI_SOUT); + int32_t spi_miso = pinmap_find_peripheral(miso, PinMap_SPI_SIN); + if ((spi_mosi == NC) && (spi_miso == NC)) { + // we're probably in slave mode. + spi_mosi = pinmap_peripheral(mosi, PinMap_SPI_SIN); + spi_miso = pinmap_peripheral(miso, PinMap_SPI_SOUT); + } + int32_t spi_sclk = pinmap_peripheral(sclk, PinMap_SPI_SCLK); + int32_t spi_data = pinmap_merge(spi_mosi, spi_miso); + return pinmap_merge(spi_data, spi_sclk); +} + +void spi_init(spi_t *obj, bool is_slave, PinName mosi, PinName miso, PinName sclk, PinName ssel) { // determine the SPI to use - uint32_t spi_mosi = pinmap_peripheral(mosi, PinMap_SPI_MOSI); - uint32_t spi_miso = pinmap_peripheral(miso, PinMap_SPI_MISO); - uint32_t spi_sclk = pinmap_peripheral(sclk, PinMap_SPI_SCLK); - uint32_t spi_ssel = pinmap_peripheral(ssel, PinMap_SPI_SSEL); - uint32_t spi_data = pinmap_merge(spi_mosi, spi_miso); - uint32_t spi_cntl = pinmap_merge(spi_sclk, spi_ssel); + int32_t spi_module = (uint32_t)spi_get_module(mosi, miso, sclk); + int32_t spi_ssel = pinmap_peripheral(ssel, PinMap_SPI_SSEL); + MBED_ASSERT(spi_module != NC); - obj->spi.instance = pinmap_merge(spi_data, spi_cntl); - MBED_ASSERT((int)obj->spi.instance != NC); + obj->instance = pinmap_merge(spi_module, spi_ssel); + MBED_ASSERT((int)obj->instance != NC); // pin out the spi pins - pinmap_pinout(mosi, PinMap_SPI_MOSI); - pinmap_pinout(miso, PinMap_SPI_MISO); + if (!is_slave) { + pinmap_pinout(mosi, PinMap_SPI_SOUT); + } else { + pinmap_pinout(mosi, PinMap_SPI_SIN); + } + if (!is_slave) { + pinmap_pinout(miso, PinMap_SPI_SIN); + } else { + pinmap_pinout(miso, PinMap_SPI_SOUT); + } pinmap_pinout(sclk, PinMap_SPI_SCLK); if (ssel != NC) { pinmap_pinout(ssel, PinMap_SPI_SSEL); } - - /* Set the transfer status to idle */ - obj->spi.status = kDSPI_Idle; - - obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_OPPORTUNISTIC; + obj->is_slave = is_slave; + obj->initialised = false; } void spi_free(spi_t *obj) { - DSPI_Deinit(spi_address[obj->spi.instance]); + if (obj->initialised) { + DSPI_Deinit(spi_address[obj->instance]); + obj->initialised = false; + } } -void spi_format(spi_t *obj, int bits, int mode, int slave) +void spi_format(spi_t *obj, uint8_t bits, spi_mode_t mode, spi_bit_ordering_t bit_ordering) { + dspi_master_config_t master_config; dspi_slave_config_t slave_config; + dspi_clock_polarity_t cpol; + dspi_clock_phase_t cpha; + + if ((mode == SPI_MODE_IDLE_HIGH_SAMPLE_FIRST_EDGE) || + (mode == SPI_MODE_IDLE_HIGH_SAMPLE_SECOND_EDGE)) { + cpol = kDSPI_ClockPolarityActiveLow; + } else { + cpol = kDSPI_ClockPolarityActiveHigh; + } + if ((mode == SPI_MODE_IDLE_HIGH_SAMPLE_FIRST_EDGE) || + (mode == SPI_MODE_IDLE_LOW_SAMPLE_FIRST_EDGE)) { + cpha = kDSPI_ClockPhaseFirstEdge; + } else { + cpha = kDSPI_ClockPhaseSecondEdge; + } /* Bits: values between 4 and 16 are valid */ MBED_ASSERT(bits >= 4 && bits <= 16); - obj->spi.bits = bits; + obj->bits = bits; + obj->order = bit_ordering; - if (slave) { + if (obj->is_slave) { /* Slave config */ DSPI_SlaveGetDefaultConfig(&slave_config); slave_config.whichCtar = kDSPI_Ctar0; - slave_config.ctarConfig.bitsPerFrame = (uint32_t)bits;; - slave_config.ctarConfig.cpol = (mode & 0x2) ? kDSPI_ClockPolarityActiveLow : kDSPI_ClockPolarityActiveHigh; - slave_config.ctarConfig.cpha = (mode & 0x1) ? kDSPI_ClockPhaseSecondEdge : kDSPI_ClockPhaseFirstEdge; + slave_config.ctarConfig.bitsPerFrame = (uint32_t)bits; + slave_config.ctarConfig.cpol = cpol; + slave_config.ctarConfig.cpha = cpha; - DSPI_SlaveInit(spi_address[obj->spi.instance], &slave_config); + DSPI_SlaveInit(spi_address[obj->instance], &slave_config); } else { /* Master config */ DSPI_MasterGetDefaultConfig(&master_config); - master_config.ctarConfig.bitsPerFrame = (uint32_t)bits;; - master_config.ctarConfig.cpol = (mode & 0x2) ? kDSPI_ClockPolarityActiveLow : kDSPI_ClockPolarityActiveHigh; - master_config.ctarConfig.cpha = (mode & 0x1) ? kDSPI_ClockPhaseSecondEdge : kDSPI_ClockPhaseFirstEdge; - master_config.ctarConfig.direction = kDSPI_MsbFirst; + master_config.ctarConfig.bitsPerFrame = (uint32_t)bits; + master_config.ctarConfig.cpol = cpol; + master_config.ctarConfig.cpha = cpha; + master_config.ctarConfig.direction = (bit_ordering == SPI_BIT_ORDERING_MSB_FIRST)? kDSPI_MsbFirst : kDSPI_LsbFirst; master_config.ctarConfig.pcsToSckDelayInNanoSec = 0; - DSPI_MasterInit(spi_address[obj->spi.instance], &master_config, CLOCK_GetFreq(spi_clocks[obj->spi.instance])); + DSPI_MasterInit(spi_address[obj->instance], &master_config, CLOCK_GetFreq(spi_clocks[obj->instance])); } -} -void spi_frequency(spi_t *obj, int hz) -{ - uint32_t busClock = CLOCK_GetFreq(spi_clocks[obj->spi.instance]); - DSPI_MasterSetBaudRate(spi_address[obj->spi.instance], kDSPI_Ctar0, (uint32_t)hz, busClock); - //Half clock period delay after SPI transfer - DSPI_MasterSetDelayTimes(spi_address[obj->spi.instance], kDSPI_Ctar0, kDSPI_LastSckToPcs, busClock, 500000000 / hz); + obj->initialised = true; } -static inline int spi_readable(spi_t *obj) +uint32_t spi_frequency(spi_t *obj, uint32_t hz) { - return (DSPI_GetStatusFlags(spi_address[obj->spi.instance]) & kDSPI_RxFifoDrainRequestFlag); + uint32_t busClock = CLOCK_GetFreq(spi_clocks[obj->instance]); + uint32_t actual_br = DSPI_MasterSetBaudRate(spi_address[obj->instance], kDSPI_Ctar0, (uint32_t)hz, busClock); + //Half clock period delay after SPI transfer + DSPI_MasterSetDelayTimes(spi_address[obj->instance], kDSPI_Ctar0, kDSPI_LastSckToPcs, busClock, 2 * (1000000000 / hz)); + DSPI_MasterSetDelayTimes(spi_address[obj->instance], kDSPI_Ctar0, kDSPI_PcsToSck, busClock, 2 * (1000000000 / hz)); + DSPI_MasterSetDelayTimes(spi_address[obj->instance], kDSPI_Ctar0, kDSPI_BetweenTransfer, busClock, 0); + return actual_br; } -int spi_master_write(spi_t *obj, int value) +static int spi_write(spi_t *obj, uint32_t value) { - dspi_command_data_config_t command; uint32_t rx_data; - DSPI_GetDefaultDataCommandConfig(&command); - command.isEndOfQueue = true; - - DSPI_MasterWriteDataBlocking(spi_address[obj->spi.instance], &command, (uint16_t)value); + if (obj->is_slave) { + DSPI_SlaveWriteDataBlocking(spi_address[obj->instance], value); + } else { + dspi_command_data_config_t command; + DSPI_GetDefaultDataCommandConfig(&command); + command.isEndOfQueue = true; - DSPI_ClearStatusFlags(spi_address[obj->spi.instance], kDSPI_TxFifoFillRequestFlag); + DSPI_MasterWriteDataBlocking(spi_address[obj->instance], &command, (uint16_t)value); + // trigger the send ? + DSPI_ClearStatusFlags(spi_address[obj->instance], kDSPI_TxFifoFillRequestFlag); + } // wait rx buffer full - while (!spi_readable(obj)); - rx_data = DSPI_ReadData(spi_address[obj->spi.instance]); - DSPI_ClearStatusFlags(spi_address[obj->spi.instance], kDSPI_RxFifoDrainRequestFlag | kDSPI_EndOfQueueFlag); + while (!(DSPI_GetStatusFlags(spi_address[obj->instance]) & kDSPI_RxFifoDrainRequestFlag)); + rx_data = DSPI_ReadData(spi_address[obj->instance]); + DSPI_ClearStatusFlags(spi_address[obj->instance], kDSPI_RxFifoDrainRequestFlag | kDSPI_EndOfQueueFlag); return rx_data & 0xffff; } -int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, - char *rx_buffer, int rx_length, char write_fill) -{ - int total = (tx_length > rx_length) ? tx_length : rx_length; - - // Default write is done in each and every call, in future can create HAL API instead - DSPI_SetDummyData(spi_address[obj->spi.instance], write_fill); - - DSPI_MasterTransferBlocking(spi_address[obj->spi.instance], &(dspi_transfer_t) { - .txData = (uint8_t *)tx_buffer, - .rxData = (uint8_t *)rx_buffer, - .dataSize = total, - .configFlags = kDSPI_MasterCtar0 | kDSPI_MasterPcs0 | kDSPI_MasterPcsContinuous, - }); +static void spi_irq_handler(spi_t *obj, status_t status) { + if (obj->handler != NULL) { + spi_async_handler_f handler = obj->handler; + void *ctx = obj->ctx; + obj->handler = NULL; + obj->ctx = NULL; - DSPI_ClearStatusFlags(spi_address[obj->spi.instance], kDSPI_RxFifoDrainRequestFlag | kDSPI_EndOfQueueFlag); + spi_async_event_t event = { + .transfered = obj->transfer_len, + .error = false + }; - return total; + handler(obj, ctx, &event); + } } - -int spi_slave_receive(spi_t *obj) -{ - return spi_readable(obj); +static void spi_master_irq_handler(SPI_Type *base, dspi_master_handle_t *handle, status_t status, void *userData) { + spi_irq_handler(userData, status); } - -int spi_slave_read(spi_t *obj) -{ - uint32_t rx_data; - - while (!spi_readable(obj)); - rx_data = DSPI_ReadData(spi_address[obj->spi.instance]); - DSPI_ClearStatusFlags(spi_address[obj->spi.instance], kDSPI_RxFifoDrainRequestFlag); - return rx_data & 0xffff; +static void spi_slave_irq_callback(SPI_Type *base, dspi_slave_handle_t *handle, status_t status, void *userData) { + spi_irq_handler(userData, status); } -void spi_slave_write(spi_t *obj, int value) -{ - DSPI_SlaveWriteDataBlocking(spi_address[obj->spi.instance], (uint32_t)value); +static void spi_sync_transfer_handler(spi_t *obj, void *ctx, spi_async_event_t *event) { + obj->transfered = event->transfered; } -static int32_t spi_master_transfer_asynch(spi_t *obj) -{ - dspi_transfer_t masterXfer; - int32_t status; - uint32_t transferSize; - - /*Start master transfer*/ - masterXfer.txData = obj->tx_buff.buffer; - masterXfer.rxData = obj->rx_buff.buffer; - masterXfer.dataSize = obj->tx_buff.length; - masterXfer.configFlags = kDSPI_MasterCtar0 | kDSPI_MasterPcs0 | kDSPI_MasterPcsContinuous; - /* Busy transferring */ - obj->spi.status = kDSPI_Busy; - - if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_ALLOCATED || - obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) { - status = DSPI_MasterTransferEDMA(spi_address[obj->spi.instance], &obj->spi.spi_dma_master_handle, &masterXfer); - if (status == kStatus_DSPI_OutOfRange) { - if (obj->spi.bits > 8) { - transferSize = 1022; - } else { - transferSize = 511; - } - masterXfer.dataSize = transferSize; - /* Save amount of TX done by DMA */ - obj->tx_buff.pos += transferSize; - obj->rx_buff.pos += transferSize; - /* Try again */ - status = DSPI_MasterTransferEDMA(spi_address[obj->spi.instance], &obj->spi.spi_dma_master_handle, &masterXfer); - } - } else { - status = DSPI_MasterTransferNonBlocking(spi_address[obj->spi.instance], &obj->spi.spi_master_handle, &masterXfer); - } - - return status; +static uint32_t spi_symbol_size(spi_t *obj) { + if (obj->bits > 16) { return 4; } + else if (obj->bits > 8) { return 2; } + return 1; } -static bool spi_allocate_dma(spi_t *obj, uint32_t handler) -{ - dma_request_source_t dma_rx_requests[] = SPI_DMA_RX_REQUEST_NUMBERS; - dma_request_source_t dma_tx_requests[] = SPI_DMA_TX_REQUEST_NUMBERS; - edma_config_t userConfig; - - /* Allocate the DMA channels */ - /* Allocate the RX channel */ - obj->spi.spiDmaMasterRx.dmaChannel = dma_channel_allocate(dma_rx_requests[obj->spi.instance]); - if (obj->spi.spiDmaMasterRx.dmaChannel == DMA_ERROR_OUT_OF_CHANNELS) { - return false; - } - - /* Check if we have separate DMA requests for TX & RX */ - if (dma_tx_requests[obj->spi.instance] != dma_rx_requests[obj->spi.instance]) { - /* Allocate the TX channel with the DMA TX request number set as source */ - obj->spi.spiDmaMasterTx.dmaChannel = dma_channel_allocate(dma_tx_requests[obj->spi.instance]); - } else { - /* Allocate the TX channel without setting source */ - obj->spi.spiDmaMasterTx.dmaChannel = dma_channel_allocate(kDmaRequestMux0Disable); - } - if (obj->spi.spiDmaMasterTx.dmaChannel == DMA_ERROR_OUT_OF_CHANNELS) { - dma_channel_free(obj->spi.spiDmaMasterRx.dmaChannel); - return false; +static uint32_t spi_get_symbol(spi_t *obj, const void *from, uint32_t i) { + uint32_t val = 0; + switch (spi_symbol_size(obj)) { + case 1: + val = ((uint8_t *)from)[i]; + break; + case 2: + val = ((uint16_t *)from)[i]; + break; + case 4: + val = ((uint32_t *)from)[i]; + break; + default: + // TODO: TRAP ? + break; } + return val; +} - /* Allocate an intermediary DMA channel */ - obj->spi.spiDmaMasterIntermediary.dmaChannel = dma_channel_allocate(kDmaRequestMux0Disable); - if (obj->spi.spiDmaMasterIntermediary.dmaChannel == DMA_ERROR_OUT_OF_CHANNELS) { - dma_channel_free(obj->spi.spiDmaMasterRx.dmaChannel); - dma_channel_free(obj->spi.spiDmaMasterTx.dmaChannel); - return false; +static void spi_set_symbol(spi_t *obj, void *to, uint32_t i, uint32_t val) { + switch (spi_symbol_size(obj)) { + case 1: + ((uint8_t *)to)[i] = val; + break; + case 2: + ((uint16_t *)to)[i] = val; + break; + case 4: + ((uint32_t *)to)[i] = val; + break; + default: + // TODO: TRAP ? + break; } - - /* EDMA init*/ - /* - * userConfig.enableRoundRobinArbitration = false; - * userConfig.enableHaltOnError = true; - * userConfig.enableContinuousLinkMode = false; - * userConfig.enableDebugMode = false; - */ - EDMA_GetDefaultConfig(&userConfig); - - EDMA_Init(DMA0, &userConfig); - - /* Set up dspi master */ - memset(&(obj->spi.spiDmaMasterRx.handle), 0, sizeof(obj->spi.spiDmaMasterRx.handle)); - memset(&(obj->spi.spiDmaMasterTx.handle), 0, sizeof(obj->spi.spiDmaMasterTx.handle)); - memset(&(obj->spi.spiDmaMasterIntermediary.handle), 0, sizeof(obj->spi.spiDmaMasterIntermediary.handle)); - - EDMA_CreateHandle(&(obj->spi.spiDmaMasterRx.handle), DMA0, obj->spi.spiDmaMasterRx.dmaChannel); - EDMA_CreateHandle(&(obj->spi.spiDmaMasterIntermediary.handle), DMA0, - obj->spi.spiDmaMasterIntermediary.dmaChannel); - EDMA_CreateHandle(&(obj->spi.spiDmaMasterTx.handle), DMA0, obj->spi.spiDmaMasterTx.dmaChannel); - - DSPI_MasterTransferCreateHandleEDMA(spi_address[obj->spi.instance], &obj->spi.spi_dma_master_handle, (dspi_master_edma_transfer_callback_t)handler, - NULL, &obj->spi.spiDmaMasterRx.handle, - &obj->spi.spiDmaMasterIntermediary.handle, - &obj->spi.spiDmaMasterTx.handle); - return true; } -static void spi_enable_dma(spi_t *obj, uint32_t handler, DMAUsage state) -{ - dma_init(); - - if (state == DMA_USAGE_ALWAYS && obj->spi.spiDmaMasterRx.dmaUsageState != DMA_USAGE_ALLOCATED) { - /* Try to allocate channels */ - if (spi_allocate_dma(obj, handler)) { - obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_ALLOCATED; - } else { - obj->spi.spiDmaMasterRx.dmaUsageState = state; - } - } else if (state == DMA_USAGE_OPPORTUNISTIC) { - if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_ALLOCATED) { - /* Channels have already been allocated previously by an ALWAYS state, so after this transfer, we will release them */ - obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED; +uint32_t spi_transfer(spi_t *obj, const void *tx_buffer, uint32_t tx_length, + void *rx_buffer, uint32_t rx_length, const void *fill) { + uint32_t total = 0; + if ((tx_length == 0) && (rx_length == 0)) { return 0; } + else if ((tx_length <= 1) && (rx_length <= 1)) { + uint32_t val_o = 0; + if (tx_length != 0) { + val_o = spi_get_symbol(obj, tx_buffer, 0); } else { - /* Try to allocate channels */ - if (spi_allocate_dma(obj, handler)) { - obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED; - } else { - obj->spi.spiDmaMasterRx.dmaUsageState = state; - } + val_o = spi_get_symbol(obj, fill, 0); } - } else if (state == DMA_USAGE_NEVER) { - /* If channels are allocated, get rid of them */ - if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_ALLOCATED) { - dma_channel_free(obj->spi.spiDmaMasterRx.dmaChannel); - dma_channel_free(obj->spi.spiDmaMasterTx.dmaChannel); - dma_channel_free(obj->spi.spiDmaMasterIntermediary.dmaChannel); - } - obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_NEVER; - } -} - -static void spi_buffer_set(spi_t *obj, const void *tx, uint32_t tx_length, void *rx, uint32_t rx_length, uint8_t bit_width) -{ - obj->tx_buff.buffer = (void *)tx; - obj->rx_buff.buffer = rx; - obj->tx_buff.length = tx_length; - obj->rx_buff.length = rx_length; - obj->tx_buff.pos = 0; - obj->rx_buff.pos = 0; - obj->tx_buff.width = bit_width; - obj->rx_buff.width = bit_width; -} - -void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint) -{ - if (spi_active(obj)) { - return; - } - - /* check corner case */ - if (tx_length == 0) { - tx_length = rx_length; - tx = (void *) 0; - } + uint32_t val_i = spi_write(obj, val_o); - /* First, set the buffer */ - spi_buffer_set(obj, tx, tx_length, rx, rx_length, bit_width); - - /* If using DMA, allocate channels only if they have not already been allocated */ - if (hint != DMA_USAGE_NEVER) { - /* User requested to transfer using DMA */ - spi_enable_dma(obj, handler, hint); - - /* Check if DMA setup was successful */ - if (obj->spi.spiDmaMasterRx.dmaUsageState != DMA_USAGE_ALLOCATED && obj->spi.spiDmaMasterRx.dmaUsageState != DMA_USAGE_TEMPORARY_ALLOCATED) { - /* Set up an interrupt transfer as DMA is unavailable */ - DSPI_MasterTransferCreateHandle(spi_address[obj->spi.instance], &obj->spi.spi_master_handle, (dspi_master_transfer_callback_t)handler, NULL); + if (rx_length != 0) { + spi_set_symbol(obj, rx_buffer, 0, val_i); } - + total = 1; } else { - /* User requested to transfer using interrupts */ - /* Disable the DMA */ - spi_enable_dma(obj, handler, hint); + SPI_Type *spi = spi_address[obj->instance]; - /* Set up the interrupt transfer */ - DSPI_MasterTransferCreateHandle(spi_address[obj->spi.instance], &obj->spi.spi_master_handle, (dspi_master_transfer_callback_t)handler, NULL); - } + total = (tx_length > rx_length) ? tx_length : rx_length; - /* Start the transfer */ - if (spi_master_transfer_asynch(obj) != kStatus_Success) { - obj->spi.status = kDSPI_Idle; + DSPI_TransferBlockingLimit(spi, &(dspi_transfer_t){ + .txData = (uint8_t *)tx_buffer, + .rxData = (uint8_t *)rx_buffer, + .dataSize = total * spi_symbol_size(obj), + .configFlags = kDSPI_MasterCtar0 | kDSPI_MasterPcs0 | kDSPI_MasterPcsContinuous, + }, tx_length, rx_length, *(uint32_t *)fill); + + DSPI_ClearStatusFlags(spi, kDSPI_RxFifoDrainRequestFlag | kDSPI_EndOfQueueFlag); } + + return total; } -uint32_t spi_irq_handler_asynch(spi_t *obj) +bool spi_transfer_async(spi_t *obj, const void *tx, uint32_t tx_len, void *rx, uint32_t rx_len, + const void *fill, spi_async_handler_f handler, void *ctx, DMAUsage hint) { - uint32_t transferSize; - dspi_transfer_t masterXfer; - - /* Determine whether the current scenario is DMA or IRQ, and act accordingly */ - if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) { - /* DMA implementation */ - /* Check If there is still data in the TX buffer */ - if (obj->tx_buff.pos < obj->tx_buff.length) { - /* Setup a new DMA transfer. */ - if (obj->spi.bits > 8) { - transferSize = 1022; - } else { - transferSize = 511; - } - - /* Update the TX buffer only if it is used */ - if (obj->tx_buff.buffer) { - masterXfer.txData = ((uint8_t *)obj->tx_buff.buffer) + obj->tx_buff.pos; - } else { - masterXfer.txData = 0; - } - - /* Update the RX buffer only if it is used */ - if (obj->rx_buff.buffer) { - masterXfer.rxData = ((uint8_t *)obj->rx_buff.buffer) + obj->rx_buff.pos; - } else { - masterXfer.rxData = 0; - } - - /* Check how much data is remaining in the buffer */ - if ((obj->tx_buff.length - obj->tx_buff.pos) > transferSize) { - masterXfer.dataSize = transferSize; - } else { - masterXfer.dataSize = obj->tx_buff.length - obj->tx_buff.pos; - } - masterXfer.configFlags = kDSPI_MasterCtar0 | kDSPI_MasterPcs0 | kDSPI_MasterPcsContinuous; - - /* Save amount of TX done by DMA */ - obj->tx_buff.pos += masterXfer.dataSize; - obj->rx_buff.pos += masterXfer.dataSize; - - /* Start another transfer */ - DSPI_MasterTransferEDMA(spi_address[obj->spi.instance], &obj->spi.spi_dma_master_handle, &masterXfer); - return 0; - } else { - /* Release the dma channels if they were opportunistically allocated */ - if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) { - dma_channel_free(obj->spi.spiDmaMasterRx.dmaChannel); - dma_channel_free(obj->spi.spiDmaMasterTx.dmaChannel); - dma_channel_free(obj->spi.spiDmaMasterIntermediary.dmaChannel); - obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_OPPORTUNISTIC; - } - obj->spi.status = kDSPI_Idle; - - return SPI_EVENT_COMPLETE; + SPI_Type *spi = spi_address[obj->instance]; + + obj->handler = handler; + obj->ctx = ctx; + + DSPI_SetDummyData(spi, *(uint32_t *)fill); + uint32_t len = (rx_len>tx_len)?rx_len:tx_len; + obj->transfer_len = len; + + if (!obj->is_slave) { + dspi_master_handle_t *handle = &obj->u.master.handle; + DSPI_MasterTransferCreateHandle(spi, handle, spi_master_irq_handler, obj); + if (DSPI_MasterTransferNonBlocking(spi, handle, &(dspi_transfer_t){ + .txData = (uint8_t *)tx, + .rxData = (uint8_t *)rx, + .dataSize = len * spi_symbol_size(obj), + .configFlags = kDSPI_MasterCtar0 | kDSPI_MasterPcs0 | kDSPI_MasterPcsContinuous, + }) != kStatus_Success) { + return false; } + DSPI_ClearStatusFlags(spi, kDSPI_RxFifoDrainRequestFlag | kDSPI_EndOfQueueFlag); } else { - /* Interrupt implementation */ - obj->spi.status = kDSPI_Idle; - - return SPI_EVENT_COMPLETE; + dspi_slave_handle_t *handle = &obj->u.slave.handle; + DSPI_SlaveTransferCreateHandle(spi, handle, spi_slave_irq_callback, obj); + if (DSPI_SlaveTransferNonBlocking(spi, handle, &(dspi_transfer_t){ + .txData = (uint8_t *)tx, + .rxData = (uint8_t *)rx, + .dataSize = len * spi_symbol_size(obj), + .configFlags = kDSPI_SlaveCtar0, + }) != kStatus_Success) { + return false; + } } + return true; } -void spi_abort_asynch(spi_t *obj) -{ - // If we're not currently transferring, then there's nothing to do here - if (spi_active(obj) == 0) { - return; - } +void spi_transfer_async_abort(spi_t *obj) { + SPI_Type *spi = spi_address[obj->instance]; - // Determine whether we're running DMA or interrupt - if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_ALLOCATED || - obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) { - DSPI_MasterTransferAbortEDMA(spi_address[obj->spi.instance], &obj->spi.spi_dma_master_handle); - /* Release the dma channels if they were opportunistically allocated */ - if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) { - dma_channel_free(obj->spi.spiDmaMasterRx.dmaChannel); - dma_channel_free(obj->spi.spiDmaMasterTx.dmaChannel); - dma_channel_free(obj->spi.spiDmaMasterIntermediary.dmaChannel); - obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_OPPORTUNISTIC; - } + if (obj->is_slave) { + DSPI_SlaveTransferAbort(spi, &obj->u.slave.handle); } else { - /* Interrupt implementation */ - DSPI_MasterTransferAbort(spi_address[obj->spi.instance], &obj->spi.spi_master_handle); + DSPI_MasterTransferAbort(spi, &obj->u.master.handle); } - - obj->spi.status = kDSPI_Idle; -} - -uint8_t spi_active(spi_t *obj) -{ - return obj->spi.status; } const PinMap *spi_master_mosi_pinmap() { - return PinMap_SPI_MOSI; + return PinMap_SPI_SOUT; } const PinMap *spi_master_miso_pinmap() { - return PinMap_SPI_MISO; + return PinMap_SPI_SIN; } const PinMap *spi_master_clk_pinmap() @@ -491,12 +626,12 @@ const PinMap *spi_master_cs_pinmap() const PinMap *spi_slave_mosi_pinmap() { - return PinMap_SPI_MOSI; + return PinMap_SPI_SIN; } const PinMap *spi_slave_miso_pinmap() { - return PinMap_SPI_MISO; + return PinMap_SPI_SOUT; } const PinMap *spi_slave_clk_pinmap() @@ -509,4 +644,4 @@ const PinMap *spi_slave_cs_pinmap() return PinMap_SPI_SSEL; } -#endif +#endif \ No newline at end of file diff --git a/targets/targets.json b/targets/targets.json index bae384bc6e3..cc932ed7b12 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1382,7 +1382,7 @@ }, "K64F": { "supported_form_factors": ["ARDUINO"], - "components_add": [], + "components_add": ["SD", "FLASHIAP"], "core": "Cortex-M4F", "supported_toolchains": ["ARM", "GCC_ARM", "IAR"], "extra_labels": [ @@ -1393,7 +1393,8 @@ "KPSDK_MCUS", "KPSDK_CODE", "MCU_K64F", - "Freescale_EMAC" + "Freescale_EMAC", + "PSA" ], "is_disk_virtual": true, "macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED", "MBEDTLS_PSA_CRYPTO_C"], @@ -1422,7 +1423,10 @@ "STORAGE", "TRNG", "FLASH", - "USBDEVICE" + "USBDEVICE", + "SPI", + "SPISLAVE", + "SPI_ASYNCH" ], "features": ["STORAGE"], "release_versions": ["2", "5"], @@ -1437,7 +1441,13 @@ "components_add": ["FLASHIAP"], "extra_labels_add": ["K64F"], "extra_labels_remove": ["FRDM"], + "components_remove": ["SD"], "supported_form_factors": [], + "device_has_remove": [ + "SPI", + "SPISLAVE", + "SPI_ASYNCH" + ], "detect_code": ["3105"] }, "EV_COG_AD4050LZ": {