Merge pull request #10924 from ghseb/free-serial-resources-2

Free serial resources if not needed anymore
pull/11775/head
Martin Kojtal 2019-10-30 09:45:22 +01:00 committed by GitHub
commit 2203549b37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 202 additions and 45 deletions

View File

@ -19,7 +19,8 @@
namespace mbed {
SerialBase::SerialBase(PinName tx, PinName rx, int baud)
SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
_tx_pin(tx), _rx_pin(rx)
{
}

View File

@ -155,6 +155,30 @@ public:
*/
void send_break();
/** Enable serial input
*
* If both serial input and serial output are disabled, the
* peripheral is freed. If either serial input or serial
* output is re-enabled, the peripheral is reinitialized.
*
* On re-initialization rx interrupts will be enabled if a
* rx handler is attached. The rx handler is called once
* during re-initialization.
*/
void enable_input(bool enable = true);
/** Enable serial output
*
* If both serial input and serial output are disabled, the
* peripheral is freed. If either serial input or serial
* output is re-enabled, the peripheral is reinitialized.
*
* On re-initialization tx interrupts will be enabled if a
* tx handler is attached. The tx handler is called once
* during re-initialization.
*/
void enable_output(bool enable = true);
#if !defined(DOXYGEN_ONLY)
protected:
@ -295,6 +319,14 @@ protected:
int _base_putc(int c);
/** Initialize serial port
*/
void _init();
/** Deinitialize serial port
*/
void _deinit();
#if DEVICE_SERIAL_ASYNCH
CThunk<SerialBase> _thunk_irq;
DMAUsage _tx_usage;
@ -308,6 +340,17 @@ protected:
serial_t _serial;
Callback<void()> _irq[IrqCnt];
int _baud;
bool _rx_enabled;
bool _tx_enabled;
const PinName _tx_pin;
const PinName _rx_pin;
#if DEVICE_SERIAL_FC
Flow _flow_type;
PinName _flow1;
PinName _flow2;
#endif
#endif
};

View File

@ -30,7 +30,17 @@ SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
_rx_callback(NULL), _tx_asynch_set(false),
_rx_asynch_set(false),
#endif
_serial(), _baud(baud)
_serial(),
_baud(baud),
#if DEVICE_SERIAL_FC
_flow_type(Disabled),
_flow1(NC),
_flow2(NC),
#endif
_rx_enabled(true),
_tx_enabled(true),
_tx_pin(tx),
_rx_pin(rx)
{
// No lock needed in the constructor
@ -38,9 +48,7 @@ SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
_irq[i] = NULL;
}
serial_init(&_serial, tx, rx);
serial_baud(&_serial, _baud);
serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this);
_init();
}
void SerialBase::baud(int baudrate)
@ -78,6 +86,11 @@ int SerialBase::writeable()
void SerialBase::attach(Callback<void()> func, IrqType type)
{
lock();
const bool enabled { (_rx_enabled &&(type == RxIrq)) || (_tx_enabled &&(type == TxIrq)) };
// If corresponding direction is not enabled only update the handler
if (!enabled) {
_irq[type] = func;
} else {
// Disable interrupts when attaching interrupt handler
core_util_critical_section_enter();
if (func) {
@ -96,6 +109,7 @@ void SerialBase::attach(Callback<void()> func, IrqType type)
serial_irq_set(&_serial, (SerialIrq)type, 0);
}
core_util_critical_section_exit();
}
unlock();
}
@ -120,6 +134,95 @@ int SerialBase::_base_putc(int c)
return c;
}
void SerialBase::_init()
{
serial_init(&_serial, _tx_pin, _rx_pin);
#if DEVICE_SERIAL_FC
set_flow_control(_flow_type, _flow1, _flow2);
#endif
serial_baud(&_serial, _baud);
serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this);
}
void SerialBase::_deinit()
{
serial_free(&_serial);
}
void SerialBase::enable_input(bool enable)
{
lock();
if (_rx_enabled != enable) {
if (enable && !_tx_enabled) {
_init();
}
core_util_critical_section_enter();
if (enable) {
// Enable rx IRQ and lock deep sleep if a rx handler is attached
// (indicated by rx IRQ callback not NULL)
if (_irq[RxIrq]) {
_irq[RxIrq].call();
sleep_manager_lock_deep_sleep();
serial_irq_set(&_serial, (SerialIrq)RxIrq, 1);
}
} else {
// Disable rx IRQ
serial_irq_set(&_serial, (SerialIrq)RxIrq, 0);
// Unlock deep sleep if a rx handler is attached
// (indicated by rx IRQ callback not NULL)
if (_irq[RxIrq]) {
sleep_manager_unlock_deep_sleep();
}
}
core_util_critical_section_exit();
_rx_enabled = enable;
if (!enable && !_tx_enabled) {
_deinit();
}
}
unlock();
}
void SerialBase::enable_output(bool enable)
{
lock();
if (_tx_enabled != enable) {
if (enable && !_rx_enabled) {
_init();
}
core_util_critical_section_enter();
if (enable) {
// Enable tx IRQ and lock deep sleep if a tx handler is attached
// (indicated by tx IRQ callback not NULL)
if (_irq[TxIrq]) {
_irq[TxIrq].call();
sleep_manager_lock_deep_sleep();
serial_irq_set(&_serial, (SerialIrq)TxIrq, 1);
}
} else {
// Disable tx IRQ
serial_irq_set(&_serial, (SerialIrq)TxIrq, 0);
// Unlock deep sleep if a tx handler is attached
// (indicated by tx IRQ callback not NULL)
if (_irq[TxIrq]) {
sleep_manager_unlock_deep_sleep();
}
}
core_util_critical_section_exit();
_tx_enabled = enable;
if (!enable && !_rx_enabled) {
_deinit();
}
}
unlock();
}
void SerialBase::set_break()
{
lock();
@ -175,6 +278,11 @@ SerialBase::~SerialBase()
void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2)
{
lock();
_flow_type = type;
_flow1 = flow1;
_flow2 = flow2;
FlowControl flow_type = (FlowControl)type;
switch (type) {
case RTS:

View File

@ -366,38 +366,18 @@ void UARTSerial::disable_tx_irq()
int UARTSerial::enable_input(bool enabled)
{
core_util_critical_section_enter();
if (_rx_enabled != enabled) {
if (enabled) {
UARTSerial::rx_irq();
if (!_rxbuf.full()) {
enable_rx_irq();
}
} else {
disable_rx_irq();
}
_rx_enabled = enabled;
}
core_util_critical_section_exit();
api_lock();
SerialBase::enable_input(enabled);
api_unlock();
return 0;
}
int UARTSerial::enable_output(bool enabled)
{
core_util_critical_section_enter();
if (_tx_enabled != enabled) {
if (enabled) {
UARTSerial::tx_irq();
if (!_txbuf.empty()) {
enable_tx_irq();
}
} else {
disable_tx_irq();
}
_tx_enabled = enabled;
}
core_util_critical_section_exit();
api_lock();
SerialBase::enable_output(enabled);
api_unlock();
return 0;
}

View File

@ -96,6 +96,12 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
}
}
//******************************************************************************
void serial_free(serial_t *obj)
{
serial_irq_ids[obj->index];
}
//******************************************************************************
void serial_baud(serial_t *obj, int baudrate)
{

View File

@ -418,3 +418,8 @@ const PinMap *serial_rts_pinmap()
{
return PinMap_UART_RTS;
}
void serial_free(serial_t *obj)
{
// Not implemented
}

View File

@ -115,6 +115,13 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
MBED_ASSERT(retval == E_NO_ERROR);
}
//******************************************************************************
void serial_free(serial_t *obj)
{
UART_Shutdown(obj->uart);
objs[obj->index] = 0;
}
//******************************************************************************
void serial_baud(serial_t *obj, int baudrate)
{

View File

@ -115,6 +115,13 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
MBED_ASSERT(retval == E_NO_ERROR);
}
//******************************************************************************
void serial_free(serial_t *obj)
{
UART_Shutdown(obj->uart);
objs[obj->index] = 0;
}
//******************************************************************************
void serial_baud(serial_t *obj, int baudrate)
{