mirror of https://github.com/ARMmbed/mbed-os.git
K64F: Add support for SERIAL ASYNCH API
Signed-off-by: Mahadevan Mahesh <Mahesh.Mahadevan@nxp.com>pull/3438/head
parent
eb3dc2d2c8
commit
ece7b6f05b
|
@ -45,4 +45,18 @@
|
|||
kDmaRequestMux0SPI0Rx, kDmaRequestMux0SPI1, kDmaRequestMux0SPI2 \
|
||||
}
|
||||
|
||||
/* Array for UART DMA TX requests */
|
||||
#define UART_DMA_TX_REQUEST_NUMBERS \
|
||||
{ \
|
||||
kDmaRequestMux0UART0Tx, kDmaRequestMux0UART1Tx, kDmaRequestMux0UART2Tx, \
|
||||
kDmaRequestMux0UART3Tx, kDmaRequestMux0UART4, kDmaRequestMux0UART5 \
|
||||
}
|
||||
|
||||
/* Array for UART DMA RX requests */
|
||||
#define UART_DMA_RX_REQUEST_NUMBERS \
|
||||
{ \
|
||||
kDmaRequestMux0UART0Rx, kDmaRequestMux0UART1Rx, kDmaRequestMux0UART2Rx, \
|
||||
kDmaRequestMux0UART3Rx, kDmaRequestMux0UART4, kDmaRequestMux0UART5 \
|
||||
}
|
||||
|
||||
#endif /* _FSL_DMA_REQS_H_ */
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "fsl_uart.h"
|
||||
#include "peripheral_clock_defines.h"
|
||||
#include "PeripheralPins.h"
|
||||
#include "dma_reqs.h"
|
||||
#include "fsl_clock_config.h"
|
||||
|
||||
static uint32_t serial_irq_ids[FSL_FEATURE_SOC_UART_COUNT] = {0};
|
||||
|
@ -37,6 +38,11 @@ static UART_Type *const uart_addrs[] = UART_BASE_PTRS;
|
|||
/* Array of UART bus clock frequencies */
|
||||
static clock_name_t const uart_clocks[] = UART_CLOCK_FREQS;
|
||||
|
||||
/* UART transfer states */
|
||||
#define kUART_TxIdle 0
|
||||
#define kUART_TxBusy 1
|
||||
#define kUART_RxIdle 2
|
||||
#define kUART_RxBusy 3
|
||||
|
||||
int stdio_uart_inited = 0;
|
||||
serial_t stdio_uart;
|
||||
|
@ -45,8 +51,8 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
|
|||
{
|
||||
uint32_t uart_tx = pinmap_peripheral(tx, PinMap_UART_TX);
|
||||
uint32_t uart_rx = pinmap_peripheral(rx, PinMap_UART_RX);
|
||||
obj->index = pinmap_merge(uart_tx, uart_rx);
|
||||
MBED_ASSERT((int)obj->index != NC);
|
||||
obj->serial.index = pinmap_merge(uart_tx, uart_rx);
|
||||
MBED_ASSERT((int)obj->serial.index != NC);
|
||||
|
||||
uart_config_t config;
|
||||
|
||||
|
@ -55,40 +61,47 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
|
|||
config.enableTx = false;
|
||||
config.enableRx = false;
|
||||
|
||||
UART_Init(uart_addrs[obj->index], &config, CLOCK_GetFreq(uart_clocks[obj->index]));
|
||||
UART_Init(uart_addrs[obj->serial.index], &config, CLOCK_GetFreq(uart_clocks[obj->serial.index]));
|
||||
|
||||
pinmap_pinout(tx, PinMap_UART_TX);
|
||||
pinmap_pinout(rx, PinMap_UART_RX);
|
||||
|
||||
if (tx != NC) {
|
||||
UART_EnableTx(uart_addrs[obj->index], true);
|
||||
UART_EnableTx(uart_addrs[obj->serial.index], true);
|
||||
pin_mode(tx, PullUp);
|
||||
}
|
||||
if (rx != NC) {
|
||||
UART_EnableRx(uart_addrs[obj->index], true);
|
||||
UART_EnableRx(uart_addrs[obj->serial.index], true);
|
||||
pin_mode(rx, PullUp);
|
||||
}
|
||||
|
||||
if (obj->index == STDIO_UART) {
|
||||
if (obj->serial.index == STDIO_UART) {
|
||||
stdio_uart_inited = 1;
|
||||
memcpy(&stdio_uart, obj, sizeof(serial_t));
|
||||
}
|
||||
|
||||
obj->serial.uartDmaRx.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;;
|
||||
obj->serial.txstate = kUART_TxIdle;
|
||||
obj->serial.rxstate = kUART_RxIdle;
|
||||
|
||||
/* Zero the handle. */
|
||||
memset(&(obj->serial.uart_transfer_handle), 0, sizeof(obj->serial.uart_transfer_handle));
|
||||
}
|
||||
|
||||
void serial_free(serial_t *obj)
|
||||
{
|
||||
UART_Deinit(uart_addrs[obj->index]);
|
||||
serial_irq_ids[obj->index] = 0;
|
||||
UART_Deinit(uart_addrs[obj->serial.index]);
|
||||
serial_irq_ids[obj->serial.index] = 0;
|
||||
}
|
||||
|
||||
void serial_baud(serial_t *obj, int baudrate)
|
||||
{
|
||||
UART_SetBaudRate(uart_addrs[obj->index], (uint32_t)baudrate, CLOCK_GetFreq(uart_clocks[obj->index]));
|
||||
UART_SetBaudRate(uart_addrs[obj->serial.index], (uint32_t)baudrate, CLOCK_GetFreq(uart_clocks[obj->serial.index]));
|
||||
}
|
||||
|
||||
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
|
||||
{
|
||||
UART_Type *base = uart_addrs[obj->index];
|
||||
UART_Type *base = uart_addrs[obj->serial.index];
|
||||
uint8_t temp;
|
||||
/* Set bit count and parity mode. */
|
||||
temp = base->C1 & ~(UART_C1_PE_MASK | UART_C1_PT_MASK | UART_C1_M_MASK);
|
||||
|
@ -174,7 +187,7 @@ void uart5_irq()
|
|||
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
|
||||
{
|
||||
irq_handler = handler;
|
||||
serial_irq_ids[obj->index] = id;
|
||||
serial_irq_ids[obj->serial.index] = id;
|
||||
}
|
||||
|
||||
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
|
||||
|
@ -182,7 +195,7 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
|
|||
IRQn_Type uart_irqs[] = UART_RX_TX_IRQS;
|
||||
uint32_t vector = 0;
|
||||
|
||||
switch (obj->index) {
|
||||
switch (obj->serial.index) {
|
||||
case 0:
|
||||
vector = (uint32_t)&uart0_irq;
|
||||
break;
|
||||
|
@ -208,42 +221,42 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
|
|||
if (enable) {
|
||||
switch (irq) {
|
||||
case RxIrq:
|
||||
UART_EnableInterrupts(uart_addrs[obj->index], kUART_RxDataRegFullInterruptEnable);
|
||||
UART_EnableInterrupts(uart_addrs[obj->serial.index], kUART_RxDataRegFullInterruptEnable);
|
||||
break;
|
||||
case TxIrq:
|
||||
UART_EnableInterrupts(uart_addrs[obj->index], kUART_TxDataRegEmptyInterruptEnable);
|
||||
UART_EnableInterrupts(uart_addrs[obj->serial.index], kUART_TxDataRegEmptyInterruptEnable);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
NVIC_SetVector(uart_irqs[obj->index], vector);
|
||||
NVIC_EnableIRQ(uart_irqs[obj->index]);
|
||||
NVIC_SetVector(uart_irqs[obj->serial.index], vector);
|
||||
NVIC_EnableIRQ(uart_irqs[obj->serial.index]);
|
||||
|
||||
} else { // disable
|
||||
int all_disabled = 0;
|
||||
SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
|
||||
switch (irq) {
|
||||
case RxIrq:
|
||||
UART_DisableInterrupts(uart_addrs[obj->index], kUART_RxDataRegFullInterruptEnable);
|
||||
UART_DisableInterrupts(uart_addrs[obj->serial.index], kUART_RxDataRegFullInterruptEnable);
|
||||
break;
|
||||
case TxIrq:
|
||||
UART_DisableInterrupts(uart_addrs[obj->index], kUART_TxDataRegEmptyInterruptEnable);
|
||||
UART_DisableInterrupts(uart_addrs[obj->serial.index], kUART_TxDataRegEmptyInterruptEnable);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (other_irq) {
|
||||
case RxIrq:
|
||||
all_disabled = ((UART_GetEnabledInterrupts(uart_addrs[obj->index]) & kUART_RxDataRegFullInterruptEnable) == 0);
|
||||
all_disabled = ((UART_GetEnabledInterrupts(uart_addrs[obj->serial.index]) & kUART_RxDataRegFullInterruptEnable) == 0);
|
||||
break;
|
||||
case TxIrq:
|
||||
all_disabled = ((UART_GetEnabledInterrupts(uart_addrs[obj->index]) & kUART_TxDataRegEmptyInterruptEnable) == 0);
|
||||
all_disabled = ((UART_GetEnabledInterrupts(uart_addrs[obj->serial.index]) & kUART_TxDataRegEmptyInterruptEnable) == 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (all_disabled)
|
||||
NVIC_DisableIRQ(uart_irqs[obj->index]);
|
||||
NVIC_DisableIRQ(uart_irqs[obj->serial.index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,7 +264,7 @@ int serial_getc(serial_t *obj)
|
|||
{
|
||||
while (!serial_readable(obj));
|
||||
uint8_t data;
|
||||
data = UART_ReadByte(uart_addrs[obj->index]);
|
||||
data = UART_ReadByte(uart_addrs[obj->serial.index]);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -259,22 +272,22 @@ int serial_getc(serial_t *obj)
|
|||
void serial_putc(serial_t *obj, int c)
|
||||
{
|
||||
while (!serial_writable(obj));
|
||||
UART_WriteByte(uart_addrs[obj->index], (uint8_t)c);
|
||||
UART_WriteByte(uart_addrs[obj->serial.index], (uint8_t)c);
|
||||
}
|
||||
|
||||
int serial_readable(serial_t *obj)
|
||||
{
|
||||
uint32_t status_flags = UART_GetStatusFlags(uart_addrs[obj->index]);
|
||||
uint32_t status_flags = UART_GetStatusFlags(uart_addrs[obj->serial.index]);
|
||||
if (status_flags & kUART_RxOverrunFlag)
|
||||
UART_ClearStatusFlags(uart_addrs[obj->index], kUART_RxOverrunFlag);
|
||||
UART_ClearStatusFlags(uart_addrs[obj->serial.index], kUART_RxOverrunFlag);
|
||||
return (status_flags & kUART_RxDataRegFullFlag);
|
||||
}
|
||||
|
||||
int serial_writable(serial_t *obj)
|
||||
{
|
||||
uint32_t status_flags = UART_GetStatusFlags(uart_addrs[obj->index]);
|
||||
uint32_t status_flags = UART_GetStatusFlags(uart_addrs[obj->serial.index]);
|
||||
if (status_flags & kUART_RxOverrunFlag)
|
||||
UART_ClearStatusFlags(uart_addrs[obj->index], kUART_RxOverrunFlag);
|
||||
UART_ClearStatusFlags(uart_addrs[obj->serial.index], kUART_RxOverrunFlag);
|
||||
return (status_flags & kUART_TxDataRegEmptyFlag);
|
||||
}
|
||||
|
||||
|
@ -289,12 +302,12 @@ void serial_pinout_tx(PinName tx)
|
|||
|
||||
void serial_break_set(serial_t *obj)
|
||||
{
|
||||
uart_addrs[obj->index]->C2 |= UART_C2_SBK_MASK;
|
||||
uart_addrs[obj->serial.index]->C2 |= UART_C2_SBK_MASK;
|
||||
}
|
||||
|
||||
void serial_break_clear(serial_t *obj)
|
||||
{
|
||||
uart_addrs[obj->index]->C2 &= ~UART_C2_SBK_MASK;
|
||||
uart_addrs[obj->serial.index]->C2 &= ~UART_C2_SBK_MASK;
|
||||
}
|
||||
|
||||
#if DEVICE_SERIAL_FC
|
||||
|
@ -307,24 +320,24 @@ void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, Pi
|
|||
switch(type) {
|
||||
case FlowControlRTS:
|
||||
pinmap_pinout(rxflow, PinMap_UART_RTS);
|
||||
uart_addrs[obj->index]->MODEM &= ~UART_MODEM_TXCTSE_MASK;
|
||||
uart_addrs[obj->index]->MODEM |= UART_MODEM_RXRTSE_MASK;
|
||||
uart_addrs[obj->serial.index]->MODEM &= ~UART_MODEM_TXCTSE_MASK;
|
||||
uart_addrs[obj->serial.index]->MODEM |= UART_MODEM_RXRTSE_MASK;
|
||||
break;
|
||||
|
||||
case FlowControlCTS:
|
||||
pinmap_pinout(txflow, PinMap_UART_CTS);
|
||||
uart_addrs[obj->index]->MODEM &= ~UART_MODEM_RXRTSE_MASK;
|
||||
uart_addrs[obj->index]->MODEM |= UART_MODEM_TXCTSE_MASK;
|
||||
uart_addrs[obj->serial.index]->MODEM &= ~UART_MODEM_RXRTSE_MASK;
|
||||
uart_addrs[obj->serial.index]->MODEM |= UART_MODEM_TXCTSE_MASK;
|
||||
break;
|
||||
|
||||
case FlowControlRTSCTS:
|
||||
pinmap_pinout(rxflow, PinMap_UART_RTS);
|
||||
pinmap_pinout(txflow, PinMap_UART_CTS);
|
||||
uart_addrs[obj->index]->MODEM |= UART_MODEM_TXCTSE_MASK | UART_MODEM_RXRTSE_MASK;
|
||||
uart_addrs[obj->serial.index]->MODEM |= UART_MODEM_TXCTSE_MASK | UART_MODEM_RXRTSE_MASK;
|
||||
break;
|
||||
|
||||
case FlowControlNone:
|
||||
uart_addrs[obj->index]->MODEM &= ~(UART_MODEM_TXCTSE_MASK | UART_MODEM_RXRTSE_MASK);
|
||||
uart_addrs[obj->serial.index]->MODEM &= ~(UART_MODEM_TXCTSE_MASK | UART_MODEM_RXRTSE_MASK);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -334,4 +347,366 @@ void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, Pi
|
|||
|
||||
#endif
|
||||
|
||||
static void serial_send_asynch(serial_t *obj)
|
||||
{
|
||||
uart_transfer_t sendXfer;
|
||||
|
||||
/*Setup send transfer*/
|
||||
sendXfer.data = obj->tx_buff.buffer;
|
||||
sendXfer.dataSize = obj->tx_buff.length;
|
||||
|
||||
if (obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_ALLOCATED ||
|
||||
obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
|
||||
UART_SendEDMA(uart_addrs[obj->serial.index], &obj->serial.uart_dma_handle, &sendXfer);
|
||||
} else {
|
||||
UART_TransferSendNonBlocking(uart_addrs[obj->serial.index], &obj->serial.uart_transfer_handle, &sendXfer);
|
||||
}
|
||||
}
|
||||
|
||||
static void serial_receive_asynch(serial_t *obj)
|
||||
{
|
||||
uart_transfer_t receiveXfer;
|
||||
|
||||
/*Setup send transfer*/
|
||||
receiveXfer.data = obj->rx_buff.buffer;
|
||||
receiveXfer.dataSize = obj->rx_buff.length;
|
||||
|
||||
if (obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_ALLOCATED ||
|
||||
obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
|
||||
UART_ReceiveEDMA(uart_addrs[obj->serial.index], &obj->serial.uart_dma_handle, &receiveXfer);
|
||||
} else {
|
||||
UART_TransferReceiveNonBlocking(uart_addrs[obj->serial.index], &obj->serial.uart_transfer_handle, &receiveXfer, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static bool serial_allocate_dma(serial_t *obj, uint32_t handler)
|
||||
{
|
||||
dma_request_source_t dma_rx_requests[] = UART_DMA_RX_REQUEST_NUMBERS;
|
||||
dma_request_source_t dma_tx_requests[] = UART_DMA_TX_REQUEST_NUMBERS;
|
||||
edma_config_t userConfig;
|
||||
|
||||
/* Allocate the UART RX DMA channel */
|
||||
obj->serial.uartDmaRx.dmaChannel = dma_channel_allocate(dma_rx_requests[obj->serial.index]);
|
||||
if (obj->serial.uartDmaRx.dmaChannel == DMA_ERROR_OUT_OF_CHANNELS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Allocate the UART TX DMA channel */
|
||||
obj->serial.uartDmaTx.dmaChannel = dma_channel_allocate(dma_tx_requests[obj->serial.index]);
|
||||
if (obj->serial.uartDmaTx.dmaChannel == DMA_ERROR_OUT_OF_CHANNELS) {
|
||||
dma_channel_free(obj->serial.uartDmaRx.dmaChannel);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* EDMA init*/
|
||||
/*
|
||||
* userConfig.enableRoundRobinArbitration = false;
|
||||
* userConfig.enableHaltOnError = true;
|
||||
* userConfig.enableContinuousLinkMode = false;
|
||||
* userConfig.enableDebugMode = false;
|
||||
*/
|
||||
EDMA_GetDefaultConfig(&userConfig);
|
||||
|
||||
EDMA_Init(DMA0, &userConfig);
|
||||
|
||||
memset(&(obj->serial.uartDmaTx.handle), 0, sizeof(obj->serial.uartDmaTx.handle));
|
||||
memset(&(obj->serial.uartDmaRx.handle), 0, sizeof(obj->serial.uartDmaRx.handle));
|
||||
|
||||
EDMA_CreateHandle(&(obj->serial.uartDmaRx.handle), DMA0, obj->serial.uartDmaRx.dmaChannel);
|
||||
EDMA_CreateHandle(&(obj->serial.uartDmaTx.handle), DMA0, obj->serial.uartDmaTx.dmaChannel);
|
||||
|
||||
UART_TransferCreateHandleEDMA(uart_addrs[obj->serial.index], &obj->serial.uart_dma_handle, (uart_edma_transfer_callback_t)handler,
|
||||
NULL, &obj->serial.uartDmaTx.handle, &obj->serial.uartDmaRx.handle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void serial_enable_dma(serial_t *obj, uint32_t handler, DMAUsage state)
|
||||
{
|
||||
dma_init();
|
||||
|
||||
if (state == DMA_USAGE_ALWAYS && obj->serial.uartDmaRx.dmaUsageState != DMA_USAGE_ALLOCATED) {
|
||||
/* Try to allocate channels */
|
||||
if (serial_allocate_dma(obj, handler)) {
|
||||
obj->serial.uartDmaRx.dmaUsageState = DMA_USAGE_ALLOCATED;
|
||||
} else {
|
||||
obj->serial.uartDmaRx.dmaUsageState = state;
|
||||
}
|
||||
} else if (state == DMA_USAGE_OPPORTUNISTIC) {
|
||||
if (obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_ALLOCATED) {
|
||||
/* Channels have already been allocated previously by an ALWAYS state, so after this transfer, we will release them */
|
||||
obj->serial.uartDmaRx.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
|
||||
} else {
|
||||
/* Try to allocate channels */
|
||||
if (serial_allocate_dma(obj, handler)) {
|
||||
obj->serial.uartDmaRx.dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED;
|
||||
} else {
|
||||
obj->serial.uartDmaRx.dmaUsageState = state;
|
||||
}
|
||||
}
|
||||
} else if (state == DMA_USAGE_NEVER) {
|
||||
/* If channels are allocated, get rid of them */
|
||||
if (obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_ALLOCATED) {
|
||||
dma_channel_free(obj->serial.uartDmaRx.dmaChannel);
|
||||
dma_channel_free(obj->serial.uartDmaRx.dmaChannel);
|
||||
}
|
||||
obj->serial.uartDmaRx.dmaUsageState = DMA_USAGE_NEVER;
|
||||
}
|
||||
}
|
||||
|
||||
void serial_enable_event(serial_t *obj, int event, uint8_t enable)
|
||||
{
|
||||
// Keep track of the requested events.
|
||||
if (enable) {
|
||||
obj->serial.events |= event;
|
||||
} else {
|
||||
obj->serial.events &= ~event;
|
||||
}
|
||||
}
|
||||
|
||||
static void serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width) {
|
||||
(void)width;
|
||||
|
||||
// Exit if a transmit is already on-going
|
||||
if (serial_tx_active(obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
obj->tx_buff.buffer = tx;
|
||||
obj->tx_buff.length = tx_length;
|
||||
obj->tx_buff.pos = 0;
|
||||
}
|
||||
|
||||
int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint)
|
||||
{
|
||||
// Check that a buffer has indeed been set up
|
||||
MBED_ASSERT(tx != (void*)0);
|
||||
|
||||
if (tx_length == 0) return 0;
|
||||
|
||||
if (serial_tx_active(obj)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set up buffer
|
||||
serial_tx_buffer_set(obj, (void *)tx, tx_length, tx_width);
|
||||
|
||||
// Set up events
|
||||
serial_enable_event(obj, SERIAL_EVENT_TX_ALL, false);
|
||||
serial_enable_event(obj, event, true);
|
||||
|
||||
/* If using DMA, allocate channels only if they have not already been allocated */
|
||||
if (hint != DMA_USAGE_NEVER) {
|
||||
/* User requested to transfer using DMA */
|
||||
serial_enable_dma(obj, handler, hint);
|
||||
|
||||
/* Check if DMA setup was successful */
|
||||
if (obj->serial.uartDmaRx.dmaUsageState != DMA_USAGE_ALLOCATED && obj->serial.uartDmaRx.dmaUsageState != DMA_USAGE_TEMPORARY_ALLOCATED) {
|
||||
/* Set up an interrupt transfer as DMA is unavailable */
|
||||
if (obj->serial.uart_transfer_handle.callback == 0) {
|
||||
UART_TransferCreateHandle(uart_addrs[obj->serial.index], &obj->serial.uart_transfer_handle, (uart_transfer_callback_t)handler, NULL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* User requested to transfer using interrupts */
|
||||
/* Disable the DMA */
|
||||
serial_enable_dma(obj, handler, hint);
|
||||
|
||||
/* Set up the interrupt transfer */
|
||||
if (obj->serial.uart_transfer_handle.callback == 0) {
|
||||
UART_TransferCreateHandle(uart_addrs[obj->serial.index], &obj->serial.uart_transfer_handle, (uart_transfer_callback_t)handler, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the transfer */
|
||||
serial_send_asynch(obj);
|
||||
obj->serial.txstate = kUART_TxBusy;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width)
|
||||
{
|
||||
// We only support byte buffers for now
|
||||
MBED_ASSERT(width == 8);
|
||||
|
||||
if (serial_rx_active(obj)) return;
|
||||
|
||||
obj->rx_buff.buffer = rx;
|
||||
obj->rx_buff.length = rx_length;
|
||||
obj->rx_buff.pos = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Character match is currently not supported */
|
||||
void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint)
|
||||
{
|
||||
// Check that a buffer has indeed been set up
|
||||
MBED_ASSERT(rx != (void*)0);
|
||||
if (rx_length == 0) return;
|
||||
|
||||
if (serial_rx_active(obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up buffer
|
||||
serial_rx_buffer_set(obj,(void*) rx, rx_length, rx_width);
|
||||
|
||||
// Set up events
|
||||
serial_enable_event(obj, SERIAL_EVENT_RX_ALL, false);
|
||||
serial_enable_event(obj, event, true);
|
||||
|
||||
//obj->char_match = char_match;
|
||||
|
||||
/* If using DMA, allocate channels only if they have not already been allocated */
|
||||
if (hint != DMA_USAGE_NEVER) {
|
||||
/* User requested to transfer using DMA */
|
||||
serial_enable_dma(obj, handler, hint);
|
||||
|
||||
/* Check if DMA setup was successful */
|
||||
if (obj->serial.uartDmaRx.dmaUsageState != DMA_USAGE_ALLOCATED && obj->serial.uartDmaRx.dmaUsageState != DMA_USAGE_TEMPORARY_ALLOCATED) {
|
||||
/* Set up an interrupt transfer as DMA is unavailable */
|
||||
if (obj->serial.uart_transfer_handle.callback == 0) {
|
||||
UART_TransferCreateHandle(uart_addrs[obj->serial.index], &obj->serial.uart_transfer_handle, (uart_transfer_callback_t)handler, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
/* User requested to transfer using interrupts */
|
||||
/* Disable the DMA */
|
||||
serial_enable_dma(obj, handler, hint);
|
||||
|
||||
/* Set up the interrupt transfer */
|
||||
if (obj->serial.uart_transfer_handle.callback == 0) {
|
||||
UART_TransferCreateHandle(uart_addrs[obj->serial.index], &obj->serial.uart_transfer_handle, (uart_transfer_callback_t)handler, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the transfer */
|
||||
serial_receive_asynch(obj);
|
||||
obj->serial.rxstate = kUART_RxBusy;
|
||||
}
|
||||
|
||||
uint8_t serial_tx_active(serial_t *obj)
|
||||
{
|
||||
if (obj->serial.txstate == kUART_TxIdle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t serial_rx_active(serial_t *obj)
|
||||
{
|
||||
if (obj->serial.rxstate == kUART_RxIdle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int serial_irq_handler_asynch(serial_t *obj)
|
||||
{
|
||||
int status = 0;
|
||||
//uint8_t *buf = (uint8_t*)obj->rx_buff.buffer;
|
||||
uint32_t status_flags = UART_GetStatusFlags(uart_addrs[obj->serial.index]);
|
||||
|
||||
/* Determine whether the current scenario is DMA or IRQ, and act accordingly */
|
||||
if (obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_ALLOCATED || obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
|
||||
/* DMA implementation */
|
||||
if ((obj->serial.txstate != kUART_TxIdle) && (obj->serial.uart_dma_handle.txState == kUART_TxIdle)) {
|
||||
obj->serial.txstate = kUART_TxIdle;
|
||||
status |= SERIAL_EVENT_TX_COMPLETE;
|
||||
}
|
||||
|
||||
if ((obj->serial.rxstate != kUART_RxIdle) && (obj->serial.uart_dma_handle.rxState == kUART_RxIdle)) {
|
||||
obj->serial.rxstate = kUART_RxIdle;
|
||||
status |= SERIAL_EVENT_RX_COMPLETE;
|
||||
}
|
||||
|
||||
/* Release the dma channels if they were opportunistically allocated */
|
||||
if (obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
|
||||
/* Ensure both TX and RX channels are idle before freeing them */
|
||||
if ((obj->serial.uart_dma_handle.txState == kUART_TxIdle) && (obj->serial.uart_dma_handle.rxState == kUART_RxIdle)) {
|
||||
dma_channel_free(obj->serial.uartDmaRx.dmaChannel);
|
||||
dma_channel_free(obj->serial.uartDmaTx.dmaChannel);
|
||||
obj->serial.uartDmaRx.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Interrupt implementation */
|
||||
if ((obj->serial.txstate != kUART_TxIdle) && (obj->serial.uart_transfer_handle.txState == kUART_TxIdle)) {
|
||||
obj->serial.txstate = kUART_TxIdle;
|
||||
status |= SERIAL_EVENT_TX_COMPLETE;
|
||||
}
|
||||
|
||||
if ((obj->serial.rxstate != kUART_RxIdle) && (obj->serial.uart_transfer_handle.rxState == kUART_RxIdle)) {
|
||||
obj->serial.rxstate = kUART_RxIdle;
|
||||
status |= SERIAL_EVENT_RX_COMPLETE;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (obj->char_match != SERIAL_RESERVED_CHAR_MATCH){
|
||||
/* Check for character match event */
|
||||
if (buf[obj->rx_buff.length - 1] == obj->char_match) {
|
||||
status |= SERIAL_EVENT_RX_CHARACTER_MATCH;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (status_flags & kUART_RxOverrunFlag) {
|
||||
UART_ClearStatusFlags(uart_addrs[obj->serial.index], kUART_RxOverrunFlag);
|
||||
status |= SERIAL_EVENT_RX_OVERRUN_ERROR;
|
||||
}
|
||||
|
||||
if (status_flags & kUART_FramingErrorFlag) {
|
||||
UART_ClearStatusFlags(uart_addrs[obj->serial.index], kUART_FramingErrorFlag);
|
||||
status |= SERIAL_EVENT_RX_FRAMING_ERROR;
|
||||
}
|
||||
|
||||
if (status_flags & kUART_ParityErrorFlag) {
|
||||
UART_ClearStatusFlags(uart_addrs[obj->serial.index], kUART_ParityErrorFlag);
|
||||
status |= SERIAL_EVENT_RX_PARITY_ERROR;
|
||||
}
|
||||
|
||||
return status & obj->serial.events;
|
||||
}
|
||||
|
||||
void serial_tx_abort_asynch(serial_t *obj)
|
||||
{
|
||||
if (obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_ALLOCATED || obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
|
||||
UART_TransferAbortSendEDMA(uart_addrs[obj->serial.index], &obj->serial.uart_dma_handle);
|
||||
/* Release the dma channels if they were opportunistically allocated */
|
||||
if (obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
|
||||
/* Ensure both TX and RX channels are idle before freeing them */
|
||||
if ((obj->serial.uart_dma_handle.txState == kUART_TxIdle) && (obj->serial.uart_dma_handle.rxState == kUART_RxIdle)) {
|
||||
dma_channel_free(obj->serial.uartDmaRx.dmaChannel);
|
||||
dma_channel_free(obj->serial.uartDmaTx.dmaChannel);
|
||||
obj->serial.uartDmaRx.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
UART_TransferAbortSend(uart_addrs[obj->serial.index], &obj->serial.uart_transfer_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void serial_rx_abort_asynch(serial_t *obj)
|
||||
{
|
||||
if (obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_ALLOCATED || obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
|
||||
UART_TransferAbortReceiveEDMA(uart_addrs[obj->serial.index], &obj->serial.uart_dma_handle);
|
||||
/* Release the dma channels if they were opportunistically allocated */
|
||||
if (obj->serial.uartDmaRx.dmaUsageState == DMA_USAGE_TEMPORARY_ALLOCATED) {
|
||||
/* Ensure both TX and RX channels are idle before freeing them */
|
||||
if ((obj->serial.uart_dma_handle.txState == kUART_TxIdle) && (obj->serial.uart_dma_handle.rxState == kUART_RxIdle)) {
|
||||
dma_channel_free(obj->serial.uartDmaRx.dmaChannel);
|
||||
dma_channel_free(obj->serial.uartDmaTx.dmaChannel);
|
||||
obj->serial.uartDmaRx.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
UART_TransferAbortReceive(uart_addrs[obj->serial.index], &obj->serial.uart_transfer_handle);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#if DEVICE_SPI_ASYNCH
|
||||
#include "fsl_dspi_edma.h"
|
||||
#endif
|
||||
#if DEVICE_SERIAL_ASYNCH
|
||||
#include "fsl_uart_edma.h"
|
||||
#endif
|
||||
#include "dma_api_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -46,6 +49,15 @@ struct pwmout_s {
|
|||
|
||||
struct serial_s {
|
||||
int index;
|
||||
#if DEVICE_SERIAL_ASYNCH
|
||||
uint8_t txstate;
|
||||
uint8_t rxstate;
|
||||
uint32_t events;
|
||||
uart_handle_t uart_transfer_handle;
|
||||
uart_edma_handle_t uart_dma_handle;
|
||||
dma_options_t uartDmaTx;
|
||||
dma_options_t uartDmaRx;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct analogin_s {
|
||||
|
|
|
@ -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", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "STORAGE", "TRNG"],
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SERIAL_ASYNCH", "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", "MCUXpresso_MCUS", "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", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES"],
|
||||
"device_has": ["I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "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", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "TRNG"],
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "TRNG"],
|
||||
"default_lib": "std",
|
||||
"release_versions": ["2", "5"],
|
||||
"device_name": "MK64FN1M0xxx12"
|
||||
|
|
Loading…
Reference in New Issue