From ee519e6a5ce2681770daf47b1a58476f5833f275 Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Fri, 11 Oct 2019 09:53:44 +0200 Subject: [PATCH 1/6] NUCLEO_F411RE, NUCLEO_L073RZ, NUCLEO_F303RE: Disable Analogin D13(PA_5) pin. Analogin test fails on D13(PA_5) pin. When logic one (3.3V) is provided on this pin ADC reads 0.86 value. On other pins we got 0.98. This is caused because this pin is connected to led2. --- .../TARGET_STM32F303xE/TARGET_NUCLEO_F303RE/PeripheralPins.c | 2 +- .../TARGET_STM32F411xE/TARGET_NUCLEO_F411RE/PeripheralPins.c | 2 +- .../TARGET_STM32L0/TARGET_NUCLEO_L073RZ/PeripheralPins.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/targets/TARGET_STM/TARGET_STM32F3/TARGET_STM32F303xE/TARGET_NUCLEO_F303RE/PeripheralPins.c b/targets/TARGET_STM/TARGET_STM32F3/TARGET_STM32F303xE/TARGET_NUCLEO_F303RE/PeripheralPins.c index e2acd728fb..6203c18d78 100644 --- a/targets/TARGET_STM/TARGET_STM32F3/TARGET_STM32F303xE/TARGET_NUCLEO_F303RE/PeripheralPins.c +++ b/targets/TARGET_STM/TARGET_STM32F3/TARGET_STM32F303xE/TARGET_NUCLEO_F303RE/PeripheralPins.c @@ -58,7 +58,7 @@ MBED_WEAK const PinMap PinMap_ADC[] = { // {PA_2, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC1_IN3 // Connected to STDIO_UART_TX // {PA_3, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC1_IN4 // Connected to STDIO_UART_RX {PA_4, ADC_2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 1, 0)}, // ADC2_IN1 - {PA_5, ADC_2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC2_IN2 // Connected to LD2 [Green Led] +// {PA_5, ADC_2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC2_IN2 // Connected to LD2 [Green Led] {PA_6, ADC_2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC2_IN3 {PA_7, ADC_2, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC2_IN4 {PB_0, ADC_3, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, // ADC3_IN12 diff --git a/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F411xE/TARGET_NUCLEO_F411RE/PeripheralPins.c b/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F411xE/TARGET_NUCLEO_F411RE/PeripheralPins.c index ada37f1db6..9988121260 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F411xE/TARGET_NUCLEO_F411RE/PeripheralPins.c +++ b/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F411xE/TARGET_NUCLEO_F411RE/PeripheralPins.c @@ -58,7 +58,7 @@ MBED_WEAK const PinMap PinMap_ADC[] = { // {PA_2, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC1_IN2 // Connected to STDIO_UART_TX // {PA_3, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC1_IN3 // Connected to STDIO_UART_RX {PA_4, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC1_IN4 - {PA_5, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC1_IN5 // Connected to LD2 [Green Led] +// {PA_5, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC1_IN5 // Connected to LD2 [Green Led] {PA_6, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC1_IN6 {PA_7, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC1_IN7 {PB_0, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC1_IN8 diff --git a/targets/TARGET_STM/TARGET_STM32L0/TARGET_NUCLEO_L073RZ/PeripheralPins.c b/targets/TARGET_STM/TARGET_STM32L0/TARGET_NUCLEO_L073RZ/PeripheralPins.c index 47e5f1b8a8..339f38fdcf 100644 --- a/targets/TARGET_STM/TARGET_STM32L0/TARGET_NUCLEO_L073RZ/PeripheralPins.c +++ b/targets/TARGET_STM/TARGET_STM32L0/TARGET_NUCLEO_L073RZ/PeripheralPins.c @@ -58,7 +58,7 @@ MBED_WEAK const PinMap PinMap_ADC[] = { // {PA_2, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 2, 0)}, // ADC_IN2 // Connected to STDIO_UART_TX // {PA_3, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 3, 0)}, // ADC_IN3 // Connected to STDIO_UART_RX {PA_4, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 4, 0)}, // ADC_IN4 - {PA_5, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC_IN5 // Connected to LD2 [Green Led] +// {PA_5, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 5, 0)}, // ADC_IN5 // Connected to LD2 [Green Led] {PA_6, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 6, 0)}, // ADC_IN6 {PA_7, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 7, 0)}, // ADC_IN7 {PB_0, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 8, 0)}, // ADC_IN8 From 95dc61dac3659ff855c80d8e2110fb3e6707b074 Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Mon, 14 Oct 2019 09:35:23 +0200 Subject: [PATCH 2/6] SPI fpga test: disable 16 bit test case for NRF52840_DK (not supported) --- TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp index 80d2456b8b..bcf2fc2e8a 100644 --- a/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp +++ b/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp @@ -178,9 +178,9 @@ Case cases[] = { Case("SPI - mode testing (MODE_1)", one_peripheral >), Case("SPI - mode testing (MODE_2)", one_peripheral >), Case("SPI - mode testing (MODE_3)", one_peripheral >), - +#if !defined(TARGET_NRF52840_DK) Case("SPI - symbol size testing (16)", one_peripheral >), - +#endif Case("SPI - frequency testing (500 kHz)", one_peripheral >), Case("SPI - frequency testing (2 MHz)", one_peripheral >), From c83307e96c975c43f0c531b0537c1777970cda3d Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Mon, 14 Oct 2019 12:19:51 +0200 Subject: [PATCH 3/6] NRF52: Fix PWM driver Fix pwm nrf --- targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/pwmout_api.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/pwmout_api.c b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/pwmout_api.c index 4f5f6dfb96..691af9d6f3 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/pwmout_api.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/pwmout_api.c @@ -297,7 +297,7 @@ void pwmout_pulsewidth(pwmout_t *obj, float pulse) DEBUG_PRINTF("pwmout_pulsewidt: %f\r\n", pulse); /* Cap pulsewidth to period before setting it. */ - if ((pulse * 1000000) > (float) (obj->pulse & ~SEQ_POLARITY_BIT)) { + if ((pulse * 1000000) > (float) obj->period) { obj->pulse &= SEQ_POLARITY_BIT; obj->pulse |= obj->period; pwmout_pulsewidth_us(obj, obj->pulse); @@ -354,4 +354,3 @@ const PinMap *pwmout_pinmap() } #endif // DEVICE_PWMOUT - From 766c3647d7580efb6bae1434d099a6a547b5ba0b Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Mon, 14 Oct 2019 12:25:48 +0200 Subject: [PATCH 4/6] Update tests-mbed_hal_fpga_ci_test_shield-pwm test (adapt for NRF_52) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like the PWM works fine on NRF52840_DK target, but this target has hardware limitation and the max PWM period is ‭32 767‬ us. That is why test cases when the period is set 50 ms are failing. The test will be modified to test the 30 ms period instead of 50 ms, so the test can pass on all CI targets. --- .../mbed_hal_fpga_ci_test_shield/pwm/main.cpp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/pwm/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/pwm/main.cpp index dd26813ace..f89e208891 100644 --- a/TESTS/mbed_hal_fpga_ci_test_shield/pwm/main.cpp +++ b/TESTS/mbed_hal_fpga_ci_test_shield/pwm/main.cpp @@ -190,26 +190,26 @@ Case cases[] = { Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral >), Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_us", one_peripheral >), - Case("PWM - period: 50 ms, fill: 10%, api: period/write", one_peripheral >), - Case("PWM - period: 50 ms, fill: 10%, api: period_ms/write", one_peripheral >), - Case("PWM - period: 50 ms, fill: 10%, api: period_us/write", one_peripheral >), - Case("PWM - period: 50 ms, fill: 10%, api: period/pulse_width", one_peripheral >), - Case("PWM - period: 50 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral >), - Case("PWM - period: 50 ms, fill: 10%, api: period/pulse_width_us", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period_ms/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period_us/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width_us", one_peripheral >), - Case("PWM - period: 50 ms, fill: 50%, api: period/write", one_peripheral >), - Case("PWM - period: 50 ms, fill: 50%, api: period_ms/write", one_peripheral >), - Case("PWM - period: 50 ms, fill: 50%, api: period_us/write", one_peripheral >), - Case("PWM - period: 50 ms, fill: 50%, api: period/pulse_width", one_peripheral >), - Case("PWM - period: 50 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral >), - Case("PWM - period: 50 ms, fill: 50%, api: period/pulse_width_us", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period_ms/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period_us/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width_us", one_peripheral >), - Case("PWM - period: 50 ms, fill: 90%, api: period/write", one_peripheral >), - Case("PWM - period: 50 ms, fill: 90%, api: period_ms/write", one_peripheral >), - Case("PWM - period: 50 ms, fill: 90%, api: period_us/write", one_peripheral >), - Case("PWM - period: 50 ms, fill: 90%, api: period/pulse_width", one_peripheral >), - Case("PWM - period: 50 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral >), - Case("PWM - period: 50 ms, fill: 90%, api: period/pulse_width_us", one_peripheral >) + Case("PWM - period: 30 ms, fill: 90%, api: period/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 90%, api: period_ms/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 90%, api: period_us/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width", one_peripheral >), + Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral >), + Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width_us", one_peripheral >) }; utest::v1::status_t greentea_test_setup(const size_t number_of_cases) From 4b1b4f72af5529cb9efa0c2f98891e246f0f53f5 Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Tue, 5 Nov 2019 12:34:31 +0100 Subject: [PATCH 5/6] Add spi_get_capabilities() function to HAL API Add also default weak version of spi_get_capabilities() which provides default/most common SPI parameters. This function can be replaced if a specific target has different capabilities. --- hal/mbed_compat.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ hal/spi_api.h | 32 ++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/hal/mbed_compat.c b/hal/mbed_compat.c index eefe5f3a4c..5aa93138f5 100644 --- a/hal/mbed_compat.c +++ b/hal/mbed_compat.c @@ -17,6 +17,7 @@ #include "analogin_api.h" #include "i2c_api.h" +#include "spi_api.h" #include "gpio_api.h" #include "mbed_toolchain.h" @@ -40,4 +41,53 @@ MBED_WEAK void analogin_free(analogin_t *obj) { // Do nothing } +#endif + +#if DEVICE_SPI +// Default SPI capabilities. If specific target has different capabilities this function needs to be re-implemented. +MBED_WEAK 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 +#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 +#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++; + } +} + #endif \ No newline at end of file diff --git a/hal/spi_api.h b/hal/spi_api.h index 21a22d1b95..54ea7fa221 100644 --- a/hal/spi_api.h +++ b/hal/spi_api.h @@ -53,6 +53,28 @@ typedef struct spi_s spi_t; #endif +/** + * Describes the capabilities of a SPI peripherals + */ +typedef struct { + /** Minimum frequency supported must be set by target device and it will be assessed during + * testing. + */ + uint32_t minimum_frequency; + /** Maximum frequency supported must be set by target device and it will be assessed during + * testing. + */ + uint32_t maximum_frequency; + /** Each bit represents the corresponding word length. lsb => 1bit, msb => 32bit. */ + uint32_t word_length; + uint16_t slave_delay_between_symbols_ns; /**< specifies required number of ns between transmission of successive symbols in slave mode. */ + uint8_t clk_modes; /**< specifies supported modes from spi_mode_t. Each bit represents the corresponding mode. */ + 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. */ + +} spi_capabilities_t; + #ifdef __cplusplus extern "C" { #endif @@ -63,6 +85,11 @@ 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 @@ -125,6 +152,11 @@ extern "C" { SPIName spi_get_peripheral_name(PinName mosi, PinName miso, PinName mclk); #endif +/** + * Fills the given spi_capabilities_t structure with the capabilities of the given peripheral. + */ +void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap); + /** Initialize the SPI peripheral * * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral From b24afed5aee4c7f8d3682b53be330769c47e7dd6 Mon Sep 17 00:00:00 2001 From: Przemyslaw Stekiel Date: Wed, 6 Nov 2019 09:54:02 +0100 Subject: [PATCH 6/6] SPI fpga test: use get_capabilities() function to skip test cases for unsupported features --- .../mbed_hal_fpga_ci_test_shield/spi/main.cpp | 53 ++++++++++-- .../TARGET_NRF5x/TARGET_NRF52/spi_api.c | 80 +++++++++++++++---- 2 files changed, 109 insertions(+), 24 deletions(-) diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp index bcf2fc2e8a..8c8c0d53d8 100644 --- a/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp +++ b/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp @@ -41,9 +41,13 @@ typedef enum { TRANSFER_SPI_MASTER_TRANSFER_ASYNC } transfer_type_t; -#define FREQ_500_KHZ 500000 -#define FREQ_1_MHZ 1000000 -#define FREQ_2_MHZ 2000000 +#define FREQ_500_KHZ 500000 +#define FREQ_1_MHZ 1000000 +#define FREQ_2_MHZ 2000000 +#define FREQ_MIN ((uint32_t)0) +#define FREQ_MAX ((uint32_t)-1) + +#define TEST_CAPABILITY_BIT(MASK, CAP) ((1 << CAP) & (MASK)) const int TRANSFER_COUNT = 300; SPIMasterTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); @@ -62,6 +66,36 @@ void spi_async_handler() } #endif +/* 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) +{ + // Symbol size + if (!TEST_CAPABILITY_BIT(capabilities->word_length, (sym_size - 1))) { + utest_printf("\n skipped "); + return false; + } + + // SPI clock mode + if (!TEST_CAPABILITY_BIT(capabilities->clk_modes, spi_mode)) { + utest_printf("\n skipped"); + return false; + } + + // Frequency + if (frequency != FREQ_MAX && frequency != FREQ_MIN && frequency < capabilities->minimum_frequency && frequency > capabilities->maximum_frequency) { + utest_printf("\n skipped "); + return false; + } + + // Async mode + if (transfer_type == TRANSFER_SPI_MASTER_TRANSFER_ASYNC && capabilities->async_mode == false) { + utest_printf("\n skipped "); + return false; + } + + return true; +} + void fpga_spi_test_init_free(PinName mosi, PinName miso, PinName sclk, PinName ssel) { spi_init(&spi, mosi, miso, sclk, ssel); @@ -72,6 +106,15 @@ void fpga_spi_test_init_free(PinName mosi, PinName miso, PinName sclk, PinName s 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) { + spi_capabilities_t capabilities; + + + spi_get_capabilities(ssel, false, &capabilities); + + if (check_capabilities(&capabilities, spi_mode, sym_size, transfer_type, frequency) == false) { + return; + } + uint32_t sym_mask = ((1 << sym_size) - 1); // Remap pins for test @@ -178,14 +221,10 @@ Case cases[] = { Case("SPI - mode testing (MODE_1)", one_peripheral >), Case("SPI - mode testing (MODE_2)", one_peripheral >), Case("SPI - mode testing (MODE_3)", one_peripheral >), -#if !defined(TARGET_NRF52840_DK) Case("SPI - symbol size testing (16)", one_peripheral >), -#endif Case("SPI - frequency testing (500 kHz)", one_peripheral >), Case("SPI - frequency testing (2 MHz)", one_peripheral >), - Case("SPI - block write", one_peripheral >), - #if DEVICE_SPI_ASYNCH Case("SPI - async mode", one_peripheral >) #endif diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/spi_api.c b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/spi_api.c index e16ae414e0..7fdd876885 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/spi_api.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/spi_api.c @@ -105,7 +105,7 @@ static void spi_configure_driver_instance(spi_t *obj) /* Clean up and uninitialize peripheral if already initialized. */ if (nordic_nrf5_spi_initialized[instance]) { - nrfx_spi_uninit(&nordic_nrf5_spi_instance[instance]); + nrfx_spi_uninit(&nordic_nrf5_spi_instance[instance]); } #if DEVICE_SPI_ASYNCH @@ -128,6 +128,51 @@ static void spi_configure_driver_instance(spi_t *obj) } } +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 = 0x00000080; // 8 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 +#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 = 0x00000080; // 8 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 +#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++; + } +} + /** Initialize the SPI peripheral * * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral @@ -191,7 +236,7 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel /* Register interrupt handlers in driver with the NVIC. */ NVIC_SetVector(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn, (uint32_t) SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler); NVIC_SetVector(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQn, (uint32_t) SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler); - NVIC_SetVector(SPIM2_SPIS2_SPI2_IRQn, (uint32_t) SPIM2_SPIS2_SPI2_IRQHandler); + NVIC_SetVector(SPIM2_SPIS2_SPI2_IRQn, (uint32_t) SPIM2_SPIS2_SPI2_IRQHandler); } } @@ -247,13 +292,13 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) nrf_spi_mode_t new_mode = NRF_SPI_MODE_0; /* Convert Mbed HAL mode to Nordic mode. */ - if(mode == 0) { + if (mode == 0) { new_mode = NRF_SPI_MODE_0; - } else if(mode == 1) { + } else if (mode == 1) { new_mode = NRF_SPI_MODE_1; - } else if(mode == 2) { + } else if (mode == 2) { new_mode = NRF_SPI_MODE_2; - } else if(mode == 3) { + } else if (mode == 3) { new_mode = NRF_SPI_MODE_3; } @@ -351,8 +396,9 @@ int spi_master_write(spi_t *obj, int value) desc.rx_length = 1; ret = nrfx_spi_xfer(&nordic_nrf5_spi_instance[instance], &desc, 0); - if (ret != NRFX_SUCCESS) + if (ret != NRFX_SUCCESS) { DEBUG_PRINTF("%d error returned from nrf_spi_xfer\n\r"); + } /* Manually set chip select pin if defined. */ if (spi_inst->cs != NC) { @@ -421,17 +467,17 @@ int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, cha int tx_actual_length = (tx_length > 255) ? 255 : tx_length; /* Set tx buffer pointer. Set to NULL if no data is going to be transmitted. */ - const uint8_t * tx_actual_buffer = (tx_actual_length > 0) ? - (const uint8_t *)(tx_buffer + tx_offset) : - NULL; + const uint8_t *tx_actual_buffer = (tx_actual_length > 0) ? + (const uint8_t *)(tx_buffer + tx_offset) : + NULL; /* Check if rx_length is larger than 255 and if so, limit to 255. */ int rx_actual_length = (rx_length > 255) ? 255 : rx_length; /* Set rx buffer pointer. Set to NULL if no data is going to be received. */ - uint8_t * rx_actual_buffer = (rx_actual_length > 0) ? - (uint8_t *)(rx_buffer + rx_offset) : - NULL; + uint8_t *rx_actual_buffer = (rx_actual_length > 0) ? + (uint8_t *)(rx_buffer + rx_offset) : + NULL; /* Blocking transfer. */ desc.p_tx_buffer = tx_actual_buffer; @@ -439,7 +485,7 @@ int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, cha desc.tx_length = tx_actual_length; desc.rx_length = rx_actual_length; result = nrfx_spi_xfer(&nordic_nrf5_spi_instance[instance], - &desc, 0); + &desc, 0); /* Update loop variables. */ tx_length -= tx_actual_length; @@ -596,7 +642,7 @@ static ret_code_t spi_master_transfer_async_continue(spi_t *obj) desc.rx_length = rx_length; ret_code_t result = nrfx_spi_xfer(&nordic_nrf5_spi_instance[obj->spi.instance], - &desc, 0); + &desc, 0); return result; } @@ -662,7 +708,7 @@ static void nordic_nrf5_spi_event_handler(nrfx_spi_evt_t const *p_event, void *p callback(); } - /* Transfer failed, signal error if mask is set. */ + /* Transfer failed, signal error if mask is set. */ } else if (signal_error) { /* Signal error if event mask matches and event handler is set. */ @@ -721,7 +767,7 @@ void spi_master_transfer(spi_t *obj, struct buffer_s *buffer_pointer; buffer_pointer = &obj->tx_buff; - buffer_pointer->buffer = (void*) tx; + buffer_pointer->buffer = (void *) tx; buffer_pointer->length = tx_length; buffer_pointer->pos = 0; buffer_pointer->width = 8;