diff --git a/hal/targets.json b/hal/targets.json index 2d1fa7b062..fcb8b3f965 100644 --- a/hal/targets.json +++ b/hal/targets.json @@ -1581,7 +1581,8 @@ "extra_labels": ["Silicon_Labs", "EFM32"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM"], "progen": {"target": "efm32gg-stk"}, - "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"] + "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], + "forced_reset_timeout": 2 }, "EFM32LG_STK3600": { "inherits": ["Target"], @@ -1590,7 +1591,8 @@ "extra_labels": ["Silicon_Labs", "EFM32"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM"], "progen": {"target": "efm32lg-stk"}, - "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"] + "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], + "forced_reset_timeout": 2 }, "EFM32WG_STK3800": { "inherits": ["Target"], @@ -1599,7 +1601,8 @@ "extra_labels": ["Silicon_Labs", "EFM32"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM"], "progen": {"target": "efm32wg-stk"}, - "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"] + "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], + "forced_reset_timeout": 2 }, "EFM32ZG_STK3200": { "inherits": ["Target"], @@ -1612,7 +1615,8 @@ "target": "efm32zg-stk" }, "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], - "default_build": "small" + "default_build": "small", + "forced_reset_timeout": 2 }, "EFM32HG_STK3400": { "inherits": ["Target"], @@ -1625,7 +1629,8 @@ "target": "efm32hg-stk" }, "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], - "default_build": "small" + "default_build": "small", + "forced_reset_timeout": 2 }, "EFM32PG_STK3401": { "inherits": ["Target"], @@ -1634,7 +1639,8 @@ "extra_labels": ["Silicon_Labs", "EFM32"], "supported_toolchains": ["GCC_ARM", "ARM", "uARM", "IAR"], "progen": {"target": "efm32pg-stk"}, - "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"] + "device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], + "forced_reset_timeout": 2 }, "WIZWIKI_W7500": { "supported_form_factors": ["ARDUINO"], diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG_STK3700/PeripheralPins.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG_STK3700/PeripheralPins.c index c5596175d1..9a0d3708f5 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG_STK3700/PeripheralPins.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG_STK3700/PeripheralPins.c @@ -86,9 +86,15 @@ const PinMap PinMap_I2C_SDA[] = { /************PWM***************/ const PinMap PinMap_PWM[] = { - {PA12, PWM_CH0, 0}, - {PA13, PWM_CH1, 0}, - {PA14, PWM_CH2, 0}, + {PA8, PWM_CH0, 0}, + {PA9, PWM_CH1, 0}, + {PA10, PWM_CH2, 0}, + {PA12, PWM_CH0, 1}, + {PA13, PWM_CH1, 1}, + {PA14, PWM_CH2, 1}, + {PC8, PWM_CH0, 2}, + {PC9, PWM_CH1, 2}, + {PC10, PWM_CH2, 2}, {NC , NC , 0} }; diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32HG_STK3400/PeripheralPins.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32HG_STK3400/PeripheralPins.c index ab148d0359..4f1712296f 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32HG_STK3400/PeripheralPins.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32HG_STK3400/PeripheralPins.c @@ -62,6 +62,9 @@ const PinMap PinMap_PWM[] = { {PA0, PWM_CH0, 0}, {PA1, PWM_CH1, 0}, {PA2, PWM_CH2, 0}, + {PF0, PWM_CH0, 5}, + {PF1, PWM_CH1, 5}, + {PF2, PWM_CH2, 5}, {NC , NC , NC} }; diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32LG_STK3600/PeripheralPins.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32LG_STK3600/PeripheralPins.c index c5596175d1..9a0d3708f5 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32LG_STK3600/PeripheralPins.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32LG_STK3600/PeripheralPins.c @@ -86,9 +86,15 @@ const PinMap PinMap_I2C_SDA[] = { /************PWM***************/ const PinMap PinMap_PWM[] = { - {PA12, PWM_CH0, 0}, - {PA13, PWM_CH1, 0}, - {PA14, PWM_CH2, 0}, + {PA8, PWM_CH0, 0}, + {PA9, PWM_CH1, 0}, + {PA10, PWM_CH2, 0}, + {PA12, PWM_CH0, 1}, + {PA13, PWM_CH1, 1}, + {PA14, PWM_CH2, 1}, + {PC8, PWM_CH0, 2}, + {PC9, PWM_CH1, 2}, + {PC10, PWM_CH2, 2}, {NC , NC , 0} }; diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32WG_STK3800/PeripheralPins.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32WG_STK3800/PeripheralPins.c index c5596175d1..9a0d3708f5 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32WG_STK3800/PeripheralPins.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32WG_STK3800/PeripheralPins.c @@ -86,9 +86,15 @@ const PinMap PinMap_I2C_SDA[] = { /************PWM***************/ const PinMap PinMap_PWM[] = { - {PA12, PWM_CH0, 0}, - {PA13, PWM_CH1, 0}, - {PA14, PWM_CH2, 0}, + {PA8, PWM_CH0, 0}, + {PA9, PWM_CH1, 0}, + {PA10, PWM_CH2, 0}, + {PA12, PWM_CH0, 1}, + {PA13, PWM_CH1, 1}, + {PA14, PWM_CH2, 1}, + {PC8, PWM_CH0, 2}, + {PC9, PWM_CH1, 2}, + {PC10, PWM_CH2, 2}, {NC , NC , 0} }; diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TESTS/spi/basic-spi/main.cpp b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TESTS/spi/basic-spi/main.cpp new file mode 100644 index 0000000000..08b120ecfe --- /dev/null +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/TESTS/spi/basic-spi/main.cpp @@ -0,0 +1,378 @@ +/***************************************************************************//** + * @file main.cpp + ******************************************************************************* + * @section License + * (C) Copyright 2016 Silicon Labs, http://www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ******************************************************************************/ + +#include "mbed.h" + +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest/utest.h" + +#include "em_cmu.h" +#include "em_gpio.h" +#include "em_prs.h" +#include "em_timer.h" + +#define SHORT_TRANSFER_FRAMES 16 +#define LONG_TRANSFER_FRAMES 1842 + +#if defined(TARGET_EFM32GG_STK3700) || defined(TARGET_EFM32LG_STK3600) || defined(TARGET_EFM32WG_STK3800) + +#define TEST 1 + +#define TEST_UART USART1 +#define MOSI_PIN PD0 +#define MISO_PIN PD1 +#define CLK_PIN PD2 +#define CS_PIN PD3 + +#define GPIO_PORT gpioPortD +#define GPIO_PIN_TX 0 +#define GPIO_PIN_CLK 2 +#define GPIO_PRS_SRC_TX PRS_CH_CTRL_SOURCESEL_GPIOL +#define GPIO_PRS_SIG_TX PRS_CH_CTRL_SIGSEL_GPIOPIN0 +#define GPIO_PRS_SRC_CLK PRS_CH_CTRL_SOURCESEL_GPIOL +#define GPIO_PRS_SIG_CLK PRS_CH_CTRL_SIGSEL_GPIOPIN2 + +#define TEST_TIMER TIMER1 +#define TEST_TIMER_CLOCK cmuClock_TIMER1 + +#elif defined(TARGET_EFM32PG_STK3401) + +#define TEST 1 + +#define TEST_UART USART1 +#define MOSI_PIN PC6 +#define MISO_PIN PC7 +#define CLK_PIN PC8 +#define CS_PIN PC9 + +#define GPIO_PORT gpioPortC +#define GPIO_PIN_TX 6 +#define GPIO_PIN_CLK 8 +#define GPIO_PRS_SRC_TX PRS_CH_CTRL_SOURCESEL_GPIOL +#define GPIO_PRS_SIG_TX PRS_CH_CTRL_SIGSEL_GPIOPIN6 +#define GPIO_PRS_SRC_CLK PRS_CH_CTRL_SOURCESEL_GPIOH +#define GPIO_PRS_SIG_CLK PRS_CH_CTRL_SIGSEL_GPIOPIN8 + +#define TEST_TIMER TIMER1 +#define TEST_TIMER_CLOCK cmuClock_TIMER1 + +#else +#define TEST 0 +#warning "Test config not defined; skipping test" +#endif + +using namespace utest::v1; + +#if TEST +DigitalOut cs(CS_PIN); +static volatile bool complete; +event_callback_t cb; + +static uint8_t short_data_8[SHORT_TRANSFER_FRAMES]; +static uint16_t short_data_16[SHORT_TRANSFER_FRAMES]; +static uint32_t short_data_32[SHORT_TRANSFER_FRAMES]; + +static uint8_t short_data_8_rx[SHORT_TRANSFER_FRAMES]; +static uint16_t short_data_16_rx[SHORT_TRANSFER_FRAMES]; +static uint32_t short_data_32_rx[SHORT_TRANSFER_FRAMES]; + +static uint8_t long_data_8[LONG_TRANSFER_FRAMES]; +static uint16_t long_data_16[LONG_TRANSFER_FRAMES]; + +static uint8_t long_data_8_rx[LONG_TRANSFER_FRAMES]; +static uint16_t long_data_16_rx[LONG_TRANSFER_FRAMES]; + +void callbackFunction(int flags) { + complete = true; +} + +void init_timer() { + CMU_ClockEnable(cmuClock_PRS, true); + CMU_ClockEnable(cmuClock_GPIO, true); + CMU_ClockEnable(TEST_TIMER_CLOCK, true); + + // Setup USART TX pin as PRS producer + GPIO_IntConfig(GPIO_PORT, GPIO_PIN_TX, false, false, false); + PRS_SourceSignalSet(0, + GPIO_PRS_SRC_TX, + GPIO_PRS_SIG_TX, + prsEdgeOff); + + // Setup USART CLK pin as PRS producer + GPIO_IntConfig(GPIO_PORT, GPIO_PIN_CLK, false, false, false); + PRS_SourceSignalSet(1, + GPIO_PRS_SRC_CLK, + GPIO_PRS_SIG_CLK, + prsEdgeOff); + + // Setup timer to count on PRS pulses + TIMER_Init_TypeDef timInit = TIMER_INIT_DEFAULT; + timInit.enable = false; + timInit.clkSel = timerClkSelCC1; + + TIMER_InitCC_TypeDef timInitCC = TIMER_INITCC_DEFAULT; + timInitCC.prsInput = true; + timInitCC.prsSel = timerPRSSELCh1; + + TIMER_Init(TEST_TIMER, &timInit); + TIMER_InitCC(TEST_TIMER, 1, &timInitCC); + + TIMER_Enable(TEST_TIMER, true); +} + +template +void init_arrays(T * tx, T * rx, int len, uint32_t mask) { + for (uint32_t i = 0; i < len; i++) { + if (tx) { + tx[i] = i & mask; + } + if (rx) { + rx[i] = 0; + } + } +} + +template +void test_transfer(int bits, int polarity, int freq, DMAUsage dma, T * data_tx, T * data_rx, int len) { + SPI spi(MOSI_PIN, MISO_PIN, CLK_PIN); + + spi.format(bits, polarity); + spi.frequency(freq); + + spi.set_dma_usage(dma); + + // Clear RX buffer, setup tx pattern + init_arrays(data_tx, data_rx, len, (1 << bits) - 1); + + // Set up PRS loopback of TX data to RX + TEST_UART->INPUT = USART_INPUT_RXPRS | USART_INPUT_RXPRSSEL_PRSCH0; + + complete = false; + TIMER1->CNT = 0; + cs = 0; + spi.transfer(data_tx, len, data_rx, data_rx ? len : 0, cb); + + while (!complete); + + uint32_t xferred = TIMER1->CNT; + cs = 1; + + // Check that all bits were sent + TEST_ASSERT_EQUAL(bits*len, xferred); + + // Check that all data was received correctly + if (data_rx) { + for (int i = 0; i < len; i++) { + TEST_ASSERT_EQUAL(data_tx[i], data_rx[i]); + } + } +} + +//////////////////////////////// +// Short single transfers + +void test_5bit_8bit_0_1mhz_short_transfer() { + test_transfer(5, 0, 1000000, DMA_USAGE_NEVER, short_data_8, short_data_8_rx, SHORT_TRANSFER_FRAMES); +} + +void test_5bit_8bit_0_1mhz_short_dma_transfer() { + test_transfer(5, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, short_data_8, short_data_8_rx, SHORT_TRANSFER_FRAMES); +} + +void test_5bit_16bit_0_1mhz_short_transfer() { + test_transfer(5, 0, 1000000, DMA_USAGE_NEVER, short_data_16, short_data_16_rx, SHORT_TRANSFER_FRAMES); +} + +void test_5bit_16bit_0_1mhz_short_dma_transfer() { + test_transfer(5, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, short_data_16, short_data_16_rx, SHORT_TRANSFER_FRAMES); +} + +void test_8bit_8bit_0_1mhz_short_transfer() { + test_transfer(8, 0, 1000000, DMA_USAGE_NEVER, short_data_8, short_data_8_rx, SHORT_TRANSFER_FRAMES); +} + +void test_8bit_8bit_0_1mhz_short_dma_transfer() { + test_transfer(8, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, short_data_8, short_data_8_rx, SHORT_TRANSFER_FRAMES); +} + +void test_8bit_16bit_0_1mhz_short_transfer() { + test_transfer(8, 0, 1000000, DMA_USAGE_NEVER, short_data_16, short_data_16_rx, SHORT_TRANSFER_FRAMES); +} + +void test_8bit_16bit_0_1mhz_short_dma_transfer() { + test_transfer(8, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, short_data_16, short_data_16_rx, SHORT_TRANSFER_FRAMES); +} + +//////////////////////////////// +// Short extended/double transfers + +void test_9bit_16bit_0_1mhz_short_transfer() { + test_transfer(9, 0, 1000000, DMA_USAGE_NEVER, short_data_16, short_data_16_rx, SHORT_TRANSFER_FRAMES); +} + +void test_9bit_16bit_0_1mhz_short_dma_transfer() { + test_transfer(9, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, short_data_16, short_data_16_rx, SHORT_TRANSFER_FRAMES); +} + +void test_9bit_32bit_0_1mhz_short_transfer() { + test_transfer(9, 0, 1000000, DMA_USAGE_NEVER, short_data_32, short_data_32_rx, SHORT_TRANSFER_FRAMES); +} + +void test_9bit_32bit_0_1mhz_short_dma_transfer() { + test_transfer(9, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, short_data_32, short_data_32_rx, SHORT_TRANSFER_FRAMES); +} + +void test_16bit_16bit_0_1mhz_short_transfer() { + test_transfer(16, 0, 1000000, DMA_USAGE_NEVER, short_data_16, short_data_16_rx, SHORT_TRANSFER_FRAMES); +} + +void test_16bit_16bit_0_1mhz_short_dma_transfer() { + test_transfer(16, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, short_data_16, short_data_16_rx, SHORT_TRANSFER_FRAMES); +} + +void test_16bit_32bit_0_1mhz_short_transfer() { + test_transfer(16, 0, 1000000, DMA_USAGE_NEVER, short_data_32, short_data_32_rx, SHORT_TRANSFER_FRAMES); +} + +void test_16bit_32bit_0_1mhz_short_dma_transfer() { + test_transfer(16, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, short_data_32, short_data_32_rx, SHORT_TRANSFER_FRAMES); +} + +//////////////////////////////// +// Long single transfers + +void test_5bit_8bit_0_1mhz_long_transfer() { + test_transfer(5, 0, 1000000, DMA_USAGE_NEVER, long_data_8, long_data_8_rx, LONG_TRANSFER_FRAMES); +} + +void test_5bit_8bit_0_1mhz_long_dma_transfer() { + test_transfer(5, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, long_data_8, long_data_8_rx, LONG_TRANSFER_FRAMES); +} + +void test_5bit_16bit_0_1mhz_long_transfer() { + test_transfer(5, 0, 1000000, DMA_USAGE_NEVER, long_data_16, long_data_16_rx, LONG_TRANSFER_FRAMES); +} + +void test_5bit_16bit_0_1mhz_long_dma_transfer() { + test_transfer(5, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, long_data_16, long_data_16_rx, LONG_TRANSFER_FRAMES); +} + +void test_8bit_8bit_0_1mhz_long_transfer() { + test_transfer(8, 0, 1000000, DMA_USAGE_NEVER, long_data_8, long_data_8_rx, LONG_TRANSFER_FRAMES); +} + +void test_8bit_8bit_0_1mhz_long_dma_transfer() { + test_transfer(8, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, long_data_8, long_data_8_rx, LONG_TRANSFER_FRAMES); +} + +void test_8bit_16bit_0_1mhz_long_transfer() { + test_transfer(8, 0, 1000000, DMA_USAGE_NEVER, long_data_16, long_data_16_rx, LONG_TRANSFER_FRAMES); +} + +void test_8bit_16bit_0_1mhz_long_dma_transfer() { + test_transfer(8, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, long_data_16, long_data_16_rx, LONG_TRANSFER_FRAMES); +} + +//////////////////////////////// +// Long extended/double transfers + +void test_9bit_16bit_0_1mhz_long_transfer() { + test_transfer(9, 0, 1000000, DMA_USAGE_NEVER, long_data_16, long_data_16_rx, LONG_TRANSFER_FRAMES); +} + +void test_9bit_16bit_0_1mhz_long_dma_transfer() { + test_transfer(9, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, long_data_16, long_data_16_rx, LONG_TRANSFER_FRAMES); +} + +void test_16bit_16bit_0_1mhz_long_transfer() { + test_transfer(16, 0, 1000000, DMA_USAGE_NEVER, long_data_16, long_data_16_rx, LONG_TRANSFER_FRAMES); +} + +void test_16bit_16bit_0_1mhz_long_dma_transfer() { + test_transfer(16, 0, 1000000, DMA_USAGE_OPPORTUNISTIC, long_data_16, long_data_16_rx, LONG_TRANSFER_FRAMES); +} + +//////////////////////////////// +#else +void test_dummy() { + TEST_IGNORE_MESSAGE("This test is not compatible with this target."); +} +#endif + +utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason) { + greentea_case_failure_abort_handler(source, reason); + return STATUS_CONTINUE; +} + +Case cases[] = { +#if TEST + Case("5-bit frames with 8-bit data, 1 MHz (short)", test_5bit_8bit_0_1mhz_short_transfer, greentea_failure_handler), + Case("5-bit frames with 8-bit data, 1 MHz, DMA (short)", test_5bit_8bit_0_1mhz_short_dma_transfer, greentea_failure_handler), + Case("5-bit frames with 16-bit data, 1 MHz (short)", test_5bit_16bit_0_1mhz_short_transfer, greentea_failure_handler), + Case("5-bit frames with 16-bit data, 1 MHz, DMA (short)", test_5bit_16bit_0_1mhz_short_dma_transfer, greentea_failure_handler), + Case("8-bit frames with 8-bit data, 1 MHz (short)", test_8bit_8bit_0_1mhz_short_transfer, greentea_failure_handler), + Case("8-bit frames with 8-bit data, 1 MHz, DMA (short)", test_8bit_8bit_0_1mhz_short_dma_transfer, greentea_failure_handler), + Case("8-bit frames with 16-bit data, 1 MHz (short)", test_8bit_16bit_0_1mhz_short_transfer, greentea_failure_handler), + Case("8-bit frames with 16-bit data, 1 MHz, DMA (short)", test_8bit_16bit_0_1mhz_short_dma_transfer, greentea_failure_handler), + Case("9-bit frames with 16-bit data, 1 MHz (short)", test_9bit_16bit_0_1mhz_short_transfer, greentea_failure_handler), + Case("9-bit frames with 16-bit data, 1 MHz, DMA (short)", test_9bit_16bit_0_1mhz_short_dma_transfer, greentea_failure_handler), + Case("9-bit frames with 32-bit data, 1 MHz (short)", test_9bit_32bit_0_1mhz_short_transfer, greentea_failure_handler), + Case("9-bit frames with 32-bit data, 1 MHz, DMA (short)", test_9bit_32bit_0_1mhz_short_dma_transfer, greentea_failure_handler), + Case("16-bit frames with 16-bit data, 1 MHz (short)", test_16bit_16bit_0_1mhz_short_transfer, greentea_failure_handler), + Case("16-bit frames with 16-bit data, 1 MHz, DMA (short)", test_16bit_16bit_0_1mhz_short_dma_transfer, greentea_failure_handler), + Case("16-bit frames with 32-bit data, 1 MHz (short)", test_16bit_32bit_0_1mhz_short_transfer, greentea_failure_handler), + Case("16-bit frames with 32-bit data, 1 MHz, DMA (short)", test_16bit_32bit_0_1mhz_short_dma_transfer, greentea_failure_handler), + + Case("5-bit frames with 8-bit data, 1 MHz (long)", test_5bit_8bit_0_1mhz_long_transfer, greentea_failure_handler), + Case("5-bit frames with 8-bit data, 1 MHz, DMA (long)", test_5bit_8bit_0_1mhz_long_dma_transfer, greentea_failure_handler), + Case("5-bit frames with 16-bit data, 1 MHz (long)", test_5bit_16bit_0_1mhz_long_transfer, greentea_failure_handler), + Case("5-bit frames with 16-bit data, 1 MHz, DMA (long)", test_5bit_16bit_0_1mhz_long_dma_transfer, greentea_failure_handler), + Case("8-bit frames with 8-bit data, 1 MHz (long)", test_8bit_8bit_0_1mhz_long_transfer, greentea_failure_handler), + Case("8-bit frames with 8-bit data, 1 MHz, DMA (long)", test_8bit_8bit_0_1mhz_long_dma_transfer, greentea_failure_handler), + Case("8-bit frames with 16-bit data, 1 MHz (long)", test_8bit_16bit_0_1mhz_long_transfer, greentea_failure_handler), + Case("8-bit frames with 16-bit data, 1 MHz, DMA (long)", test_8bit_16bit_0_1mhz_long_dma_transfer, greentea_failure_handler), + Case("9-bit frames with 16-bit data, 1 MHz (long)", test_9bit_16bit_0_1mhz_long_transfer, greentea_failure_handler), + Case("9-bit frames with 16-bit data, 1 MHz, DMA (long)", test_9bit_16bit_0_1mhz_long_dma_transfer, greentea_failure_handler), + Case("16-bit frames with 16-bit data, 1 MHz (long)", test_16bit_16bit_0_1mhz_long_transfer, greentea_failure_handler), + Case("16-bit frames with 16-bit data, 1 MHz, DMA (long)", test_16bit_16bit_0_1mhz_long_dma_transfer, greentea_failure_handler), +#else + Case("Dummy case", test_dummy, greentea_failure_handler) +#endif +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(25, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() { +#if TEST + cs = 1; + cb.attach(callbackFunction); + init_timer(); +#endif + Harness::run(specification); +} \ No newline at end of file diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/dma_api.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/dma_api.c index 9a710bc989..062ab66b70 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/dma_api.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/dma_api.c @@ -25,7 +25,6 @@ #include "dma_api_HAL.h" #include "em_device.h" #include "em_cmu.h" -#include "em_int.h" #ifdef DMA_PRESENT #include "em_dma.h" @@ -198,7 +197,6 @@ bool LDMAx_ChannelEnabled( int ch ) EFM_ASSERT(ch < DMA_CHAN_COUNT); uint32_t chMask = 1 << ch; return (bool)(LDMA->CHEN & chMask); - INT_Disable(); } #endif /* LDMA_PRESENT */ diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/gpio_irq_api.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/gpio_irq_api.c index c189c1b102..1e106f478c 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/gpio_irq_api.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/gpio_irq_api.c @@ -96,8 +96,10 @@ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32 // Init pins gpio_irq_preinit(obj, pin); // Initialize GPIO interrupt dispatcher + NVIC_SetVector(GPIO_ODD_IRQn, (uint32_t)GPIO_ODD_IRQHandler); NVIC_ClearPendingIRQ(GPIO_ODD_IRQn); NVIC_EnableIRQ(GPIO_ODD_IRQn); + NVIC_SetVector(GPIO_EVEN_IRQn, (uint32_t)GPIO_EVEN_IRQHandler); NVIC_ClearPendingIRQ(GPIO_EVEN_IRQn); NVIC_EnableIRQ(GPIO_EVEN_IRQn); diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c index 97b910ea68..adac923280 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c @@ -28,7 +28,7 @@ #include "rtc_api_HAL.h" #include "lp_ticker_api.h" -#include "em_int.h" +#include "critical.h" #if (defined RTCC_COUNT) && (RTCC_COUNT > 0) #include "em_rtcc.h" #endif @@ -38,21 +38,21 @@ static int rtc_reserved = 0; void lp_ticker_init() { if(!rtc_reserved) { - INT_Disable(); + core_util_critical_section_enter(); rtc_init_real(RTC_INIT_LPTIMER); rtc_set_comp0_handler((uint32_t)lp_ticker_irq_handler); rtc_reserved = 1; - INT_Enable(); + core_util_critical_section_exit(); } } void lp_ticker_free() { if(rtc_reserved) { - INT_Disable(); + core_util_critical_section_enter(); rtc_free_real(RTC_INIT_LPTIMER); rtc_reserved = 0; - INT_Enable(); + core_util_critical_section_exit(); } } diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/pwmout_api.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/pwmout_api.c index 67c1b24dad..e3c713a09a 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/pwmout_api.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/pwmout_api.c @@ -37,7 +37,7 @@ #include "em_gpio.h" #include "em_timer.h" -static int pwm_prescaler_div; +static uint32_t pwm_prescaler_div; float pwmout_calculate_duty(uint32_t width_cycles, uint32_t period_cycles); void pwmout_write_channel(uint32_t channel, float value); @@ -132,7 +132,7 @@ bool pwmout_all_inactive(void) { return true; } #else - if(PWM_TIMER->ROUTE == PWM_ROUTE) { + if(PWM_TIMER->ROUTE & (TIMER_ROUTE_CC0PEN | TIMER_ROUTE_CC1PEN | TIMER_ROUTE_CC2PEN)) { return true; } #endif @@ -211,7 +211,11 @@ void pwmout_init(pwmout_t *obj, PinName pin) #else // On P1, the route location is statically defined for the entire timer. PWM_TIMER->ROUTE &= ~_TIMER_ROUTE_LOCATION_MASK; - PWM_TIMER->ROUTE |= PWM_ROUTE; +if(pwmout_all_inactive()) { + PWM_TIMER->ROUTE |= pinmap_find_function(pin,PinMap_PWM) << _TIMER_ROUTE_LOCATION_SHIFT; + } else { + MBED_ASSERT((pinmap_find_function(pin,PinMap_PWM) << _TIMER_ROUTE_LOCATION_SHIFT) == (PWM_TIMER->ROUTE & _TIMER_ROUTE_LOCATION_MASK)); + } #endif // Set default 20ms frequency and 0ms pulse width @@ -281,7 +285,7 @@ void pwmout_period(pwmout_t *obj, float seconds) // This gives us max resolution for a given period //The value of the top register if prescaler is set to 0 - int cycles = REFERENCE_FREQUENCY * seconds; + uint32_t cycles = (uint32_t)REFERENCE_FREQUENCY * seconds; pwm_prescaler_div = 0; //The top register is only 16 bits, so we keep dividing till we are below 0xFFFF diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api.c index fd157202ec..1b8919c803 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api.c @@ -71,7 +71,8 @@ void RTC_IRQHandler(void) uint32_t rtc_get_32bit(void) { - return (RTC_CounterGet() + (time_extend << RTC_NUM_BITS)); + uint32_t pending = (RTC_IntGet() & RTC_IF_OF) ? 1 : 0; + return (RTC_CounterGet() + ((time_extend + pending) << RTC_NUM_BITS)); } uint64_t rtc_get_full(void) @@ -104,8 +105,8 @@ void rtc_init_real(uint32_t flags) /* Enable Interrupt from RTC */ RTC_IntEnable(RTC_IEN_OF); - NVIC_EnableIRQ(RTC_IRQn); NVIC_SetVector(RTC_IRQn, (uint32_t)RTC_IRQHandler); + NVIC_EnableIRQ(RTC_IRQn); /* Initialize */ RTC_Init(&init); @@ -198,8 +199,8 @@ void rtc_init_real(uint32_t flags) /* Enable Interrupt from RTC */ RTCC_IntEnable(RTCC_IEN_OF); - NVIC_EnableIRQ(RTCC_IRQn); NVIC_SetVector(RTCC_IRQn, (uint32_t)RTCC_IRQHandler); + NVIC_EnableIRQ(RTCC_IRQn); /* Initialize */ RTCC_Init(&init); diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/sleep.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/sleep.c index a466ba619b..abf5ec45f2 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/sleep.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/sleep.c @@ -28,7 +28,7 @@ #include "sleepmodes.h" #include "cmsis.h" #include "em_emu.h" -#include "em_int.h" +#include "critical.h" uint32_t sleep_block_counter[NUM_SLEEP_MODES] = {0}; @@ -80,9 +80,9 @@ void deepsleep(void) */ void blockSleepMode(sleepstate_enum minimumMode) { - INT_Disable(); + core_util_critical_section_enter(); sleep_block_counter[minimumMode]++; - INT_Enable(); + core_util_critical_section_exit(); } /** Unblock the microcontroller from sleeping below a certain mode @@ -94,11 +94,11 @@ void blockSleepMode(sleepstate_enum minimumMode) */ void unblockSleepMode(sleepstate_enum minimumMode) { - INT_Disable(); + core_util_critical_section_enter(); if(sleep_block_counter[minimumMode] > 0) { sleep_block_counter[minimumMode]--; } - INT_Enable(); + core_util_critical_section_exit(); } #endif diff --git a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/spi_api.c b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/spi_api.c index 92b3789e7f..2b9c68ca0d 100644 --- a/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/spi_api.c +++ b/hal/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/spi_api.c @@ -471,91 +471,60 @@ void spi_buffer_set(spi_t *obj, const void *tx, uint32_t tx_length, void *rx, ui static void spi_buffer_tx_write(spi_t *obj) { - uint32_t data; - if(obj->spi.bits >= 9) { - // write double frame - if (obj->tx_buff.buffer == (void *)0) { - data = SPI_FILL_WORD; - } else { - uint16_t *tx = (uint16_t *)(obj->tx_buff.buffer); - data = tx[obj->tx_buff.pos] & 0xFFFF; - } - obj->tx_buff.pos += 1; - if(obj->spi.bits == 9){ - obj->spi.spi->TXDATAX = data; - }else { - obj->spi.spi->TXDOUBLE = data; - } + uint32_t data = 0; - } else if (obj->tx_buff.pos < obj->tx_buff.length) { - // write single frame - if (obj->tx_buff.buffer == (void *)0) { - data = SPI_FILL_WORD & 0xFF; - } else { - uint8_t *tx = (uint8_t *)(obj->tx_buff.buffer); - data = tx[obj->tx_buff.pos] & 0xFF; - } - obj->tx_buff.pos++; + // Interpret buffer according to declared width + if (!obj->tx_buff.buffer) { + data = SPI_FILL_WORD; + } else if (obj->tx_buff.width == 32) { + uint32_t * tx = (uint32_t *)obj->tx_buff.buffer; + data = tx[obj->tx_buff.pos]; + } else if (obj->tx_buff.width == 16) { + uint16_t * tx = (uint16_t *)obj->tx_buff.buffer; + data = tx[obj->tx_buff.pos]; + } else { + uint8_t * tx = (uint8_t *)obj->tx_buff.buffer; + data = tx[obj->tx_buff.pos]; + } + obj->tx_buff.pos++; + // Send buffer + if (obj->spi.bits > 9) { + obj->spi.spi->TXDOUBLE = data; + } else if (obj->spi.bits == 9) { + obj->spi.spi->TXDATAX = data; + } else { obj->spi.spi->TXDATA = data; } } static void spi_buffer_rx_read(spi_t *obj) { - if (obj->spi.bits % 9 != 0) { - if ((obj->spi.spi->STATUS & USART_STATUS_RXFULL) && (obj->rx_buff.pos < obj->rx_buff.length - 1) && ((obj->rx_buff.pos % 2) == 0)) { - // Read max 16 bits from buffer to speed things up - uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLE; //read the data but store only if rx is set and not full - if (obj->rx_buff.buffer) { - uint16_t *rx = (uint16_t *)(obj->rx_buff.buffer); - rx[obj->rx_buff.pos / 2] = data & 0xFFFF; - obj->rx_buff.pos += 2; - } - } else if ((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length)) { - // Read 8 bits from buffer - while((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length)) { - uint32_t data = (uint32_t)obj->spi.spi->RXDATA; //read the data but store only if rx is set and not full - if (obj->rx_buff.buffer) { - uint8_t *rx = (uint8_t *)(obj->rx_buff.buffer); - rx[obj->rx_buff.pos] = data & 0xFF; - obj->rx_buff.pos++; - } - } - } else if (obj->spi.spi->STATUS & USART_STATUS_RXFULL) { - // Read from the buffer to lower the interrupt flag - volatile uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLE; - } else if (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) { - // Read from the buffer to lower the interrupt flag - volatile uint32_t data = (uint32_t)obj->spi.spi->RXDATA; + uint32_t data; + + if (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) { + // Read from the FIFO + if (obj->spi.bits > 9) { + data = obj->spi.spi->RXDOUBLE; + } else if (obj->spi.bits == 9) { + data = obj->spi.spi->RXDATAX; + } else { + data = obj->spi.spi->RXDATA; } - } else { - // Data bits is multiple of 9, so use the extended registers - if ((obj->spi.spi->STATUS & USART_STATUS_RXFULL) && (obj->rx_buff.pos < obj->rx_buff.length - 3) && ((obj->rx_buff.pos % 4) == 0)) { - // Read max 18 bits from buffer to speed things up - uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLEX; //read the data but store only if rx is set and will not overflow - if (obj->rx_buff.buffer) { - uint16_t *rx = (uint16_t *)(obj->rx_buff.buffer); - rx[obj->rx_buff.pos / 2] = data & 0x000001FF; - rx[(obj->rx_buff.pos / 2) + 1] = (data & 0x01FF0000) >> 16; - obj->rx_buff.pos += 4; + + // If there is room in the buffer, store the data + if (obj->rx_buff.buffer && obj->rx_buff.pos < obj->rx_buff.length) { + if (obj->rx_buff.width == 32) { + uint32_t * rx = (uint32_t *)(obj->rx_buff.buffer); + rx[obj->rx_buff.pos] = data; + } else if (obj->rx_buff.width == 16) { + uint16_t * rx = (uint16_t *)(obj->rx_buff.buffer); + rx[obj->rx_buff.pos] = data; + } else { + uint8_t * rx = (uint8_t *)(obj->rx_buff.buffer); + rx[obj->rx_buff.pos] = data; } - } else if ((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length - 1)) { - // Read 9 bits from buffer - while((obj->spi.spi->STATUS & (USART_STATUS_RXDATAV | USART_STATUS_RXFULL)) && (obj->rx_buff.pos < obj->rx_buff.length - 1)) { - uint32_t data = (uint32_t)obj->spi.spi->RXDATAX; //read the data but store only if rx is set and not full - if (obj->rx_buff.buffer) { - uint16_t *rx = (uint16_t *)(obj->rx_buff.buffer); - rx[obj->rx_buff.pos / 2] = data & 0x01FF; - obj->rx_buff.pos += 2; - } - } - } else if (obj->spi.spi->STATUS & USART_STATUS_RXFULL) { - // Read from the buffer to lower the interrupt flag - volatile uint32_t data = (uint32_t)obj->spi.spi->RXDOUBLEX; - } else if (obj->spi.spi->STATUS & USART_STATUS_RXDATAV) { - // Read from the buffer to lower the interrupt flag - volatile uint32_t data = (uint32_t)obj->spi.spi->RXDATAX; + obj->rx_buff.pos++; } } } @@ -813,58 +782,6 @@ static void spi_activate_dma(spi_t *obj, void* rxdata, const void* txdata, int t { LDMA_PeripheralSignal_t dma_periph; - if( txdata ) { - volatile void *target_addr; - - /* Select TX target address. 9 bit frame length requires to use extended register. - 10 bit and larger frame requires to use TXDOUBLE register. */ - switch((int)obj->spi.spi) { - case USART_0: - dma_periph = ldmaPeripheralSignal_USART0_TXBL; - if(obj->spi.bits <= 8){ - target_addr = &USART0->TXDATA; - }else if(obj->spi.bits == 9){ - target_addr = &USART0->TXDATAX; - }else{ - target_addr = &USART0->TXDOUBLE; - } - break; - case USART_1: - dma_periph = ldmaPeripheralSignal_USART1_TXBL; - if(obj->spi.bits <= 8){ - target_addr = &USART1->TXDATA; - }else if(obj->spi.bits == 9){ - target_addr = &USART1->TXDATAX; - }else{ - target_addr = &USART1->TXDOUBLE; - } - break; - default: - EFM_ASSERT(0); - while(1); - break; - } - - /* Check the transmit lenght, and split long transfers to smaller ones*/ - int max_length = 1024; -#ifdef _LDMA_CH_CTRL_XFERCNT_MASK - max_length = (_LDMA_CH_CTRL_XFERCNT_MASK>>_LDMA_CH_CTRL_XFERCNT_SHIFT)+1; -#endif - if(tx_length>max_length){ - tx_length = max_length; - } - - /* Save amount of TX done by DMA */ - obj->tx_buff.pos += tx_length; - - LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph); - LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_M2P_BYTE(txdata, target_addr, tx_length); - if(obj->spi.bits >= 9){ - desc.xfer.size = ldmaCtrlSizeHalf; - } - LDMAx_StartTransfer(obj->spi.dmaOptionsTX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete,obj->spi.dmaOptionsRX.dmaCallback.userPtr); - - } if(rxdata) { volatile const void *source_addr; /* Select RX source address. 9 bit frame length requires to use extended register. @@ -872,23 +789,9 @@ static void spi_activate_dma(spi_t *obj, void* rxdata, const void* txdata, int t switch((int)obj->spi.spi) { case USART_0: dma_periph = ldmaPeripheralSignal_USART0_RXDATAV; - if(obj->spi.bits <= 8){ - source_addr = &USART0->RXDATA; - }else if(obj->spi.bits == 9){ - source_addr = &USART0->RXDATAX; - }else{ - source_addr = &USART0->RXDOUBLE; - } break; case USART_1: dma_periph = ldmaPeripheralSignal_USART1_RXDATAV; - if(obj->spi.bits <= 8){ - source_addr = &USART1->RXDATA; - }else if(obj->spi.bits == 9){ - source_addr = &USART1->RXDATAX; - }else{ - source_addr = &USART1->RXDOUBLE; - } break; default: EFM_ASSERT(0); @@ -896,13 +799,104 @@ static void spi_activate_dma(spi_t *obj, void* rxdata, const void* txdata, int t break; } + if (obj->spi.bits <= 8) { + source_addr = &obj->spi.spi->RXDATA; + } else if (obj->spi.bits == 9) { + source_addr = &obj->spi.spi->RXDATAX; + } else { + source_addr = &obj->spi.spi->RXDOUBLE; + } + LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph); LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_P2M_BYTE(source_addr, rxdata, rx_length); + if(obj->spi.bits >= 9){ desc.xfer.size = ldmaCtrlSizeHalf; } + + if (obj->tx_buff.width == 32) { + if (obj->spi.bits >= 9) { + desc.xfer.dstInc = ldmaCtrlDstIncTwo; + } else { + desc.xfer.dstInc = ldmaCtrlDstIncFour; + } + } else if (obj->tx_buff.width == 16) { + if (obj->spi.bits >= 9) { + desc.xfer.dstInc = ldmaCtrlDstIncOne; + } else { + desc.xfer.dstInc = ldmaCtrlDstIncTwo; + } + } else { + desc.xfer.dstInc = ldmaCtrlDstIncOne; + } + LDMAx_StartTransfer(obj->spi.dmaOptionsRX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete,obj->spi.dmaOptionsRX.dmaCallback.userPtr); } + + volatile void *target_addr; + + /* Select TX target address. 9 bit frame length requires to use extended register. + 10 bit and larger frame requires to use TXDOUBLE register. */ + switch ((int)obj->spi.spi) { + case USART_0: + dma_periph = ldmaPeripheralSignal_USART0_TXBL; + break; + case USART_1: + dma_periph = ldmaPeripheralSignal_USART1_TXBL; + break; + default: + EFM_ASSERT(0); + while(1); + break; + } + + if (obj->spi.bits <= 8) { + target_addr = &obj->spi.spi->TXDATA; + } else if (obj->spi.bits == 9) { + target_addr = &obj->spi.spi->TXDATAX; + } else { + target_addr = &obj->spi.spi->TXDOUBLE; + } + + /* Check the transmit length, and split long transfers to smaller ones */ + int max_length = 1024; +#ifdef _LDMA_CH_CTRL_XFERCNT_MASK + max_length = (_LDMA_CH_CTRL_XFERCNT_MASK>>_LDMA_CH_CTRL_XFERCNT_SHIFT)+1; +#endif + if (tx_length > max_length) { + tx_length = max_length; + } + + /* Save amount of TX done by DMA */ + obj->tx_buff.pos += tx_length; + + LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph); + LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_M2P_BYTE((txdata ? txdata : &fill_word), target_addr, tx_length); + + if (obj->spi.bits >= 9) { + desc.xfer.size = ldmaCtrlSizeHalf; + } + + if (!txdata) { + desc.xfer.srcInc = ldmaCtrlSrcIncNone; + } else if (obj->tx_buff.width == 32) { + if (obj->spi.bits >= 9) { + desc.xfer.srcInc = ldmaCtrlSrcIncTwo; + } else { + desc.xfer.srcInc = ldmaCtrlSrcIncFour; + } + } else if (obj->tx_buff.width == 16) { + if (obj->spi.bits >= 9) { + desc.xfer.srcInc = ldmaCtrlSrcIncOne; + } else { + desc.xfer.srcInc = ldmaCtrlSrcIncTwo; + } + } else { + desc.xfer.srcInc = ldmaCtrlSrcIncOne; + } + + // Kick off DMA TX + LDMAx_StartTransfer(obj->spi.dmaOptionsTX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete,obj->spi.dmaOptionsTX.dmaCallback.userPtr); } #else @@ -922,90 +916,90 @@ static void spi_activate_dma(spi_t *obj, void* rxdata, const void* txdata, int t DMA_CfgDescr_TypeDef rxDescrCfg; DMA_CfgDescr_TypeDef txDescrCfg; - /* Split up transfers if the tx length is larger than what the DMA supports. */ + /* Split up transfers if the length is larger than what the DMA supports. */ const int DMA_MAX_TRANSFER = (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT); if (tx_length > DMA_MAX_TRANSFER) { - uint32_t max_length = DMA_MAX_TRANSFER; - - /* Make sure only an even amount of bytes are transferred - if the width is larger than 8 bits. */ - if (obj->spi.bits > 8) { - max_length = DMA_MAX_TRANSFER - (DMA_MAX_TRANSFER & 0x01); - } - - /* Update length for current transfer. */ - tx_length = max_length; + tx_length = DMA_MAX_TRANSFER; + } + if (rx_length > DMA_MAX_TRANSFER) { + rx_length = DMA_MAX_TRANSFER; } /* Save amount of TX done by DMA */ obj->tx_buff.pos += tx_length; + obj->rx_buff.pos += rx_length; - if(obj->spi.bits != 9) { - /* Only activate RX DMA if a receive buffer is specified */ - if (rxdata != NULL) { - // Setting up channel descriptor - rxDescrCfg.dstInc = dmaDataInc1; - rxDescrCfg.srcInc = dmaDataIncNone; - rxDescrCfg.size = dmaDataSize1; - rxDescrCfg.arbRate = dmaArbitrate1; - rxDescrCfg.hprot = 0; - DMA_CfgDescr(obj->spi.dmaOptionsRX.dmaChannel, true, &rxDescrCfg); - - /* Activate RX channel */ - DMA_ActivateBasic(obj->spi.dmaOptionsRX.dmaChannel, true, false, rxdata, (void *)&(obj->spi.spi->RXDATA), - rx_length - 1); - } - - // buffer with all FFs. - /* Setting up channel descriptor */ - txDescrCfg.dstInc = dmaDataIncNone; - txDescrCfg.srcInc = (txdata == 0 ? dmaDataIncNone : (obj->spi.bits <= 8 ? dmaDataInc1 : dmaDataInc2)); //Do not increment source pointer when there is no transmit buffer - txDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size > 9, we can use TXDOUBLE to save bandwidth - txDescrCfg.arbRate = dmaArbitrate1; - txDescrCfg.hprot = 0; - DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg); - - /* Activate TX channel */ - DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel, - true, - false, - (obj->spi.bits <= 8 ? (void *)&(obj->spi.spi->TXDATA) : (void *)&(obj->spi.spi->TXDOUBLE)), //When frame size > 9, point to TXDOUBLE - (txdata == 0 ? &fill_word : (void *)txdata), // When there is nothing to transmit, point to static fill word - (tx_length - 1)); - } else { - /* Frame size == 9 */ - /* Only activate RX DMA if a receive buffer is specified */ - if (rxdata != NULL) { - // Setting up channel descriptor + /* Only activate RX DMA if a receive buffer is specified */ + if (rxdata != NULL) { + // Setting up channel descriptor + if (obj->rx_buff.width == 32) { + rxDescrCfg.dstInc = dmaDataInc4; + } else if (obj->rx_buff.width == 16) { rxDescrCfg.dstInc = dmaDataInc2; - rxDescrCfg.srcInc = dmaDataIncNone; - rxDescrCfg.size = dmaDataSize2; - rxDescrCfg.arbRate = dmaArbitrate1; - rxDescrCfg.hprot = 0; - DMA_CfgDescr(obj->spi.dmaOptionsRX.dmaChannel, true, &rxDescrCfg); + } else { + rxDescrCfg.dstInc = dmaDataInc1; + } + rxDescrCfg.srcInc = dmaDataIncNone; + rxDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size >= 9, use RXDOUBLE + rxDescrCfg.arbRate = dmaArbitrate1; + rxDescrCfg.hprot = 0; + DMA_CfgDescr(obj->spi.dmaOptionsRX.dmaChannel, true, &rxDescrCfg); - /* Activate RX channel */ - DMA_ActivateBasic(obj->spi.dmaOptionsRX.dmaChannel, true, false, rxdata, (void *)&(obj->spi.spi->RXDATAX), - (rx_length / 2) - 1); + void * rx_reg; + if (obj->spi.bits > 9) { + rx_reg = (void *)&obj->spi.spi->RXDOUBLE; + } else if (obj->spi.bits == 9) { + rx_reg = (void *)&obj->spi.spi->RXDATAX; + } else { + rx_reg = (void *)&obj->spi.spi->RXDATA; } - /* Setting up channel descriptor */ - txDescrCfg.dstInc = dmaDataIncNone; - txDescrCfg.srcInc = (txdata == 0 ? dmaDataIncNone : dmaDataInc2); //Do not increment source pointer when there is no transmit buffer - txDescrCfg.size = dmaDataSize2; //When frame size > 9, we can use TXDOUBLE to save bandwidth - txDescrCfg.arbRate = dmaArbitrate1; - txDescrCfg.hprot = 0; - DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg); - - /* Activate TX channel */ - DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel, - true, - false, - (void *)&(obj->spi.spi->TXDATAX), //When frame size > 9, point to TXDOUBLE - (txdata == 0 ? &fill_word : (void *)txdata), // When there is nothing to transmit, point to static fill word - (tx_length - 1)); + /* Activate RX channel */ + DMA_ActivateBasic(obj->spi.dmaOptionsRX.dmaChannel, + true, + false, + rxdata, + rx_reg, + rx_length - 1); } + + // buffer with all FFs. + /* Setting up channel descriptor */ + txDescrCfg.dstInc = dmaDataIncNone; + if (txdata == 0) { + // Don't increment source when there is no transmit buffer + txDescrCfg.srcInc = dmaDataIncNone; + } else { + if (obj->tx_buff.width == 32) { + txDescrCfg.srcInc = dmaDataInc4; + } else if (obj->tx_buff.width == 16) { + txDescrCfg.srcInc = dmaDataInc2; + } else { + txDescrCfg.srcInc = dmaDataInc1; + } + } + txDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size >= 9, use TXDOUBLE + txDescrCfg.arbRate = dmaArbitrate1; + txDescrCfg.hprot = 0; + DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg); + + void * tx_reg; + if (obj->spi.bits > 9) { + tx_reg = (void *)&obj->spi.spi->TXDOUBLE; + } else if (obj->spi.bits == 9) { + tx_reg = (void *)&obj->spi.spi->TXDATAX; + } else { + tx_reg = (void *)&obj->spi.spi->TXDATA; + } + + /* Activate TX channel */ + DMA_ActivateBasic(obj->spi.dmaOptionsTX.dmaChannel, + true, + false, + tx_reg, + (txdata == 0 ? &fill_word : (void *)txdata), // When there is nothing to transmit, point to static fill word + (tx_length - 1)); } #endif //LDMA_PRESENT /******************************************************************** @@ -1191,67 +1185,84 @@ uint32_t spi_irq_handler_asynch(spi_t* obj) /* If there is still data in the TX buffer, setup a new transfer. */ if (obj->tx_buff.pos < obj->tx_buff.length) { + /* If there is still a TX transfer ongoing, let it finish + * before (if necessary) kicking off a new transfer */ + if (DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel)) { + return 0; + } /* Find position and remaining length without modifying tx_buff. */ - void* tx_pointer = (char*)obj->tx_buff.buffer + obj->tx_buff.pos; + void * tx_pointer; + if (obj->tx_buff.width == 32) { + tx_pointer = ((uint32_t *)obj->tx_buff.buffer) + obj->tx_buff.pos; + } else if (obj->tx_buff.width == 16) { + tx_pointer = ((uint16_t *)obj->tx_buff.buffer) + obj->tx_buff.pos; + } else { + tx_pointer = ((uint8_t *)obj->tx_buff.buffer) + obj->tx_buff.pos; + } uint32_t tx_length = obj->tx_buff.length - obj->tx_buff.pos; + /* Refresh RX transfer too if it exists */ + void * rx_pointer = NULL; + if (obj->rx_buff.pos < obj->rx_buff.length) { + if (obj->rx_buff.width == 32) { + rx_pointer = ((uint32_t *)obj->rx_buff.buffer) + obj->rx_buff.pos; + } else if (obj->rx_buff.width == 16) { + rx_pointer = ((uint16_t *)obj->rx_buff.buffer) + obj->rx_buff.pos; + } else { + rx_pointer = ((uint8_t *)obj->rx_buff.buffer) + obj->rx_buff.pos; + } + } + uint32_t rx_length = obj->rx_buff.length - obj->rx_buff.pos; + + /* Wait for the previous transfer to complete. */ + while(!(obj->spi.spi->STATUS & USART_STATUS_TXC)); + /* Begin transfer. Rely on spi_activate_dma to split up the transfer further. */ - spi_activate_dma(obj, obj->rx_buff.buffer, tx_pointer, tx_length, obj->rx_buff.length); + spi_activate_dma(obj, rx_pointer, tx_pointer, tx_length, rx_length); return 0; } - /* If there is an RX transfer ongoing, wait for it to finish */ + /* If an RX transfer is ongoing, continue processing RX data */ if (DMA_ChannelEnabled(obj->spi.dmaOptionsRX.dmaChannel)) { /* Check if we need to kick off TX transfer again to force more incoming data. */ - if (!DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel) && (obj->tx_buff.pos < obj->rx_buff.length)) { + if (!DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel) && (obj->rx_buff.pos < obj->rx_buff.length)) { //Save state of TX transfer amount - int length_diff = obj->rx_buff.length - obj->tx_buff.pos; + int length_diff = obj->rx_buff.length - obj->rx_buff.pos; obj->tx_buff.pos = obj->rx_buff.length; //Kick off a new DMA transfer DMA_CfgDescr_TypeDef txDescrCfg; - if(obj->spi.bits != 9) { - fill_word = SPI_FILL_WORD; - /* Setting up channel descriptor */ - txDescrCfg.dstInc = dmaDataIncNone; - txDescrCfg.srcInc = dmaDataIncNone; //Do not increment source pointer when there is no transmit buffer - txDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size > 9, we can use TXDOUBLE to save bandwidth - txDescrCfg.arbRate = dmaArbitrate1; - txDescrCfg.hprot = 0; - DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg); + fill_word = SPI_FILL_WORD; + /* Setting up channel descriptor */ + txDescrCfg.dstInc = dmaDataIncNone; + txDescrCfg.srcInc = dmaDataIncNone; //Do not increment source pointer when there is no transmit buffer + txDescrCfg.size = (obj->spi.bits <= 8 ? dmaDataSize1 : dmaDataSize2); //When frame size > 9, we can use TXDOUBLE to save bandwidth + txDescrCfg.arbRate = dmaArbitrate1; + txDescrCfg.hprot = 0; + DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg); - /* Activate TX channel */ - DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel, - true, - false, - (obj->spi.bits <= 8 ? (void *)&(obj->spi.spi->TXDATA) : (void *)&(obj->spi.spi->TXDOUBLE)), //When frame size > 9, point to TXDOUBLE - &fill_word, // When there is nothing to transmit, point to static fill word - (obj->spi.bits <= 8 ? length_diff - 1 : (length_diff / 2) - 1)); // When using TXDOUBLE, recalculate transfer length + void * tx_reg; + if (obj->spi.bits > 9) { + tx_reg = (void *)&obj->spi.spi->TXDOUBLE; + } else if (obj->spi.bits == 9) { + tx_reg = (void *)&obj->spi.spi->TXDATAX; } else { - /* Setting up channel descriptor */ - fill_word = SPI_FILL_WORD & 0x1FF; - txDescrCfg.dstInc = dmaDataIncNone; - txDescrCfg.srcInc = dmaDataIncNone; //Do not increment source pointer when there is no transmit buffer - txDescrCfg.size = dmaDataSize2; //When frame size > 9, we can use TXDOUBLE to save bandwidth - txDescrCfg.arbRate = dmaArbitrate1; - txDescrCfg.hprot = 0; - DMA_CfgDescr(obj->spi.dmaOptionsTX.dmaChannel, true, &txDescrCfg); - - DMA_ActivateBasic( obj->spi.dmaOptionsTX.dmaChannel, - true, - false, - (void *)&(obj->spi.spi->TXDATAX), //When frame size > 9, point to TXDOUBLE - &fill_word, // When there is nothing to transmit, point to static fill word - (length_diff / 2) - 1); + tx_reg = (void *)&obj->spi.spi->TXDATA; } - } else return 0; - } - /* If there is still a TX transfer ongoing (tx_length > rx_length), wait for it to finish */ - if (DMA_ChannelEnabled(obj->spi.dmaOptionsTX.dmaChannel)) { - return 0; + /* Activate TX channel */ + DMA_ActivateBasic(obj->spi.dmaOptionsTX.dmaChannel, + true, + false, + tx_reg, //When frame size > 9, point to TXDOUBLE + &fill_word, // When there is nothing to transmit, point to static fill word + length_diff - 1); + } else { + /* Nothing to do */ + return 0; + } } /* Release the dma channels if they were opportunistically allocated */ @@ -1261,7 +1272,7 @@ uint32_t spi_irq_handler_asynch(spi_t* obj) obj->spi.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC; } - /* Wait transmit to complete, before user code is indicated*/ + /* Wait for transmit to complete, before user code is indicated */ while(!(obj->spi.spi->STATUS & USART_STATUS_TXC)); unblockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE); @@ -1282,6 +1293,8 @@ uint32_t spi_irq_handler_asynch(spi_t* obj) /* disable interrupts */ spi_enable_interrupt(obj, (uint32_t)NULL, false); + /* Wait for transmit to complete, before user code is indicated */ + while(!(obj->spi.spi->STATUS & USART_STATUS_TXC)); unblockSleepMode(SPI_LEAST_ACTIVE_SLEEPMODE); /* Return the event back to userland */