mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #3312 from NXPmicro/SPI_ASYNCH_API
K64F: SPI Asynch API implementationpull/3360/merge
commit
163667165e
|
@ -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_ */
|
|
@ -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->txBuffIfNull = ((uint32_t)DSPI_DUMMY_DATA << 8) | DSPI_DUMMY_DATA;
|
||||||
|
|
||||||
handle->state = kDSPI_Busy;
|
|
||||||
|
|
||||||
dspi_command_data_config_t commandStruct;
|
dspi_command_data_config_t commandStruct;
|
||||||
DSPI_StopTransfer(base);
|
DSPI_StopTransfer(base);
|
||||||
DSPI_FlushFifo(base, true, true);
|
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;
|
return kStatus_InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handle->state = kDSPI_Busy;
|
||||||
|
|
||||||
DSPI_DisableDMA(base, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
|
DSPI_DisableDMA(base, kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
|
||||||
|
|
||||||
EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_DspiMasterCallback,
|
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);
|
DSPI_DisableDMA((dspiEdmaPrivateHandle->base), kDSPI_RxDmaEnable | kDSPI_TxDmaEnable);
|
||||||
|
|
||||||
|
dspiEdmaPrivateHandle->handle->state = kDSPI_Idle;
|
||||||
|
|
||||||
if (dspiEdmaPrivateHandle->handle->callback)
|
if (dspiEdmaPrivateHandle->handle->callback)
|
||||||
{
|
{
|
||||||
dspiEdmaPrivateHandle->handle->callback(dspiEdmaPrivateHandle->base, dspiEdmaPrivateHandle->handle,
|
dspiEdmaPrivateHandle->handle->callback(dspiEdmaPrivateHandle->base, dspiEdmaPrivateHandle->handle,
|
||||||
kStatus_Success, dspiEdmaPrivateHandle->handle->userData);
|
kStatus_Success, dspiEdmaPrivateHandle->handle->userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
dspiEdmaPrivateHandle->handle->state = kDSPI_Idle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPI_MasterTransferAbortEDMA(SPI_Type *base, dspi_master_edma_handle_t *handle)
|
void DSPI_MasterTransferAbortEDMA(SPI_Type *base, dspi_master_edma_handle_t *handle)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "mbed_error.h"
|
#include "mbed_error.h"
|
||||||
#include "fsl_dspi.h"
|
#include "fsl_dspi.h"
|
||||||
#include "peripheral_clock_defines.h"
|
#include "peripheral_clock_defines.h"
|
||||||
|
#include "dma_reqs.h"
|
||||||
#include "PeripheralPins.h"
|
#include "PeripheralPins.h"
|
||||||
|
|
||||||
/* Array of SPI peripheral base address. */
|
/* 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_data = pinmap_merge(spi_mosi, spi_miso);
|
||||||
uint32_t spi_cntl = pinmap_merge(spi_sclk, spi_ssel);
|
uint32_t spi_cntl = pinmap_merge(spi_sclk, spi_ssel);
|
||||||
|
|
||||||
obj->instance = pinmap_merge(spi_data, spi_cntl);
|
obj->spi.instance = pinmap_merge(spi_data, spi_cntl);
|
||||||
MBED_ASSERT((int)obj->instance != NC);
|
MBED_ASSERT((int)obj->spi.instance != NC);
|
||||||
|
|
||||||
// pin out the spi pins
|
// pin out the spi pins
|
||||||
pinmap_pinout(mosi, PinMap_SPI_MOSI);
|
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) {
|
if (ssel != NC) {
|
||||||
pinmap_pinout(ssel, PinMap_SPI_SSEL);
|
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)
|
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)
|
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_master_config_t master_config;
|
||||||
dspi_slave_config_t slave_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) {
|
if (slave) {
|
||||||
/* Slave config */
|
/* Slave config */
|
||||||
DSPI_SlaveGetDefaultConfig(&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.cpol = (mode & 0x2) ? kDSPI_ClockPolarityActiveLow : kDSPI_ClockPolarityActiveHigh;
|
||||||
slave_config.ctarConfig.cpha = (mode & 0x1) ? kDSPI_ClockPhaseSecondEdge : kDSPI_ClockPhaseFirstEdge;
|
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 {
|
} else {
|
||||||
/* Master config */
|
/* Master config */
|
||||||
DSPI_MasterGetDefaultConfig(&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.direction = kDSPI_MsbFirst;
|
||||||
master_config.ctarConfig.pcsToSckDelayInNanoSec = 0;
|
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)
|
void spi_frequency(spi_t *obj, int hz)
|
||||||
{
|
{
|
||||||
uint32_t busClock = CLOCK_GetFreq(spi_clocks[obj->instance]);
|
uint32_t busClock = CLOCK_GetFreq(spi_clocks[obj->spi.instance]);
|
||||||
DSPI_MasterSetBaudRate(spi_address[obj->instance], kDSPI_Ctar0, (uint32_t)hz, busClock);
|
DSPI_MasterSetBaudRate(spi_address[obj->spi.instance], kDSPI_Ctar0, (uint32_t)hz, busClock);
|
||||||
//Half clock period delay after SPI transfer
|
//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)
|
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)
|
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);
|
DSPI_GetDefaultDataCommandConfig(&command);
|
||||||
command.isEndOfQueue = true;
|
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
|
// wait rx buffer full
|
||||||
while (!spi_readable(obj));
|
while (!spi_readable(obj));
|
||||||
rx_data = DSPI_ReadData(spi_address[obj->instance]);
|
rx_data = DSPI_ReadData(spi_address[obj->spi.instance]);
|
||||||
DSPI_ClearStatusFlags(spi_address[obj->instance], kDSPI_RxFifoDrainRequestFlag | kDSPI_EndOfQueueFlag);
|
DSPI_ClearStatusFlags(spi_address[obj->spi.instance], kDSPI_RxFifoDrainRequestFlag | kDSPI_EndOfQueueFlag);
|
||||||
return rx_data & 0xffff;
|
return rx_data & 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,14 +137,297 @@ int spi_slave_read(spi_t *obj)
|
||||||
uint32_t rx_data;
|
uint32_t rx_data;
|
||||||
|
|
||||||
while (!spi_readable(obj));
|
while (!spi_readable(obj));
|
||||||
rx_data = DSPI_ReadData(spi_address[obj->instance]);
|
rx_data = DSPI_ReadData(spi_address[obj->spi.instance]);
|
||||||
DSPI_ClearStatusFlags(spi_address[obj->instance], kDSPI_RxFifoDrainRequestFlag);
|
DSPI_ClearStatusFlags(spi_address[obj->spi.instance], kDSPI_RxFifoDrainRequestFlag);
|
||||||
return rx_data & 0xffff;
|
return rx_data & 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_slave_write(spi_t *obj, int value)
|
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
|
#endif
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -20,6 +20,10 @@
|
||||||
#include "PortNames.h"
|
#include "PortNames.h"
|
||||||
#include "PeripheralNames.h"
|
#include "PeripheralNames.h"
|
||||||
#include "PinNames.h"
|
#include "PinNames.h"
|
||||||
|
#if DEVICE_SPI_ASYNCH
|
||||||
|
#include "fsl_dspi_edma.h"
|
||||||
|
#endif
|
||||||
|
#include "dma_api_hal.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -55,6 +59,15 @@ struct i2c_s {
|
||||||
|
|
||||||
struct spi_s {
|
struct spi_s {
|
||||||
uint32_t instance;
|
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 {
|
struct dac_s {
|
||||||
|
|
|
@ -576,7 +576,7 @@
|
||||||
"macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED"],
|
"macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED"],
|
||||||
"inherits": ["Target"],
|
"inherits": ["Target"],
|
||||||
"detect_code": ["0240"],
|
"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"],
|
"features": ["LWIP", "STORAGE"],
|
||||||
"release_versions": ["2", "5"],
|
"release_versions": ["2", "5"],
|
||||||
"device_name": "MK64FN1M0xxx12"
|
"device_name": "MK64FN1M0xxx12"
|
||||||
|
@ -588,7 +588,7 @@
|
||||||
"extra_labels": ["Freescale", "KSDK2_MCUS", "KPSDK_MCUS", "KPSDK_CODE", "MCU_K64F"],
|
"extra_labels": ["Freescale", "KSDK2_MCUS", "KPSDK_MCUS", "KPSDK_CODE", "MCU_K64F"],
|
||||||
"is_disk_virtual": true,
|
"is_disk_virtual": true,
|
||||||
"macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED", "TARGET_K64F"],
|
"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"
|
"device_name": "MK64FN1M0xxx12"
|
||||||
},
|
},
|
||||||
"HEXIWEAR": {
|
"HEXIWEAR": {
|
||||||
|
@ -600,7 +600,7 @@
|
||||||
"is_disk_virtual": true,
|
"is_disk_virtual": true,
|
||||||
"default_toolchain": "ARM",
|
"default_toolchain": "ARM",
|
||||||
"detect_code": ["0214"],
|
"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",
|
"default_lib": "std",
|
||||||
"release_versions": ["2", "5"],
|
"release_versions": ["2", "5"],
|
||||||
"device_name": "MK64FN1M0xxx12"
|
"device_name": "MK64FN1M0xxx12"
|
||||||
|
|
Loading…
Reference in New Issue