Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STM32: check for UART ongoing transfers before entering deepsleep #7717

Merged
merged 2 commits into from
Aug 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions targets/TARGET_STM/TARGET_STM32F0/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@
#define DEVICE_ID_LENGTH 24

#include "objects.h"
/* WORKAROUND waiting for mbed-os issue 4408 to be addressed */
#include "stm32f0xx_ll_usart.h"

#endif
2 changes: 2 additions & 0 deletions targets/TARGET_STM/TARGET_STM32F1/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@
#define DEVICE_ID_LENGTH 24

#include "objects.h"
/* WORKAROUND waiting for mbed-os issue 4408 to be addressed */
#include "stm32f1xx_ll_usart.h"

#endif
2 changes: 2 additions & 0 deletions targets/TARGET_STM/TARGET_STM32F2/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@
#define DEVICE_ID_LENGTH 24

#include "objects.h"
/* WORKAROUND waiting for mbed-os issue 4408 to be addressed */
#include "stm32f2xx_ll_usart.h"

#endif
2 changes: 2 additions & 0 deletions targets/TARGET_STM/TARGET_STM32F3/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@
#define DEVICE_ID_LENGTH 24

#include "objects.h"
/* WORKAROUND waiting for mbed-os issue 4408 to be addressed */
#include "stm32f3xx_ll_usart.h"

#endif
2 changes: 2 additions & 0 deletions targets/TARGET_STM/TARGET_STM32F4/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@
#define DEVICE_ID_LENGTH 24

#include "objects.h"
/* WORKAROUND waiting for mbed-os issue 4408 to be addressed */
#include "stm32f4xx_ll_usart.h"

#endif
2 changes: 2 additions & 0 deletions targets/TARGET_STM/TARGET_STM32F7/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@
#define DEVICE_ID_LENGTH 24

#include "objects.h"
/* WORKAROUND waiting for mbed-os issue 4408 to be addressed */
#include "stm32f7xx_ll_usart.h"

#endif
2 changes: 2 additions & 0 deletions targets/TARGET_STM/TARGET_STM32L0/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@
#define DEVICE_ID_LENGTH 24

#include "objects.h"
/* WORKAROUND waiting for mbed-os issue 4408 to be addressed */
#include "stm32l0xx_ll_usart.h"

#endif
2 changes: 2 additions & 0 deletions targets/TARGET_STM/TARGET_STM32L1/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@
#define DEVICE_ID_LENGTH 24

#include "objects.h"
/* WORKAROUND waiting for mbed-os issue 4408 to be addressed */
#include "stm32l1xx_ll_usart.h"

#endif
2 changes: 2 additions & 0 deletions targets/TARGET_STM/TARGET_STM32L4/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@
#define DEVICE_ID_LENGTH 24

#include "objects.h"
/* WORKAROUND waiting for mbed-os issue 4408 to be addressed */
#include "stm32l4xx_ll_usart.h"

#endif
101 changes: 101 additions & 0 deletions targets/TARGET_STM/serial_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -690,4 +690,105 @@ int8_t get_uart_index(UARTName uart_name)
return -1;
}

/* Function to protect deep sleep while a seral Tx is ongoing on not complete
* yet. Returns 1 if there is at least 1 serial instance with ongoing ransfer
* 0 otherwise.
*/
int serial_is_tx_ongoing(void) {
int TxOngoing = 0;

#if defined(USART1_BASE)
if (LL_USART_IsEnabled(USART1) && !LL_USART_IsActiveFlag_TC(USART1)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When serial is first enabled is the TC flag set, or does a transfer actually have to complete for this to be set? If it isn't set then UARTs which are only read from will block deep sleep all the time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm ... Reset value of TC flag is 1. It is set to 0 in case there is a new TX byte or in case it is explicitly cleared by software - which could be the case in serial ASYNCH mode ...
So Maybe I need a specific logic for Asynch ... but for UARTs that are only read, that should be fine.

Extract from spec:

Interrupt and status register (USARTx_ISR)
Address offset: 0x1C
Reset value: 0x0200 00C0
[...]
Bit 6 TC: Transmission complete
This bit is set by hardware if the transmission of a frame containing data is complete and if
TXE is set. An interrupt is generated if TCIE=1 in the USARTx_CR1 register. It is cleared by
software, writing 1 to the TCCF in the USARTx_ICR register or by a write to the
USARTx_TDR register.
An interrupt is generated if TCIE=1 in the USARTx_CR1 register.
0: Transmission is not complete
1: Transmission is complete
Note:If TE bit is reset and no transmission is on going, the TC bit will be set immediately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that in case of asynch I would expect the application or driver using this mode to be in charge of locking deep sleep until Tx is complete - don't you think ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking at the datasheet for the F429 which appears to have different behavior. The transfer complete check may need to be different for each family.

image

Bit 6 TC: Transmission complete
This bit is set by hardware if the transmission of a frame containing data is complete and if
TXE is set. An interrupt is generated if TCIE=1 in the USART_CR1 register. It is cleared by
a software sequence (a read from the USART_SR register followed by a write to the
USART_DR register). The TC bit can also be cleared by writing a '0' to it. This clearing
sequence is recommended only for multibuffer communication.
0: Transmission is not complete
1: Transmission is complete

Copy link
Contributor Author

@LMESTM LMESTM Aug 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you've got an old spec. In recent one (rev17), the reset value is 0xC0

https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf

Also I've just done tests (on NUCLEO_F429ZI) using Rx only on 1 UART while printing with another one and this works fine, i.e. Deep sleep is well entered and there is no garbage character at the end of the printed line (deep sleep is actually only entered after the transmission is complete).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good catch, I had an old version of the datasheet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also had an old one ! ... so it took me some time and tests to figure that out :-)

TxOngoing |= 1;
}
#endif

#if defined(USART2_BASE)
if (LL_USART_IsEnabled(USART2) && !LL_USART_IsActiveFlag_TC(USART2)) {
TxOngoing |= 1;
}
#endif

#if defined(USART3_BASE)
if (LL_USART_IsEnabled(USART3) && !LL_USART_IsActiveFlag_TC(USART3)) {
TxOngoing |= 1;
}
#endif

#if defined(UART4_BASE)
if (LL_USART_IsEnabled(UART4) && !LL_USART_IsActiveFlag_TC(UART4)) {
TxOngoing |= 1;
}
#endif

#if defined(USART4_BASE)
if (LL_USART_IsEnabled(USART4) && !LL_USART_IsActiveFlag_TC(USART4)) {
TxOngoing |= 1;
}
#endif

#if defined(UART5_BASE)
if (LL_USART_IsEnabled(UART5) && !LL_USART_IsActiveFlag_TC(UART5)) {
TxOngoing |= 1;
}
#endif

#if defined(USART5_BASE)
if (LL_USART_IsEnabled(USART5) && !LL_USART_IsActiveFlag_TC(USART5)) {
TxOngoing |= 1;
}
#endif

#if defined(USART6_BASE)
if (LL_USART_IsEnabled(USART6) && !LL_USART_IsActiveFlag_TC(USART6)) {
TxOngoing |= 1;
}
#endif

#if defined(UART7_BASE)
if (LL_USART_IsEnabled(UART7) && !LL_USART_IsActiveFlag_TC(UART7)) {
TxOngoing |= 1;
}
#endif

#if defined(USART7_BASE)
if (LL_USART_IsEnabled(USART7) && !LL_USART_IsActiveFlag_TC(USART7)) {
TxOngoing |= 1;
}
#endif

#if defined(UART8_BASE)
if (LL_USART_IsEnabled(UART8) && !LL_USART_IsActiveFlag_TC(UART8)) {
TxOngoing |= 1;
}
#endif

#if defined(USART8_BASE)
if (LL_USART_IsEnabled(USART8) && !LL_USART_IsActiveFlag_TC(USART8)) {
TxOngoing |= 1;
}
#endif

#if defined(UART9_BASE)
if (LL_USART_IsEnabled(UART9) && !LL_USART_IsActiveFlag_TC(UART9)) {
TxOngoing |= 1;
}
#endif

#if defined(UART10_BASE)
if (LL_USART_IsEnabled(UART10) && !LL_USART_IsActiveFlag_TC(UART10)) {
TxOngoing |= 1;
}
#endif

#if defined(LPUART1_BASE)
if (LL_USART_IsEnabled(LPUART1) && !LL_USART_IsActiveFlag_TC(LPUART1)) {
TxOngoing |= 1;
}
#endif

/* If Tx is ongoing, then transfer is */
return TxOngoing;
}

#endif /* DEVICE_SERIAL */
12 changes: 12 additions & 0 deletions targets/TARGET_STM/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,20 @@ void hal_sleep(void)
core_util_critical_section_exit();
}

extern int serial_is_tx_ongoing(void);

void hal_deepsleep(void)
{
/* WORKAROUND:
* MBED serial driver does not handle deepsleep lock
* to prevent entering deepsleep until HW serial FIFO is empty.
* This is tracked in mbed issue 4408.
* For now, we're checking all Serial HW FIFO. If any transfer is ongoing
* we're not entering deep sleep and returning immediately. */
if(serial_is_tx_ongoing()) {
return;
}

// Disable IRQs
core_util_critical_section_enter();

Expand Down