Merge pull request #3312 from NXPmicro/SPI_ASYNCH_API

K64F: SPI Asynch API implementation
pull/3360/merge
Martin Kojtal 2016-12-09 15:15:54 +01:00 committed by GitHub
commit 163667165e
7 changed files with 509 additions and 23 deletions

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSL_DMA_REQS_H_
#define _FSL_DMA_REQS_H_
#include "fsl_common.h"
/* Array for DSPI DMA TX requests */
#define SPI_DMA_TX_REQUEST_NUMBERS \
{ \
kDmaRequestMux0SPI0Tx, kDmaRequestMux0SPI1, kDmaRequestMux0SPI2 \
}
/* Array for DSPI DMA RX requests */
#define SPI_DMA_RX_REQUEST_NUMBERS \
{ \
kDmaRequestMux0SPI0Rx, kDmaRequestMux0SPI1, kDmaRequestMux0SPI2 \
}
#endif /* _FSL_DMA_REQS_H_ */

View File

@ -162,8 +162,6 @@ status_t DSPI_MasterTransferEDMA(SPI_Type *base, dspi_master_edma_handle_t *hand
handle->txBuffIfNull = ((uint32_t)DSPI_DUMMY_DATA << 8) | DSPI_DUMMY_DATA;
handle->state = kDSPI_Busy;
dspi_command_data_config_t commandStruct;
DSPI_StopTransfer(base);
DSPI_FlushFifo(base, true, true);
@ -222,6 +220,8 @@ status_t DSPI_MasterTransferEDMA(SPI_Type *base, dspi_master_edma_handle_t *hand
return kStatus_InvalidArgument;
}
handle->state = kDSPI_Busy;
DSPI_DisableDMA(base, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_DspiMasterCallback,
@ -706,13 +706,13 @@ static void EDMA_DspiMasterCallback(edma_handle_t *edmaHandle,
DSPI_DisableDMA((dspiEdmaPrivateHandle->base), kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
dspiEdmaPrivateHandle->handle->state = kDSPI_Idle;
if (dspiEdmaPrivateHandle->handle->callback)
{
dspiEdmaPrivateHandle->handle->callback(dspiEdmaPrivateHandle->base, dspiEdmaPrivateHandle->handle,
kStatus_Success, dspiEdmaPrivateHandle->handle->userData);
}
dspiEdmaPrivateHandle->handle->state = kDSPI_Idle;
}
void DSPI_MasterTransferAbortEDMA(SPI_Type *base, dspi_master_edma_handle_t *handle)

View File

@ -25,6 +25,7 @@
#include "mbed_error.h"
#include "fsl_dspi.h"
#include "peripheral_clock_defines.h"
#include "dma_reqs.h"
#include "PeripheralPins.h"
/* Array of SPI peripheral base address. */
@ -42,8 +43,8 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
uint32_t spi_data = pinmap_merge(spi_mosi, spi_miso);
uint32_t spi_cntl = pinmap_merge(spi_sclk, spi_ssel);
obj->instance = pinmap_merge(spi_data, spi_cntl);
MBED_ASSERT((int)obj->instance != NC);
obj->spi.instance = pinmap_merge(spi_data, spi_cntl);
MBED_ASSERT((int)obj->spi.instance != NC);
// pin out the spi pins
pinmap_pinout(mosi, PinMap_SPI_MOSI);
@ -52,11 +53,16 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
if (ssel != NC) {
pinmap_pinout(ssel, PinMap_SPI_SSEL);
}
/* Set the transfer status to idle */
obj->spi.status = kDSPI_Idle;
obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
}
void spi_free(spi_t *obj)
{
DSPI_Deinit(spi_address[obj->instance]);
DSPI_Deinit(spi_address[obj->spi.instance]);
}
void spi_format(spi_t *obj, int bits, int mode, int slave)
@ -64,6 +70,10 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
dspi_master_config_t master_config;
dspi_slave_config_t slave_config;
/* Bits: values between 4 and 16 are valid */
MBED_ASSERT(bits >= 4 && bits <= 16);
obj->spi.bits = bits;
if (slave) {
/* Slave config */
DSPI_SlaveGetDefaultConfig(&slave_config);
@ -72,7 +82,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
slave_config.ctarConfig.cpol = (mode & 0x2) ? kDSPI_ClockPolarityActiveLow : kDSPI_ClockPolarityActiveHigh;
slave_config.ctarConfig.cpha = (mode & 0x1) ? kDSPI_ClockPhaseSecondEdge : kDSPI_ClockPhaseFirstEdge;
DSPI_SlaveInit(spi_address[obj->instance], &slave_config);
DSPI_SlaveInit(spi_address[obj->spi.instance], &slave_config);
} else {
/* Master config */
DSPI_MasterGetDefaultConfig(&master_config);
@ -82,21 +92,21 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
master_config.ctarConfig.direction = kDSPI_MsbFirst;
master_config.ctarConfig.pcsToSckDelayInNanoSec = 0;
DSPI_MasterInit(spi_address[obj->instance], &master_config, CLOCK_GetFreq(spi_clocks[obj->instance]));
DSPI_MasterInit(spi_address[obj->spi.instance], &master_config, CLOCK_GetFreq(spi_clocks[obj->spi.instance]));
}
}
void spi_frequency(spi_t *obj, int hz)
{
uint32_t busClock = CLOCK_GetFreq(spi_clocks[obj->instance]);
DSPI_MasterSetBaudRate(spi_address[obj->instance], kDSPI_Ctar0, (uint32_t)hz, busClock);
uint32_t busClock = CLOCK_GetFreq(spi_clocks[obj->spi.instance]);
DSPI_MasterSetBaudRate(spi_address[obj->spi.instance], kDSPI_Ctar0, (uint32_t)hz, busClock);
//Half clock period delay after SPI transfer
DSPI_MasterSetDelayTimes(spi_address[obj->instance], kDSPI_Ctar0, kDSPI_LastSckToPcs, busClock, 500000000 / hz);
DSPI_MasterSetDelayTimes(spi_address[obj->spi.instance], kDSPI_Ctar0, kDSPI_LastSckToPcs, busClock, 500000000 / hz);
}
static inline int spi_readable(spi_t * obj)
{
return (DSPI_GetStatusFlags(spi_address[obj->instance]) & kDSPI_RxFifoDrainRequestFlag);
return (DSPI_GetStatusFlags(spi_address[obj->spi.instance]) & kDSPI_RxFifoDrainRequestFlag);
}
int spi_master_write(spi_t *obj, int value)
@ -106,14 +116,14 @@ int spi_master_write(spi_t *obj, int value)
DSPI_GetDefaultDataCommandConfig(&command);
command.isEndOfQueue = true;
DSPI_MasterWriteDataBlocking(spi_address[obj->instance], &command, (uint16_t)value);
DSPI_MasterWriteDataBlocking(spi_address[obj->spi.instance], &command, (uint16_t)value);
DSPI_ClearStatusFlags(spi_address[obj->instance], kDSPI_TxFifoFillRequestFlag);
DSPI_ClearStatusFlags(spi_address[obj->spi.instance], kDSPI_TxFifoFillRequestFlag);
// wait rx buffer full
while (!spi_readable(obj));
rx_data = DSPI_ReadData(spi_address[obj->instance]);
DSPI_ClearStatusFlags(spi_address[obj->instance], kDSPI_RxFifoDrainRequestFlag | kDSPI_EndOfQueueFlag);
rx_data = DSPI_ReadData(spi_address[obj->spi.instance]);
DSPI_ClearStatusFlags(spi_address[obj->spi.instance], kDSPI_RxFifoDrainRequestFlag | kDSPI_EndOfQueueFlag);
return rx_data & 0xffff;
}
@ -127,14 +137,297 @@ int spi_slave_read(spi_t *obj)
uint32_t rx_data;
while (!spi_readable(obj));
rx_data = DSPI_ReadData(spi_address[obj->instance]);
DSPI_ClearStatusFlags(spi_address[obj->instance], kDSPI_RxFifoDrainRequestFlag);
rx_data = DSPI_ReadData(spi_address[obj->spi.instance]);
DSPI_ClearStatusFlags(spi_address[obj->spi.instance], kDSPI_RxFifoDrainRequestFlag);
return rx_data & 0xffff;
}
void spi_slave_write(spi_t *obj, int value)
{
DSPI_SlaveWriteDataBlocking(spi_address[obj->instance], (uint32_t)value);
DSPI_SlaveWriteDataBlocking(spi_address[obj->spi.instance], (uint32_t)value);
}
static int32_t spi_master_transfer_asynch(spi_t *obj)
{
dspi_transfer_t masterXfer;
int32_t status;
uint32_t transferSize;
/*Start master transfer*/
masterXfer.txData = obj->tx_buff.buffer;
masterXfer.rxData = obj->rx_buff.buffer;
masterXfer.dataSize = obj->tx_buff.length;
masterXfer.configFlags = kDSPI_MasterCtar0 | kDSPI_MasterPcs0 | kDSPI_MasterPcsContinuous;
/* Busy transferring */
obj->spi.status = kDSPI_Busy;
if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_ALLOCATED ||
obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
status = DSPI_MasterTransferEDMA(spi_address[obj->spi.instance], &obj->spi.spi_dma_master_handle, &masterXfer);
if (status == kStatus_DSPI_OutOfRange) {
if (obj->spi.bits > 8) {
transferSize = 1022;
} else {
transferSize = 511;
}
masterXfer.dataSize = transferSize;
/* Save amount of TX done by DMA */
obj->tx_buff.pos += transferSize;
obj->rx_buff.pos += transferSize;
/* Try again */
status = DSPI_MasterTransferEDMA(spi_address[obj->spi.instance], &obj->spi.spi_dma_master_handle, &masterXfer);
}
} else {
status = DSPI_MasterTransferNonBlocking(spi_address[obj->spi.instance], &obj->spi.spi_master_handle, &masterXfer);
}
return status;
}
static bool spi_allocate_dma(spi_t *obj, uint32_t handler)
{
dma_request_source_t dma_rx_requests[] = SPI_DMA_RX_REQUEST_NUMBERS;
dma_request_source_t dma_tx_requests[] = SPI_DMA_TX_REQUEST_NUMBERS;
edma_config_t userConfig;
/* Allocate the DMA channels */
/* Allocate the RX channel */
obj->spi.spiDmaMasterRx.dmaChannel = dma_channel_allocate(dma_rx_requests[obj->spi.instance]);
if (obj->spi.spiDmaMasterRx.dmaChannel == DMA_ERROR_OUT_OF_CHANNELS) {
return false;
}
/* Check if we have separate DMA requests for TX & RX */
if (dma_tx_requests[obj->spi.instance] != dma_rx_requests[obj->spi.instance]) {
/* Allocate the TX channel with the DMA TX request number set as source */
obj->spi.spiDmaMasterTx.dmaChannel = dma_channel_allocate(dma_tx_requests[obj->spi.instance]);
} else {
/* Allocate the TX channel without setting source */
obj->spi.spiDmaMasterTx.dmaChannel = dma_channel_allocate(kDmaRequestMux0Disable);
}
if (obj->spi.spiDmaMasterTx.dmaChannel == DMA_ERROR_OUT_OF_CHANNELS) {
dma_channel_free(obj->spi.spiDmaMasterRx.dmaChannel);
return false;
}
/* Allocate an intermediary DMA channel */
obj->spi.spiDmaMasterIntermediary.dmaChannel = dma_channel_allocate(kDmaRequestMux0Disable);
if (obj->spi.spiDmaMasterIntermediary.dmaChannel == DMA_ERROR_OUT_OF_CHANNELS) {
dma_channel_free(obj->spi.spiDmaMasterRx.dmaChannel);
dma_channel_free(obj->spi.spiDmaMasterTx.dmaChannel);
return false;
}
/* EDMA init*/
/*
* userConfig.enableRoundRobinArbitration = false;
* userConfig.enableHaltOnError = true;
* userConfig.enableContinuousLinkMode = false;
* userConfig.enableDebugMode = false;
*/
EDMA_GetDefaultConfig(&userConfig);
EDMA_Init(DMA0, &userConfig);
/* Set up dspi master */
memset(&(obj->spi.spiDmaMasterRx.handle), 0, sizeof(obj->spi.spiDmaMasterRx.handle));
memset(&(obj->spi.spiDmaMasterTx.handle), 0, sizeof(obj->spi.spiDmaMasterTx.handle));
memset(&(obj->spi.spiDmaMasterIntermediary.handle), 0, sizeof(obj->spi.spiDmaMasterIntermediary.handle));
EDMA_CreateHandle(&(obj->spi.spiDmaMasterRx.handle), DMA0, obj->spi.spiDmaMasterRx.dmaChannel);
EDMA_CreateHandle(&(obj->spi.spiDmaMasterIntermediary.handle), DMA0,
obj->spi.spiDmaMasterIntermediary.dmaChannel);
EDMA_CreateHandle(&(obj->spi.spiDmaMasterTx.handle), DMA0, obj->spi.spiDmaMasterTx.dmaChannel);
DSPI_MasterTransferCreateHandleEDMA(spi_address[obj->spi.instance], &obj->spi.spi_dma_master_handle, (dspi_master_edma_transfer_callback_t)handler,
NULL, &obj->spi.spiDmaMasterRx.handle,
&obj->spi.spiDmaMasterIntermediary.handle,
&obj->spi.spiDmaMasterTx.handle);
return true;
}
static void spi_enable_dma(spi_t *obj, uint32_t handler, DMAUsage state)
{
dma_init();
if (state == DMA_USAGE_ALWAYS && obj->spi.spiDmaMasterRx.dmaUsageState != DMA_USAGE_ALLOCATED) {
/* Try to allocate channels */
if (spi_allocate_dma(obj, handler)) {
obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_ALLOCATED;
} else {
obj->spi.spiDmaMasterRx.dmaUsageState = state;
}
} else if (state == DMA_USAGE_OPPORTUNISTIC) {
if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_ALLOCATED) {
/* Channels have already been allocated previously by an ALWAYS state, so after this transfer, we will release them */
obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
} else {
/* Try to allocate channels */
if (spi_allocate_dma(obj, handler)) {
obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
} else {
obj->spi.spiDmaMasterRx.dmaUsageState = state;
}
}
} else if (state == DMA_USAGE_NEVER) {
/* If channels are allocated, get rid of them */
if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_ALLOCATED) {
dma_channel_free(obj->spi.spiDmaMasterRx.dmaChannel);
dma_channel_free(obj->spi.spiDmaMasterTx.dmaChannel);
dma_channel_free(obj->spi.spiDmaMasterIntermediary.dmaChannel);
}
obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_NEVER;
}
}
static void spi_buffer_set(spi_t *obj, const void *tx, uint32_t tx_length, void *rx, uint32_t rx_length, uint8_t bit_width)
{
obj->tx_buff.buffer = (void *)tx;
obj->rx_buff.buffer = rx;
obj->tx_buff.length = tx_length;
obj->rx_buff.length = rx_length;
obj->tx_buff.pos = 0;
obj->rx_buff.pos = 0;
obj->tx_buff.width = bit_width;
obj->rx_buff.width = bit_width;
}
void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint)
{
if(spi_active(obj)) {
return;
}
/* check corner case */
if(tx_length == 0) {
tx_length = rx_length;
tx = (void*) 0;
}
/* First, set the buffer */
spi_buffer_set(obj, tx, tx_length, rx, rx_length, bit_width);
/* If using DMA, allocate channels only if they have not already been allocated */
if (hint != DMA_USAGE_NEVER) {
/* User requested to transfer using DMA */
spi_enable_dma(obj, handler, hint);
/* Check if DMA setup was successful */
if (obj->spi.spiDmaMasterRx.dmaUsageState != DMA_USAGE_ALLOCATED && obj->spi.spiDmaMasterRx.dmaUsageState != DMA_USAGE_TEMPORARY_ALLOCATED) {
/* Set up an interrupt transfer as DMA is unavailable */
DSPI_MasterTransferCreateHandle(spi_address[obj->spi.instance], &obj->spi.spi_master_handle, (dspi_master_transfer_callback_t)handler, NULL);
}
} else {
/* User requested to transfer using interrupts */
/* Disable the DMA */
spi_enable_dma(obj, handler, hint);
/* Set up the interrupt transfer */
DSPI_MasterTransferCreateHandle(spi_address[obj->spi.instance], &obj->spi.spi_master_handle, (dspi_master_transfer_callback_t)handler, NULL);
}
/* Start the transfer */
if (spi_master_transfer_asynch(obj) != kStatus_Success) {
obj->spi.status = kDSPI_Idle;
}
}
uint32_t spi_irq_handler_asynch(spi_t *obj)
{
uint32_t transferSize;
dspi_transfer_t masterXfer;
/* Determine whether the current scenario is DMA or IRQ, and act accordingly */
if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_ALLOCATED || obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
/* DMA implementation */
/* Check If there is still data in the TX buffer */
if (obj->tx_buff.pos < obj->tx_buff.length) {
/* Setup a new DMA transfer. */
if (obj->spi.bits > 8) {
transferSize = 1022;
} else {
transferSize = 511;
}
/* Update the TX buffer only if it is used */
if (obj->tx_buff.buffer) {
masterXfer.txData = ((uint8_t *)obj->tx_buff.buffer) + obj->tx_buff.pos;
} else {
masterXfer.txData = 0;
}
/* Update the RX buffer only if it is used */
if (obj->rx_buff.buffer) {
masterXfer.rxData = ((uint8_t *)obj->rx_buff.buffer) + obj->rx_buff.pos;
} else {
masterXfer.rxData = 0;
}
/* Check how much data is remaining in the buffer */
if ((obj->tx_buff.length - obj->tx_buff.pos) > transferSize) {
masterXfer.dataSize = transferSize;
} else {
masterXfer.dataSize = obj->tx_buff.length - obj->tx_buff.pos;
}
masterXfer.configFlags = kDSPI_MasterCtar0 | kDSPI_MasterPcs0 | kDSPI_MasterPcsContinuous;
/* Save amount of TX done by DMA */
obj->tx_buff.pos += masterXfer.dataSize;
obj->rx_buff.pos += masterXfer.dataSize;
/* Start another transfer */
DSPI_MasterTransferEDMA(spi_address[obj->spi.instance], &obj->spi.spi_dma_master_handle, &masterXfer);
return 0;
} else {
/* Release the dma channels if they were opportunistically allocated */
if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
dma_channel_free(obj->spi.spiDmaMasterRx.dmaChannel);
dma_channel_free(obj->spi.spiDmaMasterTx.dmaChannel);
dma_channel_free(obj->spi.spiDmaMasterIntermediary.dmaChannel);
obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
}
obj->spi.status = kDSPI_Idle;
return SPI_EVENT_COMPLETE;
}
} else {
/* Interrupt implementation */
obj->spi.status = kDSPI_Idle;
return SPI_EVENT_COMPLETE;
}
}
void spi_abort_asynch(spi_t *obj)
{
// If we're not currently transferring, then there's nothing to do here
if(spi_active(obj) == 0) {
return;
}
// Determine whether we're running DMA or interrupt
if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_ALLOCATED ||
obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
DSPI_MasterTransferAbortEDMA(spi_address[obj->spi.instance], &obj->spi.spi_dma_master_handle);
/* Release the dma channels if they were opportunistically allocated */
if (obj->spi.spiDmaMasterRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
dma_channel_free(obj->spi.spiDmaMasterRx.dmaChannel);
dma_channel_free(obj->spi.spiDmaMasterTx.dmaChannel);
dma_channel_free(obj->spi.spiDmaMasterIntermediary.dmaChannel);
obj->spi.spiDmaMasterRx.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
}
} else {
/* Interrupt implementation */
DSPI_MasterTransferAbort(spi_address[obj->spi.instance], &obj->spi.spi_master_handle);
}
obj->spi.status = kDSPI_Idle;
}
uint8_t spi_active(spi_t *obj)
{
return obj->spi.status;
}
#endif

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fsl_dmamux.h"
#include "dma_api.h"
uint32_t channels = 0; // Bit vector of taken channels
void dma_init(void)
{
/* DMA MUX init */
DMAMUX_Init(DMAMUX0);
}
int dma_channel_allocate(uint32_t capabilities)
{
int i;
for (i = 0; i < FSL_FEATURE_DMAMUX_DMAMUX_CHANNELS; i++) {
if ((channels & (1 << i)) == 0) {
// Channel available
channels |= 1 << i;
/* Check if we need to set the source and enable the MUX for this channel */
if (capabilities != kDmaRequestMux0Disable) {
DMAMUX_SetSource(DMAMUX0, i, capabilities);
DMAMUX_EnableChannel(DMAMUX0, i);
}
return i;
}
}
// Couldn't find a channel.
return DMA_ERROR_OUT_OF_CHANNELS;
}
int dma_channel_free(int channelid)
{
channels &= ~(1 << channelid);
DMAMUX_DisableChannel(DMAMUX0, channelid);
return 0;
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MBED_DMA_API_HAL_H
#define MBED_DMA_API_HAL_H
#include "dma_api.h"
#if defined(FSL_FEATURE_SOC_EDMA_COUNT) && (FSL_FEATURE_SOC_EDMA_COUNT >= 1U)
#include "fsl_edma.h"
#endif
#if defined(FSL_FEATURE_SOC_DMA_COUNT) && (FSL_FEATURE_SOC_DMA_COUNT >= 1U)
#include "fsl_dma.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
DMAUsage dmaUsageState;
int dmaChannel;
#if defined(FSL_FEATURE_SOC_EDMA_COUNT) && (FSL_FEATURE_SOC_EDMA_COUNT >= 1U)
edma_handle_t handle;
#endif
#if defined(FSL_FEATURE_SOC_DMA_COUNT) && (FSL_FEATURE_SOC_DMA_COUNT >= 1U)
dma_handle_t handle;
#endif
} dma_options_t;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -20,6 +20,10 @@
#include "PortNames.h"
#include "PeripheralNames.h"
#include "PinNames.h"
#if DEVICE_SPI_ASYNCH
#include "fsl_dspi_edma.h"
#endif
#include "dma_api_hal.h"
#ifdef __cplusplus
extern "C" {
@ -55,6 +59,15 @@ struct i2c_s {
struct spi_s {
uint32_t instance;
uint8_t bits;
#if DEVICE_SPI_ASYNCH
status_t status;
dspi_master_handle_t spi_master_handle;
dspi_master_edma_handle_t spi_dma_master_handle;
dma_options_t spiDmaMasterRx;
dma_options_t spiDmaMasterTx;
dma_options_t spiDmaMasterIntermediary;
#endif
};
struct dac_s {

View File

@ -576,7 +576,7 @@
"macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED"],
"inherits": ["Target"],
"detect_code": ["0240"],
"device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "STORAGE", "TRNG"],
"device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "STORAGE", "TRNG"],
"features": ["LWIP", "STORAGE"],
"release_versions": ["2", "5"],
"device_name": "MK64FN1M0xxx12"
@ -588,7 +588,7 @@
"extra_labels": ["Freescale", "KSDK2_MCUS", "KPSDK_MCUS", "KPSDK_CODE", "MCU_K64F"],
"is_disk_virtual": true,
"macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED", "TARGET_K64F"],
"device_has": ["I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"],
"device_has": ["I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES"],
"device_name": "MK64FN1M0xxx12"
},
"HEXIWEAR": {
@ -600,7 +600,7 @@
"is_disk_virtual": true,
"default_toolchain": "ARM",
"detect_code": ["0214"],
"device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG"],
"device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "TRNG"],
"default_lib": "std",
"release_versions": ["2", "5"],
"device_name": "MK64FN1M0xxx12"