Merge pull request #2070 from akselsm/efm32-update

[EFM32] Update HAL implementation
pull/2094/head
Martin Kojtal 2016-07-04 10:35:58 +01:00 committed by GitHub
commit a3a4c78ea0
13 changed files with 711 additions and 288 deletions

View File

@ -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"],

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,378 @@
/***************************************************************************//**
* @file main.cpp
*******************************************************************************
* @section License
* <b>(C) Copyright 2016 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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<typename T>
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<typename T>
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);
}

View File

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

View File

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

View File

@ -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();
}
}

View File

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

View File

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

View File

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

View File

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