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的功能):

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

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

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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);
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

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

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//*****************************************************************************
//
// 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))
{
//
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

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

Fullscreen
1
while(SCI_getTxFIFOStatus(base) == SCI_FIFO_TX15)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

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中的哪一个, 作为比较条件,都不会出现问题.

Fullscreen
1
2
3
4
5
6
7
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);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

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

Fullscreen
1
2
3
SCI_writeCharBlockingFIFO1(SCIA_BASE, 'a');
SCI_writeCharBlockingFIFO1(SCIA_BASE, 'a');
SCI_writeCharBlockingFIFO1(SCIA_BASE, 'a');
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

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

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

Fullscreen
1
2
3
SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);
SCI_writeCharBlockingFIFO1(SCIA_BASE, 'a');
SCI_writeCharArray1(SCIA_BASE,(uint16_t*)msg,len);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

例如,使用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判断条件,交叉连续调用不会出现问题:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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];
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

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

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