diff options
| author | Giovanni Di Sirio <gdisirio@gmail.com> | 2015-04-19 07:49:28 +0000 | 
|---|---|---|
| committer | Giovanni Di Sirio <gdisirio@gmail.com> | 2015-04-19 07:49:28 +0000 | 
| commit | d52ee81b3a0704e8e1e40b6acf3ff03199905303 (patch) | |
| tree | 33b856218dae7902cffb9f6edd027a13aeafec78 | |
| parent | e2dbf2c514226554968e0e984201d2859011bd62 (diff) | |
| download | ChibiOS-d52ee81b3a0704e8e1e40b6acf3ff03199905303.tar.gz ChibiOS-d52ee81b3a0704e8e1e40b6acf3ff03199905303.tar.bz2 ChibiOS-d52ee81b3a0704e8e1e40b6acf3ff03199905303.zip | |
Fixed bug #584.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@7905 35acf78f-673a-0410-8e92-d51de3d6d3f4
| -rw-r--r-- | os/hal/ports/STM32/LLD/USARTv1/uart_lld.c | 24 | ||||
| -rw-r--r-- | os/hal/ports/STM32/LLD/USARTv2/uart_lld.c | 22 | ||||
| -rw-r--r-- | readme.txt | 1 | 
3 files changed, 34 insertions, 13 deletions
| diff --git a/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c b/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c index e72104c7b..44324fc7e 100644 --- a/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c +++ b/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c @@ -222,11 +222,10 @@ static void usart_start(UARTDriver *uartp) {    u->CR2 = uartp->config->cr2 | USART_CR2_LBDIE;
    u->CR3 = uartp->config->cr3 | USART_CR3_DMAT | USART_CR3_DMAR |
                                  USART_CR3_EIE;
 -  if (uartp->config->txend2_cb == NULL)
 -    cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE;
 -  else
 -    cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE |
 -          USART_CR1_TCIE;
 +
 +  /* Mustn't ever set TCIE here - if done, it causes an immediate
 +     interrupt.*/
 +  cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE;
    u->CR1 = uartp->config->cr1 | cr1;
    /* Starting the receiver idle loop.*/
 @@ -292,6 +291,12 @@ static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {    dmaStreamDisable(uartp->dmatx);
 +  /* Only enable TC interrupt if there's a callback attached to it.
 +     We have to do it here, rather than earlier, because TC flag is set
 +     until transmission starts.*/
 +  if (uartp->config->txend2_cb != NULL)
 +    uartp->usart->CR1 |= USART_CR1_TCIE;
 +
    /* A callback is generated, if enabled, after a completed transfer.*/
    uartp->txstate = UART_TX_COMPLETE;
    if (uartp->config->txend1_cb != NULL)
 @@ -311,17 +316,22 @@ static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {  static void serve_usart_irq(UARTDriver *uartp) {
    uint16_t sr;
    USART_TypeDef *u = uartp->usart;
 -  
 +  uint32_t cr1 = u->CR1;
 +
    sr = u->SR;   /* SR reset step 1.*/
    (void)u->DR;  /* SR reset step 2.*/
 +
    if (sr & (USART_SR_LBD | USART_SR_ORE | USART_SR_NE |
              USART_SR_FE  | USART_SR_PE)) {
      u->SR = ~USART_SR_LBD;
      if (uartp->config->rxerr_cb != NULL)
        uartp->config->rxerr_cb(uartp, translate_errors(sr));
    }
 -  if (sr & USART_SR_TC) {
 +
 +  if ((sr & USART_SR_TC) && (cr1 & USART_CR1_TCIE)) {
 +    /* TC interrupt cleared and disabled.*/
      u->SR = ~USART_SR_TC;
 +    u->CR1 = cr1 & ~USART_CR1_TCIE;
      /* End of transmission, a callback is generated.*/
      if (uartp->config->txend2_cb != NULL)
 diff --git a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c index 61cbe3ac7..1cce68503 100644 --- a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c +++ b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c @@ -176,11 +176,10 @@ static void usart_start(UARTDriver *uartp) {    u->CR2 = uartp->config->cr2 | USART_CR2_LBDIE;
    u->CR3 = uartp->config->cr3 | USART_CR3_DMAT | USART_CR3_DMAR |
                                  USART_CR3_EIE;
 -  if (uartp->config->txend2_cb == NULL)
 -    cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE;
 -  else
 -    cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE |
 -          USART_CR1_TCIE;
 +
 +  /* Mustn't ever set TCIE here - if done, it causes an immediate
 +     interrupt.*/
 +  cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE;
    u->CR1 = uartp->config->cr1 | cr1;
    /* Starting the receiver idle loop.*/
 @@ -246,6 +245,12 @@ static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {    dmaStreamDisable(uartp->dmatx);
 +  /* Only enable TC interrupt if there's a callback attached to it.
 +     We have to do it here, rather than earlier, because TC flag is set
 +     until transmission starts.*/
 +  if (uartp->config->txend2_cb != NULL)
 +    uartp->usart->CR1 |= USART_CR1_TCIE;
 +
    /* A callback is generated, if enabled, after a completed transfer.*/
    uartp->txstate = UART_TX_COMPLETE;
    if (uartp->config->txend1_cb != NULL)
 @@ -265,6 +270,7 @@ static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {  static void serve_usart_irq(UARTDriver *uartp) {
    uint32_t isr;
    USART_TypeDef *u = uartp->usart;
 +  uint32_t cr1 = u->CR1;
    /* Reading and clearing status.*/
    isr = u->ISR;
 @@ -275,7 +281,11 @@ static void serve_usart_irq(UARTDriver *uartp) {      if (uartp->config->rxerr_cb != NULL)
        uartp->config->rxerr_cb(uartp, translate_errors(isr));
    }
 -  if (isr & USART_ISR_TC) {
 +
 +  if ((isr & USART_ISR_TC) && (cr1 & USART_CR1_TCIE)) {
 +    /* TC interrupt disabled.*/
 +    u->CR1 = cr1 & ~USART_CR1_TCIE;
 +
      /* End of transmission, a callback is generated.*/
      if (uartp->config->txend2_cb != NULL)
        uartp->config->txend2_cb(uartp);
 diff --git a/readme.txt b/readme.txt index 85967ac0d..0b03de580 100644 --- a/readme.txt +++ b/readme.txt @@ -74,6 +74,7 @@  *****************************************************************************
  *** 3.0.0p4 ***
 +- HAL: Fixed spurious TC interrupt in STM32 UART (v1 and v2) driver (bug #584).
  - HAL: Fixed invalid checks on STM32L1xx LSI and LSE clocks (bug #583).
  - HAL: Fixed RCC CAN2 macros missing in STM32F1xx platform (bug #582).
  - HAL: Fixed STM32 I2Cv2 driver issue (bug 581).
 | 
