【问题标题】:Too much time taking for the copy the data复制数据花费的时间太多
【发布时间】:2023-03-17 01:48:01
【问题描述】:

我对 for 循环复制的时间有一些问题,我不明白为什么 for 循环会花费大量时间来复制小数据大小。 我正在使用 PIC24FJ256GL406 MCU,一切都很好,但是在操作 UART 微控制器时运行缓慢,因为在复制缓冲区数据时会出现一些延迟。 让我用代码和调试日志给你解释一下。

这里我发布了UART传输的功能。该函数一般只传输第一个字符,其余字节将在中断程序服务中传输。

我的时钟频率是 32Mhz 所以外围设备将是 16 Mhz。

我不明白为什么 for 循环只复制 16 字节数据需要将近 20 毫秒。所以如果数据更多,这个时间会增加。

unsigned int UART1_WriteBuffer(const uint8_t *buffer, const unsigned int bufLen)
{
    //transmit first char

    U1TXREG = buffer[0];

    while (!U1STAbits.TRMT);

    numBytesWritten = bufLen - 1;

    totalByte = 0;

    //get the current time stamp
    WSTimestamp currentTimeStamp = WSGetCurrTimestamp();

    WMLogInfo(GEN_LOG, "current time stamp %ld", currentTimeStamp);

    uint16_t i = 0;

    //memset
    memset(&uart1_txByteQ, 0x00, sizeof(uart1_txByteQ));
    
    for (i = 0; i < numBytesWritten; i++)
    {
        uart1_txByteQ = buffer[i + 1]; //copy the data
    }
    
    _U1TXIE = 1;

    //get last time stamp
    WSTimestamp lastTimeStamp = WSGetCurrTimestamp();

    WMLogInfo(GEN_LOG, "last time stamp %ld ", lastTimeStamp);
     
    ///print the debug
    WMLogInfo(GEN_LOG, "total = %ld MS time taken fo copy the = %d byte", lastTimeStamp - currentTimeStamp, numBytesWritten);

    return bufLen;

}

My Interrupt Routine service.

void __attribute__((interrupt, no_auto_psv)) _U1TXInterrupt(void)
{
    if (totalByte < numBytesWritten)
    {
        U1TXREG = uart1_txByteQ[totalByte++];

        while (!U1STAbits.TRMT);
    }
    else
    {
        _U1TXIE = 0;
        _U1TXIE = 0;
    }

}
 
Console Log.
This is function log. please note.

GEN:main loop current time stamp 6503<\r><\n>
GEN:current time stamp 6506<\r><\n>
GEN:last time stamp 6526 <\r><\n>
GEN:total = 20 MS time taken fo copy the = 16 byte<\r><\n>
GEN:command "AT+QREFUSECS=1,1<\r>" send with len [17]

【问题讨论】:

  • 什么uart1_txByteQ?它是一个数组吗?然后像uart1_txByteQ = buffer[i + 1]; 这样的分配没有意义,甚至不应该建立。请尝试创建minimal reproducible example 向我们展示。
  • 如果你想复制,为什么不使用memcpy
  • @Someprogrammerdude 是 uart1_txByteQ 是一个数组。如您所见,函数中只有 buf[0] 字符正在传输,其余字符将在中断例程中传输,因此 uart1_txByteQ 是全局数组,因此我将缓冲区 [i+1] 复制到 uart1_txByteQ,因为已经传输了 1 个字符。
  • 您在中断中等待传输字节while (!U1STAbits.TRMT); 并浪费时间。也许,如果可能的话,你应该在U1TXREG = xx之前做一些ready-test
  • 这是一个传输中断。当它发生时,加载 tx 寄存器。不要通过“Go”,不要通过毫无意义的轮询收集任何延迟。当处理程序中没有更多要发送的内容时,禁用中断。当有缓冲区要发送时,检查中断是否被禁用,如果是,则启用它并将第一个字符加载到 tx 寄存器中。

标签: c for-loop microcontroller uart


【解决方案1】:

长时间的延迟是由忙于等待标志和一些用例错误引起的。如果您打算忙于等待轮询标志,为什么首先使用 Tx 中断? ISR 没有意义 - 看起来您应该完全放弃 Tx 中断。

此外,您还有一个简单的缓冲区副本实现。不必要地硬拷贝 RAM 缓冲区是一个非常常见的嵌入式系统初学者错误。在极少数情况下,您实际上需要进行硬拷贝,而这不是一个。相反,您应该使用具有双缓冲区的系统并简单地在它们之间交换一个指针:

static uint8_t buf1 [n];
static uint8_t buf2 [n];
static uint8_t* rx_buf = buf1;   // buffer used by rx ISR
static uint8_t* app_buf = buf2;  // buffer used by the application

...

if(rx_done)
{ // swap buffers
  uint8_t* tmp = rx_buf;
  rx_buf = app_buf;
  app_buf = tmp;
}

这也解决了双缓冲问题,即 UART 接收中断需要在主程序使用数据的同时将其传入数据存储在某处。您需要以某种方式防止竞争条件 - 使用信号量等。并且您需要声明与 ISR volatile 共享的变量,以防止不良的编译器优化器。

【讨论】:

  • 这里缓冲区没有问题。这里的问题是我有一个 1024 字节的数据,我必须将其传输到 UART 中断所以我编写了仅传输第一个字符的函数,其余的将通过中断服务传输。由于在传输功能中同时打开,所以它正在保持过程中。为了避免我这样做了。
猜你喜欢
  • 2016-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-08
  • 1970-01-01
  • 2012-04-02
  • 1970-01-01
相关资源
最近更新 更多