10 finsh组件使用遇到的疑难杂症(已解决,实际是底层移植出错)

发布于 2021-03-29 01:32:46

(次日更新)谢谢评论区的各位老哥,已经破案了

按评论区里各位老哥的建议,我今天近下来思考了一下,然后单步调试一步步找错误,最终发现是我的finsh底层接收字符部分移植出错。具体错误会在下面描述,希望大家不要范和我一样的错误。

官方的接收字符是自己建立了一个FIFO的队列,然后结合信号量使用,代码比较多。我的这套移植代码是从上一个硬件平台一直用过来的,当时为了偷懒就想说反正邮箱也是FIFO的,直接用邮箱传就行,最多浪费点内存,4个btye当1个用。但是在邮箱的初始化时,我的邮箱容量赋值错了,代码如下。

static char shell_rx_mb_pool[4*15];   //邮箱缓存使用char声明的

err = rt_mb_init( &shell_rx_mb,
          "rxMail",
          shell_rx_mb_pool,
          sizeof(shell_rx_mb_pool), //所以这个地方应该除4
          RT_IPC_FLAG_FIFO);

由于代码中,初始化时输入的邮箱的容量比实际的邮箱缓存shell_rx_mb_pool数组要大,所以就导致了溢出,RAM中的其他变量受到影响。

最后,再次感谢评论区的各位老哥!!

以下是原问题描述

今天在调试LCD液晶屏幕时遇到一个非常神奇的bug,硬件平台为stm32f411ceu6核心板,软件移植的Nano+finsh。我发现输入命令达到一定次数的时候,finsh会影响到我程序中的全局变量。问题具体描述如下:
为了调试LCD驱动移植是否正常,我自定义了一条命令来执行LCD的刷屏,并反馈花费的刷屏时间。自定义命令以及调用的刷屏函数代码如下:

uint8_t msh_clear = 0;
static void msh_LCD_Clear(void)
{
    rt_tick_t ftime, ltime;
    uint16_t msh_clear_color[3] = {GREEN, YELLOW, BLUE};
    
    ++msh_clear;
    if(msh_clear > 2) msh_clear = 0;
    
    ftime = rt_tick_get();
    LCD_Clear(msh_clear_color[msh_clear]);
    ltime = rt_tick_get();

    rt_kprintf("%d\r\n", ltime - ftime);
}
MSH_CMD_EXPORT_ALIAS(msh_LCD_Clear, lcd_clear, NULL);

//被调用的清屏函数
void LCD_Clear(uint16_t Color)
{
      unsigned int i,m;  
    
    LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1); 
    LCD_CS_CLR;
    LCD_RS_SET;
    
    for(i=0;i<lcddev.height;i++)
    {
        for(m=0;m<lcddev.width;m++)
        {    
                LCD_FastWrite_16Bit(Color);
        }
    }
     LCD_CS_SET;
} 

该命令使用正常,LCD可以正常的刷屏,并统计花费的时间。但在多次执行该命令后,会发生错误,刷屏动作会失效,返回花费的时间为0。下面附上命令行输出图片:
93a0ede4b88bc1045950822a664717a.png
然后,我进行了debug调试,发现发生错误的原因是在执行命令时,上面清屏函数LCD_Clear()中使用到的全局结构体类型变量lcddev被改变了。下图为keil监视窗口:
58642fe32a7a7369c2c15489473ed3a.png
本来,height和width的值应该分别为480和320,对应十六进制表达为0x1E0和0x140。图中所示的值明显不对,而且其他成员变量也被改变。我开始怀疑是finsh线程堆栈溢出了,但实际使用ps命令查看发现并没有溢出,如下图。
2a39d51c7117ebebf8922f1b97a96e9.png
然后,我发现这个错误出现的时机大概就是在第13次调用lcd_clear命令。但是,如果在之前执行过其他命令,这个次数会缩短,见下图。
3eb0862c92c3bd1c7e44255b1583a42.png
如图可见,上头使用了很多其他命令,然后这个错误在第7次调用lcd_clear命令时就出现了。
本身命令代码中没有任何的对全局变量lcddev的赋值,对这个变量的赋值只在初始化LCD的时候,后面刷写LCD都不执行赋值动作。同时,为了排除是本身LCD驱动程序的问题,我在main线程中调用LCD_Clear()函数进行刷屏,代码如下:

int main(void)
{
    
    uint8_t num = 0;
    uint16_t msh_clear_color[6] = {GREEN, YELLOW, BLUE, RED, BROWN, BLACK};
    MX_GPIO_Init();
    

    while (1)
    {

        LCD_Clear(msh_clear_color[num++]);
        if(num > 5) num = 0;
        rt_thread_mdelay(500);
        

        LCD_Clear(msh_clear_color[num++]);
        if(num > 5) num = 0;
        rt_thread_mdelay(300);
    }

}

代码烧录后运行一切正常,可以一直刷屏下去,并没有次数限制。于是基本可以确定是finsh影响到了全局变量lcddev,但是我并不明白其中原因。按我的理解finsh命令的执行都在tshell线程中,命令函数的出入栈应该使用的都是tshell的线程栈,只要线程栈不溢出,没有理由会影响到RAM中其他的变量。
求各位大神解惑!!!

查看更多

关注者
0
被浏览
198
张世争
张世争 2021-03-29
  • 出现问题可以大胆的怀疑,假定,但不能断定,否则影响自己的思路。
  • 既然可以软件调试,可以查看调用函数,数据是由那个函数调用,如何被修改的
  • 这款芯片RAM够大,建议把每个线程栈加大一点。
  • 不排除其他线程的异常操作,指针操作,修改了数据
  • MSH命令工作时可能申请内存,但不至于影响全局变量。
3 个回答
flashman2002
flashman2002 2021-03-29

建议单步调试,追踪全局变量的变化。

mii
mii 2021-03-29

你查看一下是不是代码优化等级的问题

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览