mirror of https://github.com/ARMmbed/mbed-os.git
commit
a3a4c78ea0
|
@ -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"],
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue