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 { 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(); 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) #if !defined(DOXYGEN_ONLY)
protected: protected:
@ -295,6 +319,14 @@ protected:
int _base_putc(int c); int _base_putc(int c);
/** Initialize serial port
*/
void _init();
/** Deinitialize serial port
*/
void _deinit();
#if DEVICE_SERIAL_ASYNCH #if DEVICE_SERIAL_ASYNCH
CThunk<SerialBase> _thunk_irq; CThunk<SerialBase> _thunk_irq;
DMAUsage _tx_usage; DMAUsage _tx_usage;
@ -308,6 +340,17 @@ protected:
serial_t _serial; serial_t _serial;
Callback<void()> _irq[IrqCnt]; Callback<void()> _irq[IrqCnt];
int _baud; 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 #endif
}; };

View File

@ -30,7 +30,17 @@ SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
_rx_callback(NULL), _tx_asynch_set(false), _rx_callback(NULL), _tx_asynch_set(false),
_rx_asynch_set(false), _rx_asynch_set(false),
#endif #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 // No lock needed in the constructor
@ -38,9 +48,7 @@ SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
_irq[i] = NULL; _irq[i] = NULL;
} }
serial_init(&_serial, tx, rx); _init();
serial_baud(&_serial, _baud);
serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this);
} }
void SerialBase::baud(int baudrate) void SerialBase::baud(int baudrate)
@ -78,6 +86,11 @@ int SerialBase::writeable()
void SerialBase::attach(Callback<void()> func, IrqType type) void SerialBase::attach(Callback<void()> func, IrqType type)
{ {
lock(); 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 // Disable interrupts when attaching interrupt handler
core_util_critical_section_enter(); core_util_critical_section_enter();
if (func) { if (func) {
@ -96,6 +109,7 @@ void SerialBase::attach(Callback<void()> func, IrqType type)
serial_irq_set(&_serial, (SerialIrq)type, 0); serial_irq_set(&_serial, (SerialIrq)type, 0);
} }
core_util_critical_section_exit(); core_util_critical_section_exit();
}
unlock(); unlock();
} }
@ -120,6 +134,95 @@ int SerialBase::_base_putc(int c)
return 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() void SerialBase::set_break()
{ {
lock(); lock();
@ -175,6 +278,11 @@ SerialBase::~SerialBase()
void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2)
{ {
lock(); lock();
_flow_type = type;
_flow1 = flow1;
_flow2 = flow2;
FlowControl flow_type = (FlowControl)type; FlowControl flow_type = (FlowControl)type;
switch (type) { switch (type) {
case RTS: case RTS:

View File

@ -366,38 +366,18 @@ void UARTSerial::disable_tx_irq()
int UARTSerial::enable_input(bool enabled) int UARTSerial::enable_input(bool enabled)
{ {
core_util_critical_section_enter(); api_lock();
if (_rx_enabled != enabled) { SerialBase::enable_input(enabled);
if (enabled) { api_unlock();
UARTSerial::rx_irq();
if (!_rxbuf.full()) {
enable_rx_irq();
}
} else {
disable_rx_irq();
}
_rx_enabled = enabled;
}
core_util_critical_section_exit();
return 0; return 0;
} }
int UARTSerial::enable_output(bool enabled) int UARTSerial::enable_output(bool enabled)
{ {
core_util_critical_section_enter(); api_lock();
if (_tx_enabled != enabled) { SerialBase::enable_output(enabled);
if (enabled) { api_unlock();
UARTSerial::tx_irq();
if (!_txbuf.empty()) {
enable_tx_irq();
}
} else {
disable_tx_irq();
}
_tx_enabled = enabled;
}
core_util_critical_section_exit();
return 0; 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) void serial_baud(serial_t *obj, int baudrate)
{ {

View File

@ -418,3 +418,8 @@ const PinMap *serial_rts_pinmap()
{ {
return PinMap_UART_RTS; 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); 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) 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); 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) void serial_baud(serial_t *obj, int baudrate)
{ {