Skip to content

Commit 2203549

Browse files
authored
Merge pull request #10924 from ghseb/free-serial-resources-2
Free serial resources if not needed anymore
2 parents a072866 + df2cfae commit 2203549

File tree

8 files changed

+202
-45
lines changed

8 files changed

+202
-45
lines changed

UNITTESTS/stubs/SerialBase_stub.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919

2020
namespace mbed {
2121

22-
SerialBase::SerialBase(PinName tx, PinName rx, int baud)
22+
SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
23+
_tx_pin(tx), _rx_pin(rx)
2324
{
2425
}
2526

drivers/SerialBase.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,30 @@ class SerialBase : private NonCopyable<SerialBase> {
155155
*/
156156
void send_break();
157157

158+
/** Enable serial input
159+
*
160+
* If both serial input and serial output are disabled, the
161+
* peripheral is freed. If either serial input or serial
162+
* output is re-enabled, the peripheral is reinitialized.
163+
*
164+
* On re-initialization rx interrupts will be enabled if a
165+
* rx handler is attached. The rx handler is called once
166+
* during re-initialization.
167+
*/
168+
void enable_input(bool enable = true);
169+
170+
/** Enable serial output
171+
*
172+
* If both serial input and serial output are disabled, the
173+
* peripheral is freed. If either serial input or serial
174+
* output is re-enabled, the peripheral is reinitialized.
175+
*
176+
* On re-initialization tx interrupts will be enabled if a
177+
* tx handler is attached. The tx handler is called once
178+
* during re-initialization.
179+
*/
180+
void enable_output(bool enable = true);
181+
158182
#if !defined(DOXYGEN_ONLY)
159183
protected:
160184

@@ -295,6 +319,14 @@ class SerialBase : private NonCopyable<SerialBase> {
295319

296320
int _base_putc(int c);
297321

322+
/** Initialize serial port
323+
*/
324+
void _init();
325+
326+
/** Deinitialize serial port
327+
*/
328+
void _deinit();
329+
298330
#if DEVICE_SERIAL_ASYNCH
299331
CThunk<SerialBase> _thunk_irq;
300332
DMAUsage _tx_usage;
@@ -308,6 +340,17 @@ class SerialBase : private NonCopyable<SerialBase> {
308340
serial_t _serial;
309341
Callback<void()> _irq[IrqCnt];
310342
int _baud;
343+
bool _rx_enabled;
344+
bool _tx_enabled;
345+
const PinName _tx_pin;
346+
const PinName _rx_pin;
347+
348+
#if DEVICE_SERIAL_FC
349+
Flow _flow_type;
350+
PinName _flow1;
351+
PinName _flow2;
352+
#endif
353+
311354
#endif
312355
};
313356

drivers/source/SerialBase.cpp

Lines changed: 126 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,25 @@ SerialBase::SerialBase(PinName tx, PinName rx, int baud) :
3030
_rx_callback(NULL), _tx_asynch_set(false),
3131
_rx_asynch_set(false),
3232
#endif
33-
_serial(), _baud(baud)
33+
_serial(),
34+
_baud(baud),
35+
#if DEVICE_SERIAL_FC
36+
_flow_type(Disabled),
37+
_flow1(NC),
38+
_flow2(NC),
39+
#endif
40+
_rx_enabled(true),
41+
_tx_enabled(true),
42+
_tx_pin(tx),
43+
_rx_pin(rx)
3444
{
3545
// No lock needed in the constructor
3646

3747
for (size_t i = 0; i < sizeof _irq / sizeof _irq[0]; i++) {
3848
_irq[i] = NULL;
3949
}
4050

41-
serial_init(&_serial, tx, rx);
42-
serial_baud(&_serial, _baud);
43-
serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this);
51+
_init();
4452
}
4553

4654
void SerialBase::baud(int baudrate)
@@ -78,24 +86,30 @@ int SerialBase::writeable()
7886
void SerialBase::attach(Callback<void()> func, IrqType type)
7987
{
8088
lock();
81-
// Disable interrupts when attaching interrupt handler
82-
core_util_critical_section_enter();
83-
if (func) {
84-
// lock deep sleep only the first time
85-
if (!_irq[type]) {
86-
sleep_manager_lock_deep_sleep();
87-
}
89+
const bool enabled { (_rx_enabled &&(type == RxIrq)) || (_tx_enabled &&(type == TxIrq)) };
90+
// If corresponding direction is not enabled only update the handler
91+
if (!enabled) {
8892
_irq[type] = func;
89-
serial_irq_set(&_serial, (SerialIrq)type, 1);
9093
} else {
91-
// unlock deep sleep only the first time
92-
if (_irq[type]) {
93-
sleep_manager_unlock_deep_sleep();
94+
// Disable interrupts when attaching interrupt handler
95+
core_util_critical_section_enter();
96+
if (func) {
97+
// lock deep sleep only the first time
98+
if (!_irq[type]) {
99+
sleep_manager_lock_deep_sleep();
100+
}
101+
_irq[type] = func;
102+
serial_irq_set(&_serial, (SerialIrq)type, 1);
103+
} else {
104+
// unlock deep sleep only the first time
105+
if (_irq[type]) {
106+
sleep_manager_unlock_deep_sleep();
107+
}
108+
_irq[type] = NULL;
109+
serial_irq_set(&_serial, (SerialIrq)type, 0);
94110
}
95-
_irq[type] = NULL;
96-
serial_irq_set(&_serial, (SerialIrq)type, 0);
111+
core_util_critical_section_exit();
97112
}
98-
core_util_critical_section_exit();
99113
unlock();
100114
}
101115

@@ -120,6 +134,95 @@ int SerialBase::_base_putc(int c)
120134
return c;
121135
}
122136

137+
void SerialBase::_init()
138+
{
139+
serial_init(&_serial, _tx_pin, _rx_pin);
140+
#if DEVICE_SERIAL_FC
141+
set_flow_control(_flow_type, _flow1, _flow2);
142+
#endif
143+
serial_baud(&_serial, _baud);
144+
serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this);
145+
}
146+
147+
void SerialBase::_deinit()
148+
{
149+
serial_free(&_serial);
150+
}
151+
152+
void SerialBase::enable_input(bool enable)
153+
{
154+
lock();
155+
if (_rx_enabled != enable) {
156+
if (enable && !_tx_enabled) {
157+
_init();
158+
}
159+
160+
core_util_critical_section_enter();
161+
if (enable) {
162+
// Enable rx IRQ and lock deep sleep if a rx handler is attached
163+
// (indicated by rx IRQ callback not NULL)
164+
if (_irq[RxIrq]) {
165+
_irq[RxIrq].call();
166+
sleep_manager_lock_deep_sleep();
167+
serial_irq_set(&_serial, (SerialIrq)RxIrq, 1);
168+
}
169+
} else {
170+
// Disable rx IRQ
171+
serial_irq_set(&_serial, (SerialIrq)RxIrq, 0);
172+
// Unlock deep sleep if a rx handler is attached
173+
// (indicated by rx IRQ callback not NULL)
174+
if (_irq[RxIrq]) {
175+
sleep_manager_unlock_deep_sleep();
176+
}
177+
}
178+
core_util_critical_section_exit();
179+
180+
_rx_enabled = enable;
181+
182+
if (!enable && !_tx_enabled) {
183+
_deinit();
184+
}
185+
}
186+
unlock();
187+
}
188+
189+
void SerialBase::enable_output(bool enable)
190+
{
191+
lock();
192+
if (_tx_enabled != enable) {
193+
if (enable && !_rx_enabled) {
194+
_init();
195+
}
196+
197+
core_util_critical_section_enter();
198+
if (enable) {
199+
// Enable tx IRQ and lock deep sleep if a tx handler is attached
200+
// (indicated by tx IRQ callback not NULL)
201+
if (_irq[TxIrq]) {
202+
_irq[TxIrq].call();
203+
sleep_manager_lock_deep_sleep();
204+
serial_irq_set(&_serial, (SerialIrq)TxIrq, 1);
205+
}
206+
} else {
207+
// Disable tx IRQ
208+
serial_irq_set(&_serial, (SerialIrq)TxIrq, 0);
209+
// Unlock deep sleep if a tx handler is attached
210+
// (indicated by tx IRQ callback not NULL)
211+
if (_irq[TxIrq]) {
212+
sleep_manager_unlock_deep_sleep();
213+
}
214+
}
215+
core_util_critical_section_exit();
216+
217+
_tx_enabled = enable;
218+
219+
if (!enable && !_rx_enabled) {
220+
_deinit();
221+
}
222+
}
223+
unlock();
224+
}
225+
123226
void SerialBase::set_break()
124227
{
125228
lock();
@@ -175,6 +278,11 @@ SerialBase::~SerialBase()
175278
void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2)
176279
{
177280
lock();
281+
282+
_flow_type = type;
283+
_flow1 = flow1;
284+
_flow2 = flow2;
285+
178286
FlowControl flow_type = (FlowControl)type;
179287
switch (type) {
180288
case RTS:

drivers/source/UARTSerial.cpp

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -366,38 +366,18 @@ void UARTSerial::disable_tx_irq()
366366

367367
int UARTSerial::enable_input(bool enabled)
368368
{
369-
core_util_critical_section_enter();
370-
if (_rx_enabled != enabled) {
371-
if (enabled) {
372-
UARTSerial::rx_irq();
373-
if (!_rxbuf.full()) {
374-
enable_rx_irq();
375-
}
376-
} else {
377-
disable_rx_irq();
378-
}
379-
_rx_enabled = enabled;
380-
}
381-
core_util_critical_section_exit();
369+
api_lock();
370+
SerialBase::enable_input(enabled);
371+
api_unlock();
382372

383373
return 0;
384374
}
385375

386376
int UARTSerial::enable_output(bool enabled)
387377
{
388-
core_util_critical_section_enter();
389-
if (_tx_enabled != enabled) {
390-
if (enabled) {
391-
UARTSerial::tx_irq();
392-
if (!_txbuf.empty()) {
393-
enable_tx_irq();
394-
}
395-
} else {
396-
disable_tx_irq();
397-
}
398-
_tx_enabled = enabled;
399-
}
400-
core_util_critical_section_exit();
378+
api_lock();
379+
SerialBase::enable_output(enabled);
380+
api_unlock();
401381

402382
return 0;
403383
}

targets/TARGET_Maxim/TARGET_MAX32600/serial_api.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
9696
}
9797
}
9898

99+
//******************************************************************************
100+
void serial_free(serial_t *obj)
101+
{
102+
serial_irq_ids[obj->index];
103+
}
104+
99105
//******************************************************************************
100106
void serial_baud(serial_t *obj, int baudrate)
101107
{

targets/TARGET_Maxim/TARGET_MAX32620C/serial_api.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,3 +418,8 @@ const PinMap *serial_rts_pinmap()
418418
{
419419
return PinMap_UART_RTS;
420420
}
421+
422+
void serial_free(serial_t *obj)
423+
{
424+
// Not implemented
425+
}

targets/TARGET_Maxim/TARGET_MAX32625/serial_api.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
115115
MBED_ASSERT(retval == E_NO_ERROR);
116116
}
117117

118+
//******************************************************************************
119+
void serial_free(serial_t *obj)
120+
{
121+
UART_Shutdown(obj->uart);
122+
objs[obj->index] = 0;
123+
}
124+
118125
//******************************************************************************
119126
void serial_baud(serial_t *obj, int baudrate)
120127
{

targets/TARGET_Maxim/TARGET_MAX32630/serial_api.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
115115
MBED_ASSERT(retval == E_NO_ERROR);
116116
}
117117

118+
//******************************************************************************
119+
void serial_free(serial_t *obj)
120+
{
121+
UART_Shutdown(obj->uart);
122+
objs[obj->index] = 0;
123+
}
124+
118125
//******************************************************************************
119126
void serial_baud(serial_t *obj, int baudrate)
120127
{

0 commit comments

Comments
 (0)