AnsweredAssumed Answered

STM32F030 parity error only with activated RXNEIE?

Question asked by horn.thomas.001 on Jul 5, 2016
Latest reply on Jul 5, 2016 by horn.thomas.001
Hello,

For a simple bus-protocol I would like to use a parity error for waking up nodes at the beginning of a new frame, i.e. all usual data is transferred with odd parity, only a start byte has even parity. This way the nodes don't get interrupts from received bytes that directed to other nodes. Only a start byte will activate (by triggering a parity error) the node, it then activates the RXNEIE and receives the header and the decides if it receives the whole frame or not (by deactivating RXNEIE again).

To implement this I enabled the USART :
    USART_CR1_UE | USART_CR1_RE | USART_CR1_PEIE  | (all other fields for setting the correct data format)
    , but I didn't get interrupts triggered by a parity error.
Only if I additionally activate RXNEIE:
    USART_CR1_UE | USART_CR1_RE | USART_CR1_PEIE | USART_CR1_RXNEIE
    , I get interrupts and the expected parity errors.
According to the reference manual ( RM0360 Reference manual, page 627) there shouldn't be a dependency between PEIE and RXNEIE.
Has anybody observed that behavior?
Am I doing something wrong?

I attached my USART routines (a mix-up of my and STM32Cube code).
PS: I know the STM32F030 has a character match filter, but there are nodes on the bus, which don't have this feature, therefore I decided to use parity as SOF mark.
Sorry for the number of entries, my browser went nuts and attachments doesn't work :(



#include <stdint.h>
#include "Pipe.h"
#include "stm32f030x6.h"
#include "stm32f0xx_hal.h"

Pipe<32, uint8_t> ReceiverQueue;
Pipe<32, uint8_t> SendQueue;

extern UART_HandleTypeDef huart1;

bool s_IsSending_bt = false;
uint8_t s_EchoCnt_u8 = 0U;

const uint32_t TRANSMIT_ENABLE = USART_CR1_UE | USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE | USART_CR1_TXEIE;
const uint32_t RECEIVER_ENABLE = USART_CR1_UE | USART_CR1_RE | USART_CR1_RXNEIE;

// working
const uint32_t RECEIVER_WAIT = USART_CR1_UE | USART_CR1_RE | USART_CR1_PEIE | USART_CR1_RXNEIE;
// not working
// const uint32_t RECEIVER_WAIT = USART_CR1_UE | USART_CR1_RE | USART_CR1_PEIE;

const uint32_t ENABLE_MASK = USART_CR1_UE | USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE | USART_CR1_TXEIE | USART_CR1_PEIE;

int uart_getc()
{
  uint8_t Byte;
  if (ReceiverQueue.Read(Byte)) {
    return static_cast<int>(Byte);
  }
  return 0x100;
}

void uart_putc(char c)
{
  SendQueue.Write(c);
  if (!s_IsSending_bt) {
    s_IsSending_bt = true;
    MODIFY_REG(USART1->CR1, ENABLE_MASK, TRANSMIT_ENABLE);
    uint8_t val;
    SendQueue.Read(val);
    USART1->TDR = val;  
  }
}

void uart_sleep()
{
    MODIFY_REG(USART1->CR1, ENABLE_MASK, RECEIVER_WAIT);
}

void uart_puts(const char* pStr)
{
#if 0
  HAL_UART_Transmit_IT(&huart1,(uint8_t *)pStr,strlen(pStr));
#else
  const char* p=pStr;
  while (*p) {
    uart_putc(*p++);
  }
#endif
}

#if 1
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef * huart)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    
  /* USER CODE END USART1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();
 
    /**USART1 GPIO Configuration    
    PA2     ------> USART1_TX
    PA3     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF1_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


    USART1->BRR = 2500U;        // 48MHz --> 19200
    USART1->CR2 = 0U;
    USART1->CR3 = 0U;
    uint32_t tmpreg = (uint32_t)huart->Init.WordLength | huart->Init.Parity | huart->Init.Mode | huart->Init.OverSampling ;
    tmpreg |=  RECEIVER_ENABLE;
    USART1->CR1 = tmpreg;
        
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
    
    return HAL_OK;
}


void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  static volatile uint8_t LastRec;
    uint32_t isr = USART1->ISR;
    if (isr & UART_FLAG_RXNE) {      
      uint8_t val=USART1->RDR;
      LastRec = val;
      if (0U==s_EchoCnt_u8) {
        ReceiverQueue.Write(val);
      }
      else {
        s_EchoCnt_u8--;
      }
    }    
    if (isr & (UART_FLAG_PE)) {
      USART1->ICR =  UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_FEF;
      uint8_t val=USART1->RDR;
      LastRec = val;
      if (LastRec == 0xAA) {
        MODIFY_REG(huart->Instance->CR1, ENABLE_MASK, RECEIVER_ENABLE);
      }
    }
    if (isr & (UART_FLAG_ORE | UART_FLAG_FE)) {
      USART1->ICR =  UART_CLEAR_OREF | UART_CLEAR_FEF;
    }
    if ( 0!= (isr & (UART_FLAG_TXE | UART_FLAG_TC)) && s_IsSending_bt){
      uint8_t val;
      if (SendQueue.Read(val)) {
        USART1->TDR = val;
        s_EchoCnt_u8++;
      }      
      else {        // nothing left to send
          MODIFY_REG(huart->Instance->CR1, ENABLE_MASK, RECEIVER_WAIT);
          USART1->ICR =  UART_CLEAR_TCF;
          s_IsSending_bt = false;
      }
    }
}

/**
  * @brief Configure the UART peripheral.
  * @param huart: UART handle.
  * @retval HAL status
  */
#define UART_CR1_FIELDS  ((uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | \
                                     USART_CR1_TE | USART_CR1_RE | USART_CR1_OVER8)) /*!< UART or USART CR1 fields of parameters set by UART_SetConfig API */


HAL_StatusTypeDef UART_SetConfig(UART_HandleTypeDef *huart)
{
  uint32_t tmpreg                     = 0x00000000;
  UART_ClockSourceTypeDef clocksource = UART_CLOCKSOURCE_UNDEFINED;
  uint16_t brrtemp                    = 0x0000;
  uint16_t usartdiv                   = 0x0000;
  HAL_StatusTypeDef ret               = HAL_OK;

  /* Check the parameters */
  assert_param(IS_UART_BAUDRATE(huart->Init.BaudRate));
  assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength));
  assert_param(IS_UART_STOPBITS(huart->Init.StopBits));
  assert_param(IS_UART_PARITY(huart->Init.Parity));
  assert_param(IS_UART_MODE(huart->Init.Mode));
  assert_param(IS_UART_HARDWARE_FLOW_CONTROL(huart->Init.HwFlowCtl));
  assert_param(IS_UART_ONE_BIT_SAMPLE(huart->Init.OneBitSampling));
  assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling));


  /*-------------------------- USART CR1 Configuration -----------------------*/
  /* Clear M, PCE, PS, TE, RE and OVER8 bits and configure
   *  the UART Word Length, Parity, Mode and oversampling:
   *  set the M bits according to huart->Init.WordLength value
   *  set PCE and PS bits according to huart->Init.Parity value
   *  set TE and RE bits according to huart->Init.Mode value
   *  set OVER8 bit according to huart->Init.OverSampling value */
  tmpreg = (uint32_t)huart->Init.WordLength | huart->Init.Parity | huart->Init.Mode | huart->Init.OverSampling ;
  MODIFY_REG(huart->Instance->CR1, UART_CR1_FIELDS, tmpreg);

  /*-------------------------- USART CR2 Configuration -----------------------*/
  /* Configure the UART Stop Bits: Set STOP[13:12] bits according
   * to huart->Init.StopBits value */
  MODIFY_REG(huart->Instance->CR2, USART_CR2_STOP, huart->Init.StopBits);

  /*-------------------------- USART CR3 Configuration -----------------------*/
  /* Configure
   * - UART HardWare Flow Control: set CTSE and RTSE bits according
   *   to huart->Init.HwFlowCtl value
   * - one-bit sampling method versus three samples' majority rule according
   *   to huart->Init.OneBitSampling */
  tmpreg = (uint32_t)huart->Init.HwFlowCtl | huart->Init.OneBitSampling ;
  MODIFY_REG(huart->Instance->CR3, (USART_CR3_RTSE | USART_CR3_CTSE | USART_CR3_ONEBIT), tmpreg);

  /*-------------------------- USART BRR Configuration -----------------------*/
  UART_GETCLOCKSOURCE(huart, clocksource);
 
  /* Check UART Over Sampling to set Baud Rate Register */
  if (huart->Init.OverSampling == UART_OVERSAMPLING_8)
  {
    switch (clocksource)
    {
      case UART_CLOCKSOURCE_PCLK1:
        usartdiv = (uint16_t)(UART_DIV_SAMPLING8(HAL_RCC_GetPCLK1Freq(), huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_HSI:
        usartdiv = (uint16_t)(UART_DIV_SAMPLING8(HSI_VALUE, huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_SYSCLK:
        usartdiv = (uint16_t)(UART_DIV_SAMPLING8(HAL_RCC_GetSysClockFreq(), huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_LSE:
        usartdiv = (uint16_t)(UART_DIV_SAMPLING8(LSE_VALUE, huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_UNDEFINED:
      default:
        ret = HAL_ERROR;
        break;
    }

    brrtemp = usartdiv & 0xFFF0;
    brrtemp |= (uint16_t)((usartdiv & (uint16_t)0x000F) >> 1U);
    huart->Instance->BRR = brrtemp;
  }
  else
  {
    switch (clocksource)
    {
      case UART_CLOCKSOURCE_PCLK1:
        huart->Instance->BRR = (uint16_t)(UART_DIV_SAMPLING16(HAL_RCC_GetPCLK1Freq(), huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_HSI:
        huart->Instance->BRR = (uint16_t)(UART_DIV_SAMPLING16(HSI_VALUE, huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_SYSCLK:
        huart->Instance->BRR = (uint16_t)(UART_DIV_SAMPLING16(HAL_RCC_GetSysClockFreq(), huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_LSE:
        huart->Instance->BRR = (uint16_t)(UART_DIV_SAMPLING16(LSE_VALUE, huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_UNDEFINED:
      default:
        ret = HAL_ERROR;
        break;
    }
  }

  return ret;

}

#endif

Outcomes