2

I am using STM32F1 (STM32F103C8T6) in order to develop a project using FreeRTOS.

The following is my GPIO and USART1 interface configuration:

    __GPIOA_CLK_ENABLE();
    __USART1_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    huart1.Instance = USART1;
  huart1.Init.BaudRate = 9600;//115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  HAL_UART_Init(&huart1);

  HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(USART1_IRQn);

The question is: Why does UART transmit work before threads start but not after threads started or from threads? I want to transmit data from threads. i.e

int main(void)
{
     Initializations();

     //THIS WORKS!!
     uart_transmit_buffer[0] = 'H';
     uart_transmit_buffer[1] = 'R';
     uart_transmit_buffer[2] = '#';
     uint8_t nums_in_tr_buf = 0;
     nums_in_tr_buf = sizeof(uart_transmit_buffer)/sizeof(uint8_t);
     state = HAL_UART_Transmit(&huart1, uart_transmit_buffer, nums_in_tr_buf, 5000);

     StartAllThreads();
     osKernelStart();

     for (;;);
}

static void A_Random_Thread(void const *argument)
{
      for(;;)
      {
         if (conditionsMet())  //Executed once when a proper response received.
         {
            //BUT NOT THIS :(!!
            uart_transmit_buffer[0] = 'H';
            uart_transmit_buffer[1] = 'R';
            uart_transmit_buffer[2] = '#';
            uint8_t nums_in_tr_buf = 0;
            nums_in_tr_buf = sizeof(uart_transmit_buffer)/sizeof(uint8_t);
            state = HAL_UART_Transmit(&huart1, uart_transmit_buffer, nums_in_tr_buf, 5000);
        }
      }
}

I have made sure no thread is in deadlock. The problem is UART_HAL_Transmit gives HAL_BUSY state.

Furthermore, I have dedicated one thread to receiving and parsing information from UART RX and I suspect this might be a cause of the problem. The following is the code:

static void UART_Receive_Thread(void const *argument)
{
  uint32_t count;
  (void) argument;
    int j = 0, word_length = 0;

  for (;;)
  {
            if (uart_line_ready == 0)
            {
                    HAL_UART_Receive(&huart1, uart_receive_buffer, UART_RX_BUFFER_SIZE, 0xFFFF);
                    if (uart_receive_buffer[0] != 0)
                    {
                            if (uart_receive_buffer[0] != END_OF_WORD_CHAR)
                            {
                                    uart_line_buffer[k] = uart_receive_buffer[0];
                                    uart_receive_buffer[0] = 0;
                                    k++;
                            }
                            else
                            {
                                    uart_receive_buffer[0] = 0;
                                    uart_line_ready = 1;
                                    word_length = k;
                                    k = 0;
                            }
                    }
            }
            if (uart_line_ready == 1)
            {
                    //osThreadSuspend(OLEDThreadHandle);
                    for (j = 0; j <= word_length; j++)
                    {
                            UART_RECEIVED_COMMAND[j] = uart_line_buffer[j];
                    }
                    for (j = 0; j <= word_length; j++)
                    {
                            uart_line_buffer[j] = 0;
                    }
                    uart_line_ready = 0;

                    RECEIVED_COMMAND = ParseReceivedCommand(UART_RECEIVED_COMMAND);
                    if (RECEIVED_COMMAND != _ID_)
                    {
                            AssignReceivedData (word_length);  //Results in uint8_t * RECEIVED_DATA
                    }
                    //osThreadResume(OLEDThreadHandle);
            }
          //Should be no delay in order not to miss any data..
  }
}

Another cause to the problem I suspect could be related to interrupts of the system (Also please notice initialization part, I configured NVIC):

void USART1_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart1);
}

Any help or guidance to this issue would be highly appreciated. Thanks in advance.

mozcelikors
  • 2,582
  • 8
  • 43
  • 77
  • 1
    You do not use the interrupt actually, you are enabling the UART IRQ only in NVIC but it has to be at the peripheral as well. `HAL_UART_Receive_IT` does it `HAL_UART_Receive` does not. Make a test in which you do not start the UART receive thread. – Bence Kaulics Apr 11 '17 at 10:29
  • I meant to mention that without UART receive thread it works. The question is how to overcome this problem? Do you suggest using HAL_UART_Receive_IT instead of HAL_UART_Receive? – mozcelikors Apr 11 '17 at 10:46
  • No, that was just a remark that it is not related to the IRQ. Possibly your threads try to use the UART concurrently and take over in BUSY state for example. Try to protect the UART usage with a semaphore or mutex. – Bence Kaulics Apr 11 '17 at 10:58
  • Since I dont value threads when transmitting that message, I tried suspending and then resuming all the other threads which sadly did not work. – mozcelikors Apr 11 '17 at 11:03

3 Answers3

2

From what I can see HAL_UART_Transmit would've worked with the F4 HAL (v1.4.2) if it weren't for __HAL_LOCK(huart). The RX thread would lock the handle and then the TX thread would try to lock as well and return HAL_BUSY. HAL_UART_Transmit_IT and HAL_UART_Receive_IT don't lock the handle for the duration of the transmit/receive.

Which may cause problems with the State member, as it is non-atomically updated by the helper functions UART_Receive_IT and UART_Transmit_IT. Though I don't think it would affect operation.

You could modify the function to allow simultaneous RX and TX. You'd have to update this every time they release a new version of the HAL.

The problem is that the ST HAL isn't meant to be used with an RTOS. It says so in the definition of the macro __HAL_LOCK. Redefining it to use the RTOS's mutexes might worth trying as well. Same with HAL_Delay() to use the RTOS's thread sleep function.

In general though, sending via a blocking function in a thread should be fine, but I would not receive data using a blocking function in a thread. You are bound to experience overrun errors that way.

Likewise, if you put too much processing in the receive interrupt you might also run into overrun errors. I prefer using DMA for reception, followed by interrupts if I've run out of DMA streams. The interrupt only copies the data to a buffer, similarly to the DMA. A processRxData thread is then used to process the actual data.

Flip
  • 881
  • 7
  • 13
1

When using FreeRTOS, you have to set interrupt priority to 5 or above, because below 5 is reserved for the OS. So change your code to set the priority to:

HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
Guillaume Michel
  • 1,189
  • 8
  • 14
1

The problem turned out to be something to do with blocking statements. Since UART_Receive_Thread has HAL_UART_Receive inside and that is blocking the thread until something is received, that results in a busy HAL (hence, the HAL_BUSY state).

The solution was using non-blocking statements without changing anything else. i.e. using HAL_UART_Receive_IT and HAL_UART_Transmit_IT at the same time and ignoring blocking statements worked.

Thanks for all suggestions that lead to this solution.

mozcelikors
  • 2,582
  • 8
  • 43
  • 77