首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在低速MSP430上获得高速串口数据

如何在低速MSP430上获得高速串口数据
EN

Stack Overflow用户
提问于 2020-02-02 11:22:21
回答 1查看 353关注 0票数 1

我的项目有一个通过UART连接到Bluegiga蓝牙模块的MSP430。MCU必须能够从BG模块接收可变长度的消息。在当前架构中,每个接收到的字节都会产生一个通用异步收发器中断,以允许进行消息处理,并且功率限制会对MSP430的时钟速度施加限制。这使得MSP430很难跟上高于9600bps的任何通用异步收发器的速度。结果是通信接口很慢。加快数据速率会导致溢出错误、字节丢失和通信中断。

在这种情况下,如何在不牺牲数据完整性的情况下提高通信速度?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-02-02 22:38:53

通过在MSP430上使用3个可用DMA通道中的2个来填充可由CPU处理的环形缓冲区,我能够实现12倍的速度提升。这有点棘手,因为只有当大小寄存器达到零时才会产生MSP430 DMA中断,所以我不能直接填充环形缓冲区,因为消息大小是可变的。

使用一个DMA通道作为单字节缓冲区,UART接收到的每个字节都会触发该缓冲区,然后触发第二个DMA通道填充环形缓冲区。

下面是演示该方法的示例C代码。请注意,它合并了来自MSP430库的引用。

代码语言:javascript
复制
#include "dma.h"

#define BLUETOOTH_RXQUEUE_SIZE <size_of_ring_buffer>

static int headIndex = 0;
static int tailIndex = 0;

static char uartRecvByte;
static char bluetoothRXQueue[BLUETOOTH_RXQUEUE_SIZE];

/*!********************************************************************************
  * \brief Initialize DMA hardware
  *
  * \param none
  *
  * \return none
  *
  ******************************************************************************/
void init(void)
{
    // This is the primary buffer.
    //  It will be triggered by UART Rx and generate an interrupt.
    //  It's purpose is to service every byte recieved by the UART while
    //    also waking up the CPU to let it know something happened.
    //  It uses a single address of RAM to store the data, so it needs to be
    //    serviced before the next byte is received from the UART.
    //  This was done so that any byte received triggers processing of the data.
    DMA_initParam dmaSettings;
    dmaSettings.channelSelect = DMA_CHANNEL_2;
    dmaSettings.transferModeSelect = DMA_TRANSFER_REPEATED_SINGLE;
    dmaSettings.transferSize = 1;
    dmaSettings.transferUnitSelect = DMA_SIZE_SRCBYTE_DSTBYTE;
    dmaSettings.triggerSourceSelect = DMA_TRIGGERSOURCE_20; // USCA1RXIFG, or any UART recieve trigger
    dmaSettings.triggerTypeSelect = DMA_TRIGGER_RISINGEDGE;
    DMA_init(&dmaSettings);
    DMA_setSrcAddress(DMA_CHANNEL_2, (UINT32)&UCA1RXBUF, DMA_DIRECTION_UNCHANGED);
    DMA_setDstAddress(DMA_CHANNEL_2, (UINT32)&uartRecvByte, DMA_DIRECTION_UNCHANGED);

    // This is the secondary buffer.
    //  It will be triggered when DMA_CHANNEL_2 copies a byte and will store bytes into a ring buffer.
    //  It's purpose is to pull data from DMA_CHANNEL_2 as quickly as possible
    //    and add it to the ring buffer.
    dmaSettings.channelSelect = DMA_CHANNEL_0;
    dmaSettings.transferModeSelect = DMA_TRANSFER_REPEATED_SINGLE;
    dmaSettings.transferSize = BLUETOOTH_RXQUEUE_SIZE;
    dmaSettings.transferUnitSelect = DMA_SIZE_SRCBYTE_DSTBYTE;
    dmaSettings.triggerSourceSelect = DMA_TRIGGERSOURCE_30; // DMA2IFG
    dmaSettings.triggerTypeSelect = DMA_TRIGGER_RISINGEDGE;
    DMA_init(&dmaSettings);
    DMA_setSrcAddress(DMA_CHANNEL_0, (UINT32)&uartRecvByte, DMA_DIRECTION_UNCHANGED);
    DMA_setDstAddress(DMA_CHANNEL_0, (UINT32)&bluetoothRXQueue, DMA_DIRECTION_INCREMENT);

    DMA_enableTransfers(DMA_CHANNEL_2);
    DMA_enableTransfers(DMA_CHANNEL_0);
    DMA_enableInterrupt(DMA_CHANNEL_2);
}

/*!********************************************************************************
  * \brief DMA Interrupt for receipt of data from the Bluegiga module
  *
  * \param none
  *
  * \return none
  *
  * \par Further Detail
  * \n Dependencies:   N/A
  * \n Processing:     Clear the interrupt and update the circular buffer head
  * \n Error Handling: N/A
  * \n Tests:          N/A
  * \n Special Considerations: N/A
  *
  ******************************************************************************/
void DMA_Interrupt(void)
{
    DMA_clearInterrupt(DMA_CHANNEL_2);
    headIndex = BLUETOOTH_RXQUEUE_SIZE - DMA_getTransferSize(DMA_CHANNEL_0);

    if (headIndex == tailIndex)
    {
        // This indicates ring buffer overflow.
    }
    else
    {
        // Perform processing on the current state of the ring buffer here.
        // If only partial data has been received, just leave.  Either set a flag
        // or generate an event to process the message outside of the interrupt.
        // Once the message is processed, move the tailIndex.
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60022971

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档