mirror of https://github.com/ARMmbed/mbed-os.git
SiLabs: serial_api: Keep track of sleep mode changes
Keep a counter of sleeps blocked for every device, and do not try to unblock sleep modes we did not block. This fixes problems where serial events would cause EM1/EM2 to be unblocked too early, causing the MCU to go to EM3 and not being able to wake up.pull/1501/head
parent
1c47e974ff
commit
a6e137f188
|
@ -99,6 +99,8 @@ static CMU_Clock_TypeDef serial_get_clock(serial_t *obj);
|
|||
static void serial_dmaSetupChannel(serial_t *obj, bool tx_nrx);
|
||||
static void serial_rx_abort_asynch_intern(serial_t *obj, int unblock_sleep);
|
||||
static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep);
|
||||
static void serial_block_sleep(serial_t *obj);
|
||||
static void serial_unblock_sleep(serial_t *obj);
|
||||
|
||||
/* ISRs for RX and TX events */
|
||||
#ifdef UART0
|
||||
|
@ -756,6 +758,11 @@ static void serial_switch_to_usart(serial_t *obj, int baudrate)
|
|||
|
||||
/* TODO: disable clocks? */
|
||||
|
||||
/* Disable sleep */
|
||||
uint32_t sleep_count = obj->serial.sleep_blocked;
|
||||
while( obj->serial.sleep_blocked > 0 )
|
||||
serial_unblock_sleep(obj);
|
||||
|
||||
SerialParity par = ParityNone;
|
||||
switch( parity ) {
|
||||
case LEUART_CTRL_PARITY_NONE: par = ParityNone; break;
|
||||
|
@ -792,6 +799,10 @@ static void serial_switch_to_usart(serial_t *obj, int baudrate)
|
|||
serial_uart_free(leuart);
|
||||
serial_enable(obj, true);
|
||||
|
||||
/* Restore sleep */
|
||||
while( obj->serial.sleep_blocked < sleep_count )
|
||||
serial_block_sleep(obj);
|
||||
|
||||
/* Restore interrupts */
|
||||
serial_irq_ids[serial_get_index(obj)] = irq_id;
|
||||
|
||||
|
@ -1708,15 +1719,7 @@ int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx
|
|||
serial_tx_enable_event(obj, event, true);
|
||||
|
||||
// Set up sleepmode
|
||||
#ifdef LEUART_USING_LFXO
|
||||
if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){
|
||||
blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART);
|
||||
}else{
|
||||
blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
||||
}
|
||||
#else
|
||||
blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
||||
#endif
|
||||
serial_block_sleep(obj);
|
||||
|
||||
// Determine DMA strategy
|
||||
serial_dmaTrySetState(&(obj->serial.dmaOptionsTX), hint, obj, true);
|
||||
|
@ -1788,15 +1791,7 @@ void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_widt
|
|||
obj->char_match = char_match;
|
||||
|
||||
// Set up sleepmode
|
||||
#ifdef LEUART_USING_LFXO
|
||||
if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){
|
||||
blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART);
|
||||
}else{
|
||||
blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
||||
}
|
||||
#else
|
||||
blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
||||
#endif
|
||||
serial_block_sleep(obj);
|
||||
|
||||
// Determine DMA strategy
|
||||
// If character match is enabled, we can't use DMA, sadly. We could when using LEUART though, but that support is not in here yet.
|
||||
|
@ -2201,7 +2196,14 @@ static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep)
|
|||
}
|
||||
|
||||
/* Say that we can stop using this emode */
|
||||
if( unblock_sleep ) {
|
||||
if(unblock_sleep)
|
||||
serial_unblock_sleep(obj);
|
||||
}
|
||||
|
||||
|
||||
static void serial_unblock_sleep(serial_t *obj)
|
||||
{
|
||||
if( obj->serial.sleep_blocked > 0 ) {
|
||||
#ifdef LEUART_USING_LFXO
|
||||
if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){
|
||||
unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART);
|
||||
|
@ -2211,9 +2213,24 @@ static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep)
|
|||
#else
|
||||
unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
||||
#endif
|
||||
obj->serial.sleep_blocked--;
|
||||
}
|
||||
}
|
||||
|
||||
static void serial_block_sleep(serial_t *obj)
|
||||
{
|
||||
obj->serial.sleep_blocked++;
|
||||
#ifdef LEUART_USING_LFXO
|
||||
if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){
|
||||
blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART);
|
||||
}else{
|
||||
blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
||||
}
|
||||
#else
|
||||
blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Abort the ongoing RX transaction It disables the enabled interrupt for RX and
|
||||
* flush RX hardware buffer if RX FIFO is used
|
||||
*
|
||||
|
@ -2273,17 +2290,8 @@ static void serial_rx_abort_asynch_intern(serial_t *obj, int unblock_sleep)
|
|||
}
|
||||
|
||||
/* Say that we can stop using this emode */
|
||||
if( unblock_sleep ) {
|
||||
#ifdef LEUART_USING_LFXO
|
||||
if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){
|
||||
unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART);
|
||||
}else{
|
||||
unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
||||
}
|
||||
#else
|
||||
unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
||||
#endif
|
||||
}
|
||||
if( unblock_sleep )
|
||||
serial_unblock_sleep(obj);
|
||||
}
|
||||
|
||||
#endif //DEVICE_SERIAL_ASYNCH
|
||||
|
|
Loading…
Reference in New Issue