Jump to content

    

Пропадают прерывания по приёму UART. FreeRTOS CMSIS_V2

Например, чтобы каждый не вызывать Receive_IT(... 1) после приема - можно после вызова HAL_UART_IRQ_... уменьшить счетчик и вернуть указатель (если они изменились). А вызывать Receive_IT(... 2) только в начале программы и после ошибки. В общем всё зависит от желания. Но можно конечно под каждый процессор проштудировать RM и колбасить всё ручками.

Share this post


Link to post
Share on other sites
8 minutes ago, x893 said:

Но можно конечно под каждый процессор проштудировать RM и колбасить всё ручками

Так.. это... как бэ разве куб отменяет смотреть доку?)))

Share this post


Link to post
Share on other sites
1 minute ago, haker_fox said:

разве куб отменяет смотреть доку?)))

Косвенно - да, поскольку куб значительно снизил "порог вхождения" и в тему хлынул поток "ардуинщиков" :focus:

Share this post


Link to post
Share on other sites
19 minutes ago, x893 said:

Например, чтобы каждый не вызывать Receive_IT(... 1) после приема - можно после вызова HAL_UART_IRQ_... уменьшить счетчик и вернуть указатель (если они изменились). А вызывать Receive_IT(... 2) только в начале программы

Счётчик тогда уж увеличивать надо (при приёме он уменьшается). Но это не работает, ибо HAL_UART_RxCpltCallback никогда не вызовется, поскольку его вызов в UART_RxISR_8BIT случается только когда счётчик принятых байтов стал равен 0, а к моменту вызова "чёрное дело" по запрету прерываний и пр. уже случилось.

Share this post


Link to post
Share on other sites
4 minutes ago, Dimonira said:

Счётчик тогда уж увеличивать надо (при приёме он уменьшается). Но это не работает, ибо HAL_UART_RxCpltCallback никогда не вызовется, поскольку его вызов в UART_RxISR_8BIT случается только когда счётчик принятых байтов стал равен 0, а к моменту вызова "чёрное дело" по запрету прерываний и пр. уже случилось.

Не вызывается, но где лежат данные известно. Можно забрать по указателю.

Share this post


Link to post
Share on other sites
4 minutes ago, x893 said:

Не вызывается, но где лежат данные известно. Можно забрать по указателю.

Можно конечно, но в каком месте забирать?

Share this post


Link to post
Share on other sites
30 minutes ago, Dimonira said:

Можно конечно, но в каком месте забирать?

А разве при вызове Receive_IT не передаете указатель ? И он потом сохраняется в husart1 (название поля есть в описании структуры). 

Share this post


Link to post
Share on other sites

В итоге я сделал более-менее приемлемо - заменил три стандартные функции UART_RxISR_8BIT, UART_RxISR_16BIT и HAL_UART_Receive_IT на свои. Чтобы не было конфликта, сделал у них имена с суфиксом "_new": UART_RxISR_8BIT_new, UART_RxISR_16BIT_new, HAL_UART_Receive_IT_new. Я воспользовался полем дескриптора huart->RxXferSize, в которое HAL только записывает количество байтов для приёма, но нигде не использует. Сделал, чтобы при вызове HAL_UART_Receive_IT_new аргумент Size мог принимать значение 0, которое "сигнализирует" необходимость непрерывного приёма. Size как раз присваивается полю huart->RxXferSize, а если оно равно 0, то в UART_RxISR_8BIT_new и UART_RxISR_16BIT_new это используется как "сигнал", что приём надо продолжать, указатель в буфере и счётчик не менять, плюс надо вызвать HAL_UART_RxCpltCallback. То есть буфер при вызове HAL_UART_Receive_IT_new при Size = 0 может быть на одно слово (uint8_t или uint16_t). Если Size > 0, то всё будет работать по старому.

Далее в main включаю новый заголовок и в дефолтовой задаче один раз делаю вызов HAL_UART_Receive_IT_new с аргументом Size = 0 и всё:

void StartDefaultTask(void *argument)
{
  /* init code for LWIP */
  MX_LWIP_Init();

  /* USER CODE BEGIN 5 */
  logprintf("LWIP initialization done...\r\n");
  // Запускаем приём UART по прерываниям
  for(int i = 0; i < NUMBER_OF_UARTS; i++)
  {
    if(uarts[i])
      HAL_UART_Receive_IT_new(uarts[i], &rx_buf[i], 0);
  }
  logprintf("UART reception started...\r\n");
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
    osDelay(500);
  }
  /* USER CODE END 5 */ 
}

Функция обратного вызова остаётся в том же виде (без вызова HAL_UART_Receive_IT):

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  // Находим индекс UART
  int idx;
  for(idx = 0; idx < NUMBER_OF_UARTS; idx++)
  {
    if(uarts[idx] == huart)
      break;
  }
  // Готовим сообщение с принятым байтом
  MSG_UART_RX msg;
  msg.uart = idx;         // индекс UART
  msg.byte = rx_buf[idx]; // принятый байт
  // Помещаем сообщение в очередь
  osMessageQueuePut(mid_RxQueue, &msg, 0, 0);
}

В файле stm32f7xx_it.c всё вернул взад как было (свой MY_UART_IRQHandler не нужен).

Теперь всё работает как надо. И код HAL "не пострадал".

Моё "дополнение" состоит из двух файлов. Исходник stm32f7xx_hal_uart_new.c:

#include "stm32f7xx_hal_uart_new.h"

#ifdef HAL_UART_MODULE_ENABLED

/**
  * @brief RX interrrupt handler for 7 or 8 bits data word length .
  * @param huart UART handle.
  * @retval None
  */
static void UART_RxISR_8BIT_new(UART_HandleTypeDef *huart)
{
  uint16_t uhMask = huart->Mask;
  uint16_t  uhdata;

  /* Check that a Rx process is ongoing */
  if (huart->RxState == HAL_UART_STATE_BUSY_RX)
  {
    uhdata = (uint16_t) READ_REG(huart->Instance->RDR);
    *huart->pRxBuffPtr = (uint8_t)(uhdata & (uint8_t)uhMask);
    if(huart->RxXferSize)
    {
      huart->pRxBuffPtr++;
      huart->RxXferCount--;
    }

    if (huart->RxXferCount == 0U)
    {
      /* Disable the UART Parity Error Interrupt and RXNE interrupts */
      CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));

      /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
      CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);

      /* Rx process is completed, restore huart->RxState to Ready */
      huart->RxState = HAL_UART_STATE_READY;

      /* Clear RxISR function pointer */
      huart->RxISR = NULL;
    }

    if(huart->RxXferCount == 0U || !huart->RxXferSize)
    {
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
      /*Call registered Rx complete callback*/
      huart->RxCpltCallback(huart);
#else
      /*Call legacy weak Rx complete callback*/
      HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
    }
  }
  else
  {
    /* Clear RXNE interrupt flag */
    __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
  }
}

/**
  * @brief RX interrrupt handler for 9 bits data word length .
  * @note   Function is called under interruption only, once
  *         interruptions have been enabled by HAL_UART_Receive_IT()
  * @param huart UART handle.
  * @retval None
  */
static void UART_RxISR_16BIT_new(UART_HandleTypeDef *huart)
{
  uint16_t *tmp;
  uint16_t uhMask = huart->Mask;
  uint16_t  uhdata;

  /* Check that a Rx process is ongoing */
  if (huart->RxState == HAL_UART_STATE_BUSY_RX)
  {
    uhdata = (uint16_t) READ_REG(huart->Instance->RDR);
    tmp = (uint16_t *) huart->pRxBuffPtr ;
    *tmp = (uint16_t)(uhdata & uhMask);
    if(huart->RxXferSize)
    {
      huart->pRxBuffPtr += 2U;
      huart->RxXferCount--;
    }

    if (huart->RxXferCount == 0U)
    {
      /* Disable the UART Parity Error Interrupt and RXNE interrupt*/
      CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));

      /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
      CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);

      /* Rx process is completed, restore huart->RxState to Ready */
      huart->RxState = HAL_UART_STATE_READY;

      /* Clear RxISR function pointer */
      huart->RxISR = NULL;
    }

    if(huart->RxXferCount == 0U || !huart->RxXferSize)
    {
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
      /*Call registered Rx complete callback*/
      huart->RxCpltCallback(huart);
#else
      /*Call legacy weak Rx complete callback*/
      HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
    }
  }
  else
  {
    /* Clear RXNE interrupt flag */
    __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
  }
}

/**
  * @brief Receive an amount of data in interrupt mode.
  * @param huart UART handle.
  * @param pData Pointer to data buffer. If Size=0, then just one word buffer.
  * @param Size  Amount of data to be received. If 0, then continuous reception of one word.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Receive_IT_new(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  /* Check that a Rx process is not already ongoing */
  if (huart->RxState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL))
    {
      return HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    huart->pRxBuffPtr  = pData;
    huart->RxXferSize  = Size;
    huart->RxXferCount = !Size ? 1 : Size;
    huart->RxISR       = NULL;

    /* Computation of UART mask to apply to RDR register */
    UART_MASK_COMPUTATION(huart);

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;

    /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    SET_BIT(huart->Instance->CR3, USART_CR3_EIE);

    /* Set the Rx ISR function pointer according to the data word length */
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    {
      huart->RxISR = UART_RxISR_16BIT_new;
    }
    else
    {
      huart->RxISR = UART_RxISR_8BIT_new;
    }

    /* Process Unlocked */
    __HAL_UNLOCK(huart);

    /* Enable the UART Parity Error interrupt and Data Register Not Empty interrupt */
    SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

#endif /* HAL_UART_MODULE_ENABLED */

И заголовок stm32f7xx_hal_uart_new.h:

#ifndef STM32F7xx_HAL_UART_NEW_H
#define STM32F7xx_HAL_UART_NEW_H

#include "stm32f7xx_hal.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
  * @brief Receive an amount of data in interrupt mode.
  * @param huart UART handle.
  * @param pData Pointer to data buffer. If Size=0, then just one word buffer.
  * @param Size  Amount of data to be received. If 0, then continuous reception of one word.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Receive_IT_new(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

#ifdef __cplusplus
}
#endif

#endif /* STM32F7xx_HAL_UART_NEW_H */

 

Share this post


Link to post
Share on other sites

Господа, вы это всё серьёзно? Побайтный приём из USART?

void USART1_IRQHandler(void)
{
  uint32_t sr = USART1->SR;  
  if(sr & USART_SR_RXNE)
  {   
    uint8_t data = USART1->DR;
    if(!(sr & (USART_SR_PE | USART_SR_FE | USART_SR_NE | USART_SR_ORE)))
    {
      // в data принятый байт, делай с ним что хошь.
    }
  }  
}

 

Share this post


Link to post
Share on other sites
11 minutes ago, VladislavS said:

Господа, вы это всё серьёзно? Побайтный приём из USART?


void USART1_IRQHandler(void)
{
  uint32_t sr = USART1->SR;  
  if(sr & USART_SR_RXNE)
  {   
    uint8_t data = USART1->DR;
    if(!(sr & (USART_SR_PE | USART_SR_FE | USART_SR_NE | USART_SR_ORE)))
    {
      // в data принятый байт, делай с ним что хошь.
    }
  }  
}

 

Что хошь в FreeRTOS не получится. Вы вообще читали тему с начала?

Share this post


Link to post
Share on other sites
1 hour ago, Dimonira said:

Что хошь в FreeRTOS не получится.

Так, а причём здесь FreeRTOS?

Share this post


Link to post
Share on other sites

Просто мастера программирования !

Share this post


Link to post
Share on other sites
#include "stm32f7xx_hal_uart_new.h"

 Положение обязывает :biggrin:

Share this post


Link to post
Share on other sites

(С) "Ежики кололись, но все равно ели кактус..."

Share this post


Link to post
Share on other sites

Некоторые и плитку кафельную молотком режут.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now