This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LAUNCHXL-F28379D: 关于SCI driverlib例子 以及TX FIFO的问题

Part Number: LAUNCHXL-F28379D

大家好,最近刚开始学习C2000,在尝试driverlib关于SCI例子的时候,遇到了一些问题,下面是SCI例子的连接:

https://dev.ti.com/tirex4-desktop/content/c2000_academy_2_00_00_00_all/modules/Module_8_Communications/module_8_communications_lab.html

这个例子的功能是:1. 发送字符串到PC,请求用户键入一个0-9的数字,

2. SCI读取用户键入的数字,根据这个数字调整LED的闪烁频率,同时,再把接收到的数字发送回PC,通过Terminal显示,并再次请求键入新的数字。

例子提供的源码,键入数字设定LED闪烁频率这部分功能没有问题。但是,SCI发送字符串存在下面的问题:

期望的显示的结果为:

 (这里使用的是修改过,可以正常运行的代码,其中x为用户键入的数字)

即:"  LED set to blink rate x"  + " \r\nEnter a number 0-9>"

但实际的显示结果为

 (这里使用的是例子提供的代码)

即:"  LED set"  + " r a number 0-9:"

两个应该显示的字符串分别只显示了一部分

主函数如下(我把源代码里面用来设定闪烁频率的时钟和LED Toggle删除了,因为这里我想只考虑SCI的功能):

void main(void)
{
//--- CPU Initialization
    Device_init();

//--- Configure GPIO pins LED1, SCI Rx, and SCI Tx
    Device_initGPIO();
    initGPIO();


//--- Enable global interrupts and real-time debug
    EINT;
    ERTM;

    initSCIA();


    char receivedChar;
    char* msg;
    uint16_t rxStatus,i=0,len;

    msg="\r\nHello World! Enter a number 0-9 to change the LED blink rate\n\n\0";
    len=strlen(msg);

    SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);

    for(;;)
    {

    msg= "\r\nEnter a number 0-9: \0";
    len=strlen(msg);
    SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);

    receivedChar = SCI_readCharBlockingFIFO(SCIA_BASE);
    //Turns character to digit
    delayCount = receivedChar - '0';
    rxStatus = SCI_getRxStatus(SCIA_BASE);
            if((rxStatus & SCI_RXSTATUS_ERROR) != 0)
            {
                ////If Execution stops here there is some error
                //Analyze SCI_getRxStatus() API return value//
                ESTOP0;
            }


    msg = "  LED set to blink rate \0";
    len=strlen(msg);
    SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);

    SCI_writeCharBlockingFIFO(SCIA_BASE, receivedChar);
    }

SCI A设置为8位数据,1位停止,无奇偶校验,启用FIFO。

void initSCIA(void){
//--- Initialize SCIA and its FIFO.
    SCI_performSoftwareReset(SCIA_BASE);

//--- Configure SCIA for echoback.
    SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 9600, (SCI_CONFIG_WLEN_8 |
                                                        SCI_CONFIG_STOP_ONE |
                                                        SCI_CONFIG_PAR_NONE));
    SCI_resetChannels(SCIA_BASE);
    SCI_resetRxFIFO(SCIA_BASE);
    SCI_resetTxFIFO(SCIA_BASE);
    SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_TXFF | SCI_INT_RXFF);
    SCI_enableFIFO(SCIA_BASE);
    SCI_enableModule(SCIA_BASE);
    SCI_performSoftwareReset(SCIA_BASE);


}

发送字符串使用的是  SCI_writeCharArray(SCIA_BASE,(uint16_t*)msg,len) 函数(/driverlib/sci.c)。

//*****************************************************************************
//
// SCI_writeCharArray
//
//*****************************************************************************
void
SCI_writeCharArray(uint32_t base, const uint16_t * const array,
                   uint16_t length)
{
    //
    // Check the arguments.
    //
    ASSERT(SCI_isBaseValid(base));

    uint16_t i;
    //
    // Check if FIFO enhancement is enabled.
    //
    if(SCI_isFIFOEnabled(base))
    {
        //
        // FIFO is enabled.
        // For loop to write (Blocking) 'length' number of characters
        //
        for(i = 0U; i < length; i++)
        {
            //
            // Wait until space is available in the transmit FIFO.
            //
            while(SCI_getTxFIFOStatus(base) == SCI_FIFO_TX15)
            {
            }

            //
            // Send a char.
            //
            HWREGH(base + SCI_O_TXBUF) = array[i];
        }
    }
    else 
    { 
       //....
    }
}

上面函数中,利用while判断 TX FIFO中是否仍有可用的空间,问题在于判别式

while(SCI_getTxFIFOStatus(base) == SCI_FIFO_TX15)

ti提供的代码中判别式使用的是SCI_FIFO_TX15,但我自己实验的时候,除了将判断设置为 SCI_FIFO_TX16,能够顺利实现正确的echo功能之外,

SCI_FIFO_TX0 - SCI_FIFO_TX15 都会出现上面的问题,区别在于不同的设置,漏掉的字符不同:

"  LED set to blink rate"  + "r a number 0-9:"  @ SCI_FIFO_TX1

"  LED set to blink rat" + "r a number 0-9:" @ SCI_FIFO_TX2

" LED set to blink ra" + "r a number 0-9:" SCI_FIFO_TX3

"  LED set to blink r"  + "r a number 0-9:"  @ SCI_FIFO_TX4

...

"  LED set"+ "r a number 0-9:"  @ SCI_FIFO_TX15

第一个问题是:

我不明白的是,这里FIFO到底起的什么作用,因为,例子中并没有使用 SCI中断,也没有设置发送FIFO中断层级 TXFFIL(默认为00000b),16x8 bit 的TX FIFO单纯作为缓冲来说,为什么会因为不同的判断条件,对发送结果产生不同的影响?为什么只有当判断条件中使用 SCI_FIFO_TX16时才能正常运行,而其他的不行?

第二个问题是:

有没有大神能够详细的讲解一下这个增强 FIFO的发送过程

发送FIFO的机制到底是什么,可不可以理解为CPU将TX FIFO装满之后,才会开始从TX FIFO中向TXSHF转移并从引脚依次发送?

如果需要发送的数据数N小于16个words,CPU将TX FIFO装满N个words,之后TX FIFO每移出一位,TXFFST就减1,当TXFFST=TXFFIL就会置位TXFFINT

(这是不是也是,TXFFIL默认值为00000b,TXFFST小于等于TXFFIL时,TXFFINT才会置位的原因? 意味着TX FIFO中还剩TXFFIL个words(默认为0),同时,也说明已经发出了 (N - TXFFIL)个words(默认为N)?)

如果需要发送的数据大于等于16个words,CPU将TX FIFO装满16个words,之后从TX FIFO每移出一位,TXFFST就减1,之后CPU再向TX FIFO装填1个word,TXFFST又加1,一直保持TXFFST=16,直到没有新的数据需要发送为止,之后TXFFST开始减少,最终为0

如果我上面说的没错,那是怎样判定TX FIFO装填结束,可以开始从TX FIFO向TXSHF移动的呢? 是TX FIFO_0 被装填吗? 上电初始化后TX FIFO中的每一层都为空吗?

还望大家能不吝赐教,提前谢过。

///////////////////////////////////////////////////更新/////////////////////////////////////

今天又试了一下, 发现真正的问题 并不是 SCI_writeCharArray 函数 判别式的问题, 而是 因为SCI_writeCharArray() 库函数 SCI_writeCharBlockingFIFO() 库函数 被交叉着连续调用.

原因在于: SCI_writeCharArray()中, 判别式使用的是 SCI_FIFO_TX15,  SCI_writeCharBlockingFIFO() 使用的是 SCI_FIFO_TX16.

如果这两个函数while判断使用的是相同的值,那就不会出现任何问题。

具体为什么两个函数使用不一样的比较值会造成发送结果的不一样,我还没有答案。

下面是我得到的一些思路。

单独连续调用SCI_writeCharArray() SCI_writeCharBlockingFIFO()不论使用的是SCI_FIFO_TX1-15中的哪一个, 作为比较条件,都不会出现问题.

msg="\r\nHello World! Enter a number 0-9 to change the LED blink rate\n\0";
    len=strlen(msg);

    SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);
    SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);
    SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);
    SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);

上面已经将SCI_writeCharArray()中使用的值改为SCI_FIFO_TX1,可以正常发送。

SCI_writeCharBlockingFIFO1(SCIA_BASE, 'a');
SCI_writeCharBlockingFIFO1(SCIA_BASE, 'a');
SCI_writeCharBlockingFIFO1(SCIA_BASE, 'a');

SCI_writeCharBlockingFIFO() 里使用的也修改为SCI_FIFO_TX1,也可以正常发送

但是,如果进行下面形式的交叉连续调用,则会出现问题:

SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);
SCI_writeCharBlockingFIFO1(SCIA_BASE, 'a');
SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);

例如,使用SCI_writeCharArray()发送63个字符,设SCI_FIFO_TX15, 则只会发送前48个字符。使用SCI_writeCharBlockingFIFO() ,设SCI_FIFO_TX16发送的单个字符会丢失,并且再次使用SCI_writeCharArray()发送63个字符,只会发出最后的16个字符,之前的全部会丢失,这里发出的字符数量与while判断值无关,总是16个 (刚好也是TX FIFO 的深度)。

但是,如果SCI_writeCharArray(), SCI_writeCharBlockingFIFO() 使用相同的while判断条件,交叉连续调用不会出现问题:

uint16_t SCI_FIFO=SCI_FIFO_TX1;

void main(void)
{
.....

SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);
SCI_writeCharBlockingFIFO1(SCIA_BASE, 'a');
SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);

}

void
SCI_writeCharArray1(uint32_t base, const uint16_t * const array,
                   uint16_t length)
{
...
    while(SCI_getTxFIFOStatus1(base) == SCI_FIFO)
            {
            }
         disp=array[i];
            HWREGH(base + SCI_O_TXBUF) = array[i];

}

static inline void
SCI_writeCharBlockingFIFO1(uint32_t base, uint16_t data)
{
    //
    // Check the arguments.
    //
       ASSERT(SCI_isBaseValid(base));

    //
    // Wait until space is available in the transmit FIFO.
    //
    while(SCI_getTxFIFOStatus1(base) == SCI_FIFO)
    {
    }

    //
    // Send a char.
    //
    HWREGH(base + SCI_O_TXBUF) = data;
}

上面的代码,我把库函数复制到main.c里了(所以拷贝的库函数后面都有个“1”),上面两个函数共用一个global变量SCI_FIFO作为while比较值,PC接收到的与发送的一致。

我会继续研究的,如果有答案了会再更新的,如果有人能解释一些,就再好不过了。