2018-05-09 05:37 AM
Hi!
in my program i am using the 'HAL_UART_Receive_IT' function, it is first called when i initialize my app.
There comes a moment during the run of the program when the pointer to buffer given to the function expires and is no longer valid, this is when i want to call this function again with new parameters.
The problem is that the operation doesnt succeed and the HAL_BUSY retval is returned.
please advise on how to restart this function properly after it has already been used.
thanks alot!
2018-05-13 07:27 PM
Worse case find one of the libraries where it is implemented and diff/merge the stuff you need. Or as I suggested before update the structures data pointer in the IRQ handler before you hand off to HAL
2018-05-14 01:49 AM
Yep,
i'm working with the cubeMX and the generated libr3eries of the HAL layer do not contain the abort functions.
2018-05-14 07:10 PM
,
,
Yuri:
This may not help much, but I don't usually use 'HAL_UART_Receive_IT()' in my projects. , I instead use 'HAL_UART_Receive_DMA()' and set up the handlers , 'HAL_UART_RxHalfCpltCallback()' and 'HAL_UART_RxCpltCallback()'. , There's a function 'HAL_UART_DMAStop()' that works fine. , The CubeMX project needs to have the Rx DMA channel set up, I recommend circular mode. , If you set your buffer size to 2, you'll get an interrupt on every character, though that's not what I recommend for streaming.
Looking around, I have one project that is using the interrupt version, but the input buffer is never changed. , I don't fully understand the constraint you're under not to use a buffer defined at a file scope, either static to the file it's defined in or global name space. , It simply takes putting the array declaration outside any function definition. , If it's global, put a declaration of the array (as opposed to definition) in a header file that's included by every C source file that references the buffer by name. , I would never have thought of using a buffer with automatic allocation within an init function that returns its caller before the program is complete. , Even if there is a cancel function for 'HAL_UART_Receive_IT()', unless it's called before the init function returns, the program will not be stable.
Some more advice that will probably not help (but I hope it will): in your interrupt callback functions, copy the received data from the input buffer used in the HAL receive calls into ,a separate ,FIFO/circular buffer. , The callback is called at the interrupt level, you don't want to do real work there. , In your main program, poll the FIFO and read the characters from it. , Keep in mind that more characters may arrive when you're processing stuff, so a circular buffer is the best bet.
The program I have that uses the interrupt form of the HAL UART receive ,runs on a Nucleo-144 board with an STM32F767ZI. , The application code can be configured using a ♯ define to support up to 6 UART/USARTs, and uses a multi-session protocol over a USB device CDC-ACM connection to a PC, where a Linux driver handles multiplexing of up to 7 ,serial character devices over the single USB link. , The first session talks to the set-up function of the STM32 application, and the UART/USARTs are connected to the UART pins on up to 6 SBCs that don't have level shifters thus have TTL 3.3V serial ports, for example, a Raspberry Pi 2 or 3 (and probably other Pis). , The app is also running a multi-threading RTE (AtomThreads). , It's able to handle 4 serial lines at 115200 bps without dropping characters. , I've not tried it with 6 because I don't have that many devices. , The Nucleo-144 is cheaper than 4 USB-to-TTL serial adapters, and it was a fun project.
The code snippet below has an abstract version of my Receive Complete Callback function. , I stripped out all the extra stuff to make the example easier to understand, and have left the implementation of the FIFO push and pull functions to the reader. , (The version of my supports 6 UART/USARTs, each with its own FIFO and receive buffer.It is assumed that the CubeMX generated 'main()' has been called, and that 'myMainLoop()' is called from where the infinite loop is in the 'main()' generated by CubeMX. , It is also assumed that nothing has already called 'HAL_UART_Receive_IT()' before 'myMainLoop()' is called.
♯ include <,stdint.h>,
,
♯ include 'stm32f7xx_hal.h',
♯ include 'stm32f7xx_hal_uart.h',
,
uint8_t usart3_buff[2],,
extern UART_HandleTypeDef huart3,,
,
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart) {,
, , if (huart == &,huart3),
, , { /* ignore anything other than USART3 */,
, , , , , , uint16_t rxSize = huart->,RxXferSize,,
, , , , , , yourFifoPushBytes(usart3_buff, rxSize),,
, , , , , , HAL_UART_Receive_IT(huart, usart3_buff, 1),,
, , } /* was USART 3 */,
} /* end of HAL_UART_RxCpltCallback() */void myMainLoop(void)
{
, , uint8_t localBuff[20],
, , int rxCount,
, , HAL_UART_Receive_ID(&,huart3, usart3_buff, 1),
, , for (,,)
, , { /* main loop, does not exit */
, , , , , rxCount = yourFifoPullBytes(localBuff, sizeof localBuff),
, , , , , if (rxCount >, 0)
, , , , , { /* characters have been received */
, , , , , , , , /* process the rxCount bytes of data in localBuff */
, , , , , } /* characters read */
, , , , , /* Do other things besides reading from the FIFO */
, , } /* end of main loop */
} /* end of myMainLoop() */
, ,
Good luck with your project.
2018-05-14 07:17 PM
Note: The forum software keeps messing up my formatting; I see missing newlines, edit the reply to put them back in, save it, then find that other newlines have been removed in other places within the <pre> block. This is about as close as I've managed to get, so I'm leaving it with the single missing newline rather than risking the formatting becomming unreadable again. I know it's hard to make an HTML that works well in an HTML browser...
2018-05-14 07:34 PM
You could use the syntax Highlighter,
not from your messages, you must enter the actual question.
then look for '...'
then More
then Syntax Highlighter.
then select C++
then paste.
2018-05-15 12:18 PM
OK. I have been doing this all the time and it id based on the assumption that if I do not receive a byte within 5ms of the last, then I have received the whole message. No fuss with circular buffers and get tangled with in-and-out pointers etc.
Obviously there are some assumed code. If you want those as well, email me at willem(at)stima.co.za.
Firstly the IRQ handler has to be modified:
In STM32xxx_it.c:
void USART2_IRQHandler(void)
{ /* USER CODE BEGIN USART2_IRQn 0 */ uint32_t tmp1 = 0, tmp2 = 0; tmp1 = __HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE); tmp2 = __HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_RXNE); /* UART in mode Receiver ---------------------------------------------------*/ if((tmp1 != RESET) && (tmp2 != RESET)) {/* just my Status Engine that informs the application that reception is in progress. Struct is below */
Usart_Message.Status.Receiving = true;
if(Tick_IsStarted(&MessageRXTicker))
/* refreshing the timeout a tick driven timer. Can put your own solution here */
Tick_NewRepeatTime(&MessageRXTicker,5); else {/* setting a tick timer for 30ms after first character received with a callback function
UART_RXVD_Complete() that would be called at timeout. Can put own solution here */
Tick_SetParam(&MessageRXTicker, 30, 30, ONETIME, UART_RXVD_Complete); Tick_Start(&MessageRXTicker); } RX_SIZE++;}
/* USER CODE END USART2_IRQn 0 */ HAL_UART_IRQHandler(&huart2); /* USER CODE BEGIN USART2_IRQn 1 *//* USER CODE END USART2_IRQn 1 */
}in usart.c user section:
void UART_RXVD_Complete(void)
{ if(RX_SIZE== 0) Usart_Message.Status.Aborting = true;/* This is how you stop further reception and solve you HA_BUSY problem */
HAL_UART_RxCpltCallback(&huart2);}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{ if(huart->Instance == USART2) { Usart_Message.Status.Receiving = false; Usart_Message.Status.MessageWaiting = true; RX_Mess_Buf = (uint8_t *) &RX_TEMPBUFFER[0]; /* copy the message into your own buffer and free up the interupt buffer to hold nect recieved message */ strncpy((char *) &Usart_Message.RX_MESS_BUFFER[0], (char *)&RX_TEMPBUFFER[0], sizeof(Usart_Message.RX_MESS_BUFFER) -1); /* RXsize is a global variable declared as volatile */ Usart_Message.RX_size = RX_SIZE; RX_SIZE = 0; HAL_UART_ReceiveAbort(&huart2); HAL_UART_Receive_IT(&huart2, (uint8_t *)&RX_TEMPBUFFER[0], sizeof(RX_TEMPBUFFER)-1); } if(huart->Instance == USART3) { // handle next Usart here } }/* for all Usarts */
HAL_StatusTypeDef HAL_UART_ReceiveAbort(UART_HandleTypeDef *huart){ /* Process Locked */ __HAL_LOCK(huart);memset((void *)&RX_TEMPBUFFER, 0, sizeof(RX_TEMPBUFFER));
RX_SIZE = 0; huart->pRxBuffPtr = (uint8_t *)&RX_TEMPBUFFER[0]; /* Care should be taken when interrupt is disabled. It must be reenabled again */ //__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE); huart->RxXferCount = 0; huart->RxXferSize = 0; huart->ErrorCode = HAL_UART_ERROR_NONE; __HAL_UNLOCK(huart);return HAL_OK;
}In your main.c:
typedef struct MESSAGE_OBJECT
{ MessageFlags Flags; uint8_t RX_MESS_BUFFER[256]; uint8_t TX_MESS_BUFFER[256]; uint8_t SMS_Text[170]; uint16_t RX_size; uint16_t TX_size; UartState State; UartState LastState; struct COMMS_STATUS { unsigned Busy : 1; unsigned Aborting : 1; unsigned MessageWaiting : 1; unsigned Receiving : 1; unsigned Transmitting : 1; unsigned SendRequest : 1; unsigned ReleaseTimeout : 1; unsigned QueueWaiting : 1; }Status;}MessageObject;volatile MessageObject Usart_Message;
//mainloop:
while (1){ ...... if(Usart_Message.Status.MessageWaiting) Go_handle_Usart message(); ......}