STM32 – 使用DMA + 循环缓冲解析Mavlink 2时出现问题

huangapple go评论91阅读模式
英文:

STM32 - problem parsing mavlink 2 using DMA + circular buffer

问题

我正在尝试从Pixhawk 4设备的UART端口读取遥测数据,并将其转发到另一个设备。我可以成功读取数据,但是我跳过了一些消息。我曾尝试使用大小为1的缓冲区,但我认为这是我的问题之一。

谢谢你的帮助。

以下是我的代码:

我的缓冲区和启动DMA以获取回调的方式...

/* 用户代码开始 0 */

#define MAX_BUFFER_APS_SIZE 128

uint8_t APS_Buffer[MAX_BUFFER_APS_SIZE];
mavlink_message_t current_message;
mavlink_status_t current_status;
/* 用户代码结束 0 */

/* 用户代码开始 2 */

  // 启动DMA缓冲区
  HAL_UARTEx_ReceiveToIdle_DMA(&huart4, APS_Buffer, MAX_BUFFER_APS_SIZE);
/* 用户代码结束 2 */

主循环目前为空。我已经注释掉了所有内容,所以它只是一个“continue”。

我的回调函数:

/* 用户代码开始 4 */

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
        if (huart->Instance == UART4) // aps
		{
			for (int i = 0; i < Size; i++)
			{
				uint8_t c = APS_Buffer[i];

				if (mavlink_parse_char(MAVLINK_COMM_1, c, &current_message, &current_status)) {

					ParseMavlinkMessage(current_message);


					last_msg_received_seq_number = current_message.seq;

					// 为下一次迭代清除状态
					current_status.packet_rx_drop_count = 0;
				}

			}
		}
}

void ParseMavlinkMessage(mavlink_message_t message)
{

    // 将消息发送到UART 3
    uint8_t data[MAVLINK_MAX_PACKET_LEN];
	uint16_t len = mavlink_msg_to_send_buffer(data, &message);

	HAL_UART_Transmit(&huart3, data, len, 1000);

	switch(message.msgid)
	{
		case MAVLINK_MSG_ID_OPERATIONAL_STATUS:
		{
			mavlink_msg_operational_status_decode(&message, &operational_status);
			break;
		}
        ... 其他类似的情况 ...
	}


    // 用于调试消息是否被跳过的代码...

	char msg_to_send[100];
	if(current_message.seq != (last_msg_received_seq_number +1 ) % 256)
	{
		sprintf(msg_to_send, "Autopilot Parsing Thread - Message skipped -> %d | previous message was -> %d\n\r", current_message.seq, last_msg_received_seq_number);
		HAL_UART_Transmit(&huart3, (uint8_t *)msg_to_send, strlen(msg_to_send), 1);
	}

... 一些其他逻辑 ...
}

英文:

I'm trying to read from a uart port telemetry from a pixhawk 4 device, and forward it to another.
I can read it successfully however I am skipping some messages.
I've tried using a buffer with size 1 however I believe that was one of my problems.

Thank you for your help

Here's what I have:

My buffers and how I start DMA to get the callback...


/* USER CODE BEGIN 0 */

#define MAX_BUFFER_APS_SIZE 128

uint8_t APS_Buffer[MAX_BUFFER_APS_SIZE];
mavlink_message_t current_message;
mavlink_status_t current_status;
/* USER CODE END 0 */

/* USER CODE BEGIN 2 */

  //start DMA buffers
  HAL_UARTEx_ReceiveToIdle_DMA(&amp;huart4, APS_Buffer, MAX_BUFFER_APS_SIZE);
/* USER CODE END 2 */

while loop in main is empty for now. I've commented all so it is just a "continue"

my callback:


/* USER CODE BEGIN 4 */

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
        if (huart-&gt;Instance == UART4) //aps
		{
			for (int i = 0; i &lt; Size; i++)
			{
				uint8_t c = APS_Buffer[i];

				if (mavlink_parse_char(MAVLINK_COMM_1, c, &amp;current_message, &amp;current_status)) {

					ParseMavlinkMessage(current_message);


					last_msg_received_seq_number = current_message.seq;

					// Clear the status for the next iteration
					current_status.packet_rx_drop_count = 0;
				}

			}
		}
}

void ParseMavlinkMessage(mavlink_message_t message)
{

    //sending the message to uart 3
    uint8_t data[MAVLINK_MAX_PACKET_LEN];
	uint16_t len = mavlink_msg_to_send_buffer(data, &amp;message);

	HAL_UART_Transmit(&amp;huart3, data, len, 1000);

	switch(message.msgid)
	{
		case MAVLINK_MSG_ID_OPERATIONAL_STATUS:
		{
			mavlink_msg_operational_status_decode(&amp;message, &amp;operational_status);
			break;
		}
        ... other similar cases...
	}


    //code used to debug that messages are being skipped...

	char msg_to_send[100];
	if(current_message.seq != (last_msg_received_seq_number +1 ) % 256)
	{
		sprintf(msg_to_send, &quot;Autopilot Parsing Thread - Message skipped -&gt; %d | previous message was -&gt; %d\n\r&quot;, current_message.seq, last_msg_received_seq_number);
		HAL_UART_Transmit(&amp;huart3, (uint8_t *)msg_to_send, strlen(msg_to_send), 1);
	}

...some other logic...

}

答案1

得分: 2

您的中断回调函数应尽量简短,绝对不应解析和发送数据。它应该仅管理缓冲区并返回。解析和发送操作应由主程序或者如果您使用RTOS的话,由另一个任务来执行。这是一个一般规则 - 中断处理程序必须尽量简短和快速。不要用它们来实现程序逻辑。

我鼓励您学习如何使用RTOS,因为它们可以让类似的任务变得更容易,并且已经实现了IPC机制(这样您就不必重新发明轮子),或者在您的主循环中实现复杂的状态机。

英文:

Your interrupt callback function should be as short as possible and definitely not parse and send the data. It should only manage the buffer and return. The parsing and sending should be done by the main program or another task if you use RTOS. It is a general rule - interrupt handlers have to be as short and fast as possible. Do not use them to implement program logic.

I would encourage you to learn how to use RTOS-es, as they make similar tasks much easier and have IPC mechanisms implemented (so you will not have to reinvent the wheel) or implement complicated state machines in your main loop.

huangapple
  • 本文由 发表于 2023年7月31日 19:29:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76803194.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定