From 5eb92ea1dbfce751dd6a5276b375fac57dcfdf67 Mon Sep 17 00:00:00 2001 From: Mahadevan Mahesh Date: Thu, 3 Nov 2016 07:55:27 -0500 Subject: [PATCH 1/2] K64F SPI Update: Implement Asynch API's for SPI Signed-off-by: Mahadevan Mahesh --- .../TARGET_MCU_K64F/dma_reqs.h | 48 +++ .../TARGET_MCU_K64F/spi_api.c | 325 +++++++++++++++++- .../TARGET_KSDK2_MCUS/api/dma_api.c | 70 ++++ .../TARGET_KSDK2_MCUS/api/dma_api_hal.h | 62 ++++ .../TARGET_KSDK2_MCUS/api/objects.h | 13 + targets/targets.json | 6 +- 6 files changed, 505 insertions(+), 19 deletions(-) create mode 100644 targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/dma_reqs.h create mode 100644 targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/dma_api.c create mode 100644 targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/dma_api_hal.h diff --git a/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/dma_reqs.h b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/dma_reqs.h new file mode 100644 index 0000000000..cf569510e0 --- /dev/null +++ b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/dma_reqs.h @@ -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_ */ diff --git a/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/spi_api.c b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/spi_api.c index 18428a9a44..44f37ca175 100644 --- a/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/spi_api.c +++ b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/spi_api.c @@ -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 diff --git a/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/dma_api.c b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/dma_api.c new file mode 100644 index 0000000000..b578d00de3 --- /dev/null +++ b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/dma_api.c @@ -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; +} diff --git a/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/dma_api_hal.h b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/dma_api_hal.h new file mode 100644 index 0000000000..79681fd2ac --- /dev/null +++ b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/dma_api_hal.h @@ -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 diff --git a/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/objects.h b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/objects.h index dbdb8c411b..ac4f33898d 100644 --- a/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/objects.h +++ b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/api/objects.h @@ -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 { diff --git a/targets/targets.json b/targets/targets.json index a69a46ee0f..c6221f7a90 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -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" From d5fca6dab0315264be7978c2ba3f89e789d17b5a Mon Sep 17 00:00:00 2001 From: Mahadevan Mahesh Date: Mon, 21 Nov 2016 14:39:26 -0600 Subject: [PATCH 2/2] K64F DSPI Driver: Fix errors where DSPI state is incorrectly kept busy Signed-off-by: Mahadevan Mahesh --- .../TARGET_MCU_K64F/drivers/fsl_dspi_edma.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_dspi_edma.c b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_dspi_edma.c index e37c78eac7..a110c18881 100755 --- a/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_dspi_edma.c +++ b/targets/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_dspi_edma.c @@ -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)