mirror of https://github.com/ARMmbed/mbed-os.git
Enable async serial for K66F
Added DMA definitions and usage for UART, based on K64F's code.pull/11443/head
parent
1800632655
commit
551bc8a1f5
|
@ -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 _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, kDmaRequestMux0SPI1Tx \
|
||||
}
|
||||
|
||||
/* Array for DSPI DMA RX requests */
|
||||
#define SPI_DMA_RX_REQUEST_NUMBERS \
|
||||
{ \
|
||||
kDmaRequestMux0SPI0Rx, kDmaRequestMux0SPI1Rx \
|
||||
}
|
||||
|
||||
/* Array for UART DMA TX requests */
|
||||
#define UART_DMA_TX_REQUEST_NUMBERS \
|
||||
{ \
|
||||
kDmaRequestMux0UART0Tx, kDmaRequestMux0UART1Tx, kDmaRequestMux0UART2Tx, \
|
||||
kDmaRequestMux0UART3Tx, kDmaRequestMux0UART4 \
|
||||
}
|
||||
|
||||
/* Array for UART DMA RX requests */
|
||||
#define UART_DMA_RX_REQUEST_NUMBERS \
|
||||
{ \
|
||||
kDmaRequestMux0UART0Rx, kDmaRequestMux0UART1Rx, kDmaRequestMux0UART2Rx, \
|
||||
kDmaRequestMux0UART3Rx, kDmaRequestMux0UART4 \
|
||||
}
|
||||
|
||||
#endif /* _FSL_DMA_REQS_H_ */
|
|
@ -24,10 +24,12 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "cmsis.h"
|
||||
#include "mbed_power_mgmt.h"
|
||||
#include "pinmap.h"
|
||||
#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 +39,12 @@ 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;
|
||||
|
||||
|
@ -44,8 +52,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;
|
||||
|
||||
|
@ -54,40 +62,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);
|
||||
|
@ -163,10 +178,11 @@ void uart4_irq()
|
|||
uint32_t status_flags = UART4->S1;
|
||||
uart_irq((status_flags & UART_S1_TDRE_MASK), (status_flags & UART_S1_RDRF_MASK), 4);
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -174,7 +190,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;
|
||||
|
@ -197,42 +213,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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,7 +256,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;
|
||||
}
|
||||
|
@ -248,22 +264,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);
|
||||
}
|
||||
|
||||
|
@ -278,45 +294,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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only hardware flow control is implemented in this API.
|
||||
*/
|
||||
void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
break;
|
||||
|
||||
case FlowControlNone:
|
||||
uart_addrs[obj->index]->MODEM &= ~(UART_MODEM_TXCTSE_MASK | UART_MODEM_RXRTSE_MASK);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
uart_addrs[obj->serial.index]->C2 &= ~UART_C2_SBK_MASK;
|
||||
}
|
||||
|
||||
const PinMap *serial_tx_pinmap()
|
||||
|
@ -339,6 +322,441 @@ const PinMap *serial_rts_pinmap()
|
|||
return PinMap_UART_RTS;
|
||||
}
|
||||
|
||||
#if DEVICE_SERIAL_FC
|
||||
|
||||
/*
|
||||
* Only hardware flow control is implemented in this API.
|
||||
*/
|
||||
void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow)
|
||||
{
|
||||
switch(type) {
|
||||
case FlowControlRTS:
|
||||
pinmap_pinout(rxflow, PinMap_UART_RTS);
|
||||
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->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->serial.index]->MODEM |= UART_MODEM_TXCTSE_MASK | UART_MODEM_RXRTSE_MASK;
|
||||
break;
|
||||
|
||||
case FlowControlNone:
|
||||
uart_addrs[obj->serial.index]->MODEM &= ~(UART_MODEM_TXCTSE_MASK | UART_MODEM_RXRTSE_MASK);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
obj->serial.txstate = kUART_TxBusy;
|
||||
|
||||
/* Start the transfer */
|
||||
serial_send_asynch(obj);
|
||||
|
||||
/* Can't enter deep sleep as long as UART transmit is active */
|
||||
sleep_manager_lock_deep_sleep();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
obj->serial.rxstate = kUART_RxBusy;
|
||||
|
||||
/* Start the transfer */
|
||||
serial_receive_asynch(obj);
|
||||
|
||||
/* Can't enter deep sleep as long as UART transfer is active */
|
||||
sleep_manager_lock_deep_sleep();
|
||||
}
|
||||
|
||||
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;
|
||||
/* Transmit is complete, re-enable entry to deep sleep mode */
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
|
||||
if ((obj->serial.rxstate != kUART_RxIdle) && (obj->serial.uart_dma_handle.rxState == kUART_RxIdle)) {
|
||||
obj->serial.rxstate = kUART_RxIdle;
|
||||
status |= SERIAL_EVENT_RX_COMPLETE;
|
||||
/* Receive is complete, re-enable entry to deep sleep mode */
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* Transmit is complete, re-enable entry to deep sleep mode */
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
|
||||
if ((obj->serial.rxstate != kUART_RxIdle) && (obj->serial.uart_transfer_handle.rxState == kUART_RxIdle)) {
|
||||
obj->serial.rxstate = kUART_RxIdle;
|
||||
status |= SERIAL_EVENT_RX_COMPLETE;
|
||||
/* Receive is complete, re-enable entry to deep sleep mode */
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
}
|
||||
#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 we're not currently transferring, then there's nothing to do here
|
||||
if (serial_tx_active(obj) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
obj->serial.txstate = kUART_TxIdle;
|
||||
|
||||
/* Re-enable entry to deep sleep mode */
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
|
||||
void serial_rx_abort_asynch(serial_t *obj)
|
||||
{
|
||||
// If we're not currently transferring, then there's nothing to do here
|
||||
if (serial_rx_active(obj) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
obj->serial.rxstate = kUART_RxIdle;
|
||||
|
||||
/* Re-enable entry to deep sleep mode */
|
||||
sleep_manager_unlock_deep_sleep();
|
||||
}
|
||||
|
||||
static int serial_is_enabled(uint32_t uart_index)
|
||||
{
|
||||
int clock_enabled = 0;
|
||||
|
|
|
@ -1817,6 +1817,7 @@
|
|||
"PWMOUT",
|
||||
"SERIAL",
|
||||
"SERIAL_FC",
|
||||
"SERIAL_ASYNCH",
|
||||
"SLEEP",
|
||||
"SPI",
|
||||
"SPISLAVE",
|
||||
|
|
Loading…
Reference in New Issue