【问题标题】:Weirdness using the raspberry pi pico uart with the c sdk使用带有 c sdk 的树莓派 pico uart 的奇怪之处
【发布时间】:2021-10-15 06:18:13
【问题描述】:

我非常不安。

我正在制作一台远程控制机器,使用 pi pico 驱动电机并读取一些传感器,并使用 raspberry pi 4 通过串行向 pi pico 发送命令并托管 Web 界面。

以下代码似乎可以工作...但是...如果我使用 uart_is_writable 编码删除 if 及其内容,它将不起作用。有人知道为什么吗?

#include <stdlib.h>
#include <string.h>

#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/irq.h"

//DEFINES
#define UART_ID uart0
#define BAUD_RATE 19200
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY    UART_PARITY_NONE
#define UART_TX_PIN 0
#define UART_RX_PIN 1
#define LED_PIN PICO_DEFAULT_LED_PIN

static int chars_rxed = 0;

volatile char uCommand[32] = {0, 0};

void on_uart_rx(void) {
   char tmp_string[] = {0, 0};
   new_command = true;
   while (uart_is_readable(UART_ID)) {
       uint8_t ch = uart_getc(UART_ID);
       tmp_string[0] = ch;
       strcat(uCommand, tmp_string);
       if(uart_is_writable(UART_ID)){
         uart_putc(UART_ID, '-');
         uart_puts(UART_ID, uCommand);
         uart_putc(UART_ID, '-');
       }
       chars_rxed++;
   }
}

int main(){

 uart_init(UART_ID, BAUD_RATE);

 gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
 gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);

 uart_set_hw_flow(UART_ID, false, false);

 uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);

 uart_set_fifo_enabled(UART_ID, false);

 int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;

 irq_set_exclusive_handler(UART_IRQ, on_uart_rx);
 irq_set_enabled(UART_IRQ, true);

 uart_set_irq_enables(UART_ID, true, false);

 uart_puts(UART_ID, "\nOK\n");

   while (1){
       tight_loop_contents();
       if(uCommand[0] != 0){
         uart_putc(UART_ID, '/');
         uart_puts(UART_ID, uCommand);
         memset(uCommand, 0, sizeof(uCommand));
       }
     }

}

【问题讨论】:

  • 没有上下文,我不清楚你为什么期望它会起作用。我假设它是出于某种目的而添加的,并且对方关心您发回的信息。
  • Thomas Jager 这个小片段取自覆盆子示例,理论上它可以用于发送回读取的字符。删除它不应该影响代码,但它确实会提供不同的输出,就好像它退出了中断并解释了多次发送一样。
  • 这是出自哪个具体例子?
  • 是否有代码在另一边解释事情,或者你是直接输入到串行控制台?

标签: c raspberry-pi embedded microcontroller raspberry-pi-pico


【解决方案1】:

您链接到的示例代码用于简单的 tty/echo 实现。

您需要针对您的用例对其进行调整。

因为 Tx 中断被禁用,所以发送到发送器的所有输出都必须轮询 I/O。此外,uart 中的 FIFO 已禁用,因此仅使用单个字符 I/O。

因此,uart_is_writable 来检查一个字符是否可以被传输。


链接代码...

在 Rx ISR 中回显接收到的字符。所以,它需要调用上面的函数。请注意,如果 Tx 准备好(即已满),则字符回显并丢弃

我不知道uart_putcuart_puts是否以这种方式检查准备传输。

所以,我假设他们这样做。 这意味着,如果您调用 uart_putc/uart_puts 并且 Tx 已满,则 uart 中的当前/待处理字符可能会被丢弃/损坏。

因此,应该调用uart_is_writable 来发送任何/每个字符。

或者...uart_putc/uart_puts检查并将阻塞直到uart Tx fifo中有空间可用。对于您的用例,这种阻塞是可取的。


你想要什么...

旁注:我已经在 RPi 上进行了类似的 [产品/商业级] 编程,用于通过 uart 进行电机控制,所以其中一些来自我自己的经验。

对于您的用例,您确实想要回显接收到的字符。您想将其附加到接收缓冲区。

要实现这一点,您可能需要使用环形队列:一个用于接收的字符,一个用于传输的字符。

我假设您已经[或]设计了某种简单的数据包协议来发送/接收命令。 Rpi 发送的命令是(例如):

  1. 设置电机速度
  2. 获取当前传感器数据

对方应响应这些命令并执行所需的操作或返回所需的数据。

两个处理器可能需要具有相似的服务循环和 ISR。

Rx ISR 仅检查 Rx 环队列中的可用空间。如果空间可用,它会从 uart 获取一个字符并将其排入队列。如果 uart 中没有可用的 Rx char,则 ISR 可能会退出。

基础级代码服务循环应该:

  1. 检查 uart Tx 是否可以接受另一个字符(通过 uart_is_writable),如果可以,它可以从 Tx 环队列中取出一个字符 [如果可用] 并发送它(通过 uart_putc)。它可以在此循环以保持 uart 发送器忙碌。

  2. 检查是否接收到足够的字符以形成来自另一端的数据包/消息。如果有这样的数据包,它可以为其中包含的“请求”提供服务[使字符出队以在 Rx 环队列中腾出更多空间]。

  3. 如果基础层需要发送一条消息,它应该enqueue它到Tx ring队列。它将在上一步中 [最终] 发送。


一些额外的想法......

链接代码启用 Rx 中断并以轮询模式运行 Tx。这可能就足够了。但是,为了获得最大吞吐量和最低延迟,您可能还需要驱动 Tx 中断。

您可能还希望在 uart 中启用 FIFO,以便您可以排队多个字符。这可以减少对 ISR 的调用次数并提供更好的吞吐量/延迟,因为服务循环不必如此频繁地轮询。

【讨论】:

    猜你喜欢
    • 2022-12-16
    • 2021-10-18
    • 2021-07-29
    • 2022-11-13
    • 1970-01-01
    • 2018-12-23
    • 1970-01-01
    • 1970-01-01
    • 2022-11-08
    相关资源
    最近更新 更多