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/1500/head
parent
0cf5279356
commit
49f6313007
|
@ -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_dmaSetupChannel(serial_t *obj, bool tx_nrx);
|
||||||
static void serial_rx_abort_asynch_intern(serial_t *obj, int unblock_sleep);
|
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_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 */
|
/* ISRs for RX and TX events */
|
||||||
#ifdef UART0
|
#ifdef UART0
|
||||||
|
@ -756,6 +758,11 @@ static void serial_switch_to_usart(serial_t *obj, int baudrate)
|
||||||
|
|
||||||
/* TODO: disable clocks? */
|
/* 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;
|
SerialParity par = ParityNone;
|
||||||
switch( parity ) {
|
switch( parity ) {
|
||||||
case LEUART_CTRL_PARITY_NONE: par = ParityNone; break;
|
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_uart_free(leuart);
|
||||||
serial_enable(obj, true);
|
serial_enable(obj, true);
|
||||||
|
|
||||||
|
/* Restore sleep */
|
||||||
|
while( obj->serial.sleep_blocked < sleep_count )
|
||||||
|
serial_block_sleep(obj);
|
||||||
|
|
||||||
/* Restore interrupts */
|
/* Restore interrupts */
|
||||||
serial_irq_ids[serial_get_index(obj)] = irq_id;
|
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);
|
serial_tx_enable_event(obj, event, true);
|
||||||
|
|
||||||
// Set up sleepmode
|
// Set up sleepmode
|
||||||
#ifdef LEUART_USING_LFXO
|
serial_block_sleep(obj);
|
||||||
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
|
|
||||||
|
|
||||||
// Determine DMA strategy
|
// Determine DMA strategy
|
||||||
serial_dmaTrySetState(&(obj->serial.dmaOptionsTX), hint, obj, true);
|
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;
|
obj->char_match = char_match;
|
||||||
|
|
||||||
// Set up sleepmode
|
// Set up sleepmode
|
||||||
#ifdef LEUART_USING_LFXO
|
serial_block_sleep(obj);
|
||||||
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
|
|
||||||
|
|
||||||
// Determine DMA strategy
|
// 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.
|
// 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 */
|
/* 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
|
#ifdef LEUART_USING_LFXO
|
||||||
if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){
|
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);
|
unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART);
|
||||||
|
@ -2211,9 +2213,24 @@ static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep)
|
||||||
#else
|
#else
|
||||||
unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE);
|
||||||
#endif
|
#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
|
/** Abort the ongoing RX transaction It disables the enabled interrupt for RX and
|
||||||
* flush RX hardware buffer if RX FIFO is used
|
* 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 */
|
/* Say that we can stop using this emode */
|
||||||
if( unblock_sleep ) {
|
if( unblock_sleep )
|
||||||
#ifdef LEUART_USING_LFXO
|
serial_unblock_sleep(obj);
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //DEVICE_SERIAL_ASYNCH
|
#endif //DEVICE_SERIAL_ASYNCH
|
||||||
|
|
Loading…
Reference in New Issue