Enable async serial for K66F

Added DMA definitions and usage for UART, based on K64F's code.
pull/11443/head
Michal Paszta 2019-09-09 08:03:26 +03:00
parent 1800632655
commit 551bc8a1f5
3 changed files with 543 additions and 62 deletions

View File

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

View File

@ -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;

View File

@ -1817,6 +1817,7 @@
"PWMOUT",
"SERIAL",
"SERIAL_FC",
"SERIAL_ASYNCH",
"SLEEP",
"SPI",
"SPISLAVE",