解决。 问题是在调试会话之外使用指向包含指向环缓冲区的指针的串行驱动程序对象的全局指针不起作用。 使用全局驱动程序指针时,缓冲区指针为NULL。 使驱动程序指针为本地解决了问题,请参阅下面的内容。
我的猜测是,全局(指针和对象)在调试会话内部和外部的初始化方式不同。
来自RS485_DRIVER.HPP的代码片段:
//在调试会话之外使用指向驱动程序对象的全局指针不起作用。
//RS485Driver *RS485 = ProcessorC28::Instance.GetRS485Driver();
int CliUartWrite (int fileDescriptor, const char *buffer,unsigned count)
{//
我们必须使用本地指针而不是全局指针。
//否则,SendChar将发现指向其类的环缓冲区的指针为NULL。
RS485Driver *RS485 = ProcessorC28::Instance.GetRS485Driver();
RS485->SetBusTxMode(GPIO::eHIGH);
返回RS485->SendCharBuffer((Char *)缓冲区,计数);
}
我保留了问题描述的第一个版本(见下文),但我认为我的问题是启用SCI TX fifo中断时未触发(sciRegisters->SCIFFTX.bit.TXFFIENA =1;)。 我的SendCharBuffer函数填充环缓冲区,然后启用此中断。 所有操作都可以在调试会话中工作,但不能在调试会话之外工作。 当我在发送前几个字符之前将stdio连接到串行驱动程序时,它还可以在调试会话之外工作。
Int SerialPortUartDriver::SendCharBuffer(Char *pBuf, int len)
{
int buffersize = buffers->bufferSizeTx;
如果(buffersize <= len)
{
返回-1;
}
//获取环形缓冲区的当前容量。
UINT16_t indexHead = buffers->indexTxHead;//
等待容量变得足以容纳数据。
while (GetCapacityTx(indexHead)<=(len +1));
//将数据复制到环形缓冲区中。
char *buffer = buffers->bufferTx + indexHead;
而(len--)
{
*BUFF++=*pBuf++;
IF (++indexHead >= buffersize)
{
索引头=0;
缓冲区=缓冲区->bufferTx
;}
}
buffers->indexTxHead = indexHead;
//启用FIFO中断。 如果环形缓冲区为空,ISR将禁用它。
volatile SCI_regs *sciRegisters =
#ifdef调试
通道== SCI_B ?
&ScibRegs:
#endif
&ScicRegs;
sciRegisters->SCIFFTX.bit.TXFFIENA =1;//
等待第一个字节进入FIFO。
//while (sciRegisters ->SCICTL2.bit.TXEMPTY ==1);
返回len
;}
我实施了一项功能,在启动时将stdio切换为SCI_B (RS485),然后允许在SCI_B和SCI_C之间切换stdio 它在调试会话中工作,但同一项目配置(调试,无优化,调试配置/目标中的CIO功能已禁用)在调试会话之外不工作。
要再现:
- 在终端窗口中打开PC上相应的COM端口。 在我的情况下,SCI_B (RS232)连接到COM6,SCI_C (RS485)连接到COM1。 两者均以11.52万波特率运行。
- 启动调试会话。 ->应用程序初始化外围设备,将stdio切换到SCI_C (参见下面的功能),并将测试菜单打印到COM1。
- 用户从测试菜单中选择Switch stdio (切换心脏)。 ->应用程序调用开关功能(参见下文)。
- 如果存在当前设备(例如,连接到SCI_B的stdio),切换功能将删除该设备, 添加连接到SCI_C的stdio设备并返回。
- 开关测试功能打印测试菜单。 由于stdio已被切换,菜单将通过SCI_B打印到COM6。
以下是在调试会话中运行时终端的日志。
COM1 / RS485 (正在切换至stdio):
stdout现在使用SCI-C
Stdin现在使用SCI-C
Stdio现在使用SCI-C
SM320F2.8335万处理器已初始化...
测试菜单-版本0.3 .........0
0采集-采集波形(<channel[0..2]>,<average count>,<delay in ms
...
COM6/RS232 (已初始化SCI_C外设):
Stdio现在使用SCI-C
...
调试会话之外的日志在COM1上不显示任何内容,在COM6上显示相同的行(如预期)。
---------------- stdio切换功能-------------------------------
CliReturnCode CLI:::CliCommand_switchCli (CLI *pCli,CliCommand *pCmd,CliParams *pParams)
{
int returnValue;
bool
Cli ToCli = false;if (pParams->numParams ==2){ switchToCli =(atoi(pParams->str[1])>0);} else if (pParams->numParams >2){ switchToams = true;
//串行驱动程序中的todo实现SetBaud()。
// clockSpeedRS485 = atol(pParams->str[2]);
}
IF (switchToCli == true)
{//
printf("stdin和stdout正切换到SCI-C\r\n");//
Switch stdout和stdin切换到SCI-C
#ifdef debug
if (ProcessorC28::Instance.GetStdioUart()== ProcessorC28::stdio_RS232)
{//
删除使用SCI-B的stdout和stdin调试设备。
extern char *DebugFname;DebugValue
= remove_device_device(debrreturn_device)(crretrreturn.char
=<rendr\n)=<rendrendrendr\n\retrendrendrendr\n)=
<rendrendrendr\n(
Return eCliReturn_failed;
}
ProcessorC28::Instance.SetStdioUart(ProcessorC28::stdio_none);
}
#endif
returnValue = add_device (cliFname,_MSA,CliUartOpen,CliUartClose,CliUartRead, CliUartWrite,NULL,NULL);
IF (returnValue)
{
const char *cliErrorAdd ="Error adding SCI-C devices\r\n";
CliUartWrite(0),cliErrorAdd,strlen(cliErrorAdd));
reteCliReturn_failed;
}
file *fid = fopen(clifname,"w");
freopen(clifnameReopen,"w", stdout; //将stdout重定向到UART
setvbuf (stdout,NULL,_IONBF,0);//关闭stdout
printf的缓冲("stdout现在使用SCI-C.\r\n");
fid = fopen (cliFname,"r");
freopen (cliFnameReopen,"r", stdin);//将stdin重定向到UART
setvbuf (stdin,NULL,_IONBF,0);//关闭stdin
printf的缓冲("stdin现在使用SCI-C.\r\n");
const char *cliSwitchSuccessess ="stdio现在使用SCI-C\r\n";
//下面的行证明在调试会话之外执行了此函数。
DebugUart.SendCharBuffer((car *) cliSwitchSuccessess,strlen(cliSwitchSuccessess));
RS485->SendCharBuffer((car *) cliSwitchSuccessess,strlen(cliSwitchSuccessess));
ProcessorC28::Instance.SetStdioUart(ProcessorC28::stdio_RS485);
}
否则
{
returnValue = remove_device(clifname);
if (returnValue)
{
return eCliReturn_failed;
}
pCli->dCliNextState = eCliState_Exit;
#ifdef debug
returnValue = DebugUartAsStdio(ProcessorC28::Instance.GetCpuClockHz());
if (SpeedReturnValue)
{ SpeedReturn_Success
}