硬汉嵌入式论坛

 找回密码
 立即注册
查看: 868|回复: 8
收起左侧

[以太网] stm32H743zit6使用cubemx构建LWIP+Freertos时创建udp客户端任务发送时hardfault

[复制链接]

0

主题

6

回帖

6

积分

新手上路

积分
6
发表于 2023-3-29 21:14:38 | 显示全部楼层 |阅读模式
我使用了cubemx进行freertos工程的构建并且完成了基本的ping通任务。
因为我使用的是GCC的开发环境,因此是参照的官方LWIP的历程进行的MPU的配置,并且将历程中的ld文件直接复制过来了。
具体的情况如下,目测应该是使用的axi ram作为ram的开始, 然后将以太网的DMA分配到如下位置:

[C] 纯文本查看 复制代码
_estack = 0x24080000; 
......   
.lwip_sec (NOLOAD) : {
    . = ABSOLUTE(0x30000000);
    *(.RxDecripSection) 
    
    . = ABSOLUTE(0x30000200);
    *(.TxDecripSection)
    
    . = ABSOLUTE(0x30000400);
    *(.Rx_PoolSection) 
  } >RAM_D2 AT> FLASH


在默认任务中我调用了udp_client_init()函数之前以为是任务空间小了的原因,因此给了4096,但是还是hardfault.......

[C] 纯文本查看 复制代码
void udp_client_init(void) 
{
    udp_client_task = sys_thread_new("udp_client", udp_client_thread, NULL, 4096, osPriorityNormal);
}


在任务函数中我经过调试发现在运行 netconn_send 函数处发生hardfault, 进去之后发现最后进入的入口每次都不一样...
任务函数如下,这个发送的一个数据包大概1416字节左右LARGE_BUF_SIZE=1416
[C] 纯文本查看 复制代码
 uint8_t send_buf[LARGE_BUF_SIZE] = {0XFA, 0X5A, 0XA5, 0XAA, 0x00, 0x00, 0x88, 0x88, 0x01, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00};   //帧头就地初始化

static void udp_client_thread(void *arg) 
{
    err_t err;
    ip_addr_t destipaddr;
    struct netbuf *txBuf;
    conn = netconn_new(NETCONN_UDP);
    IP4_ADDR(&destipaddr, 192, 168, 2, 1);
    err = netconn_bind(conn, IPADDR_ANY, 8090);
    err = netconn_connect(conn, &destipaddr, 8080);
    if (err == ERR_OK)
        printf("connect succ\n");
    
    for(;;)
    {  
        if(send_flag)
        {
            // 构造数据并写入数组
            ...
            txBuf = netbuf_new();     //控制块
            netbuf_alloc(txBuf, send_size);
            pbuf_take(txBuf->p, (const void *)send_buf, send_size);
            err = netconn_send(conn, buf);
            if (err != ERR_OK) 
            {
                printf("send err\n");
            }
            vTaskDelay(1000);
            netbuf_delete(txBuf);
        }
    }
}

由于官方给的历程中没有对发送的数组进行什么MPU配置, 因此我也就没有特别配置。后面专门试了一下, 找一块空地配置成没有WB和WA的NORMAL模式也不行。
MPU的环境如下:
下载+(2).png
就是和官方历程一模一样的,将DMA描述符那里设成Device模式,然后LWIP的heap区域设置成noncache的normal内存,并且禁用DTCM...
上述代码在F4的开发板中是可以完美运行的,但是扔到H7的上面就问题重重......我不清楚应该找哪一个地方的问题了,特此来请教硬汉和其它大哥们



回复

使用道具 举报

0

主题

6

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 2023-3-29 21:19:29 | 显示全部楼层
本帖最后由 576262501 于 2023-3-29 21:25 编辑

MPU部分配置代码如下:
[C] 纯文本查看 复制代码
void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x00;
  MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
  MPU_InitStruct.SubRegionDisable = 0x87;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  MPU_InitStruct.BaseAddress = 0x30000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_1KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER2;
  MPU_InitStruct.BaseAddress = 0x30004000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
 HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}


问题就出现在netconn_send这行代码中, 在conn和buf的申请中没有报错。


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106749
QQ
发表于 2023-3-30 10:45:32 | 显示全部楼层
1、硬件异常错误类型是什么,先锁定问题
2、你的主RAM空间的Cache配置的什么
3、发送没有配置是因为ST的底层发送代码做了个Cache手动处理。
4、这个将共享也设置为不使能


下载+(3).png

5、这个删掉,先不配置

QQ截图20230330104753.png
回复

使用道具 举报

0

主题

6

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 2023-3-30 14:35:00 | 显示全部楼层
eric2013 发表于 2023-3-30 10:45
1、硬件异常错误类型是什么,先锁定问题
2、你的主RAM空间的Cache配置的什么
3、发送没有配置是因为ST的 ...

感谢硬汉哥的回复!
已经将4G的那块MPU配置删掉。
我的工程是cubemx生成的,因此默认主RAM是DTCM,且主空间MPU应该就是那个默认的SRAM策略WBWA也就是cache开启的。
以下是我根据硬汉哥的指点进行的排查:
①我把0x30004000也就是LWIP的HEAP区的shareable关闭
②我发现将发送数组减小之后完全可以正常发送
具体来说就是将send_buf数组从原来的1416调整成16, 发现发送正常不会进入hardfault
③尝试找到进入hardfault的原因
根据网上资料我找到了SCB的CFSR寄存器

下载+(2).png
进入hardfault后置位的相关寄存器是precise data bus error 和 bus fault address register(BFAR) valid flag
然后继续追溯到发生错误的bus fault的address 发现是0x0166016e,但是我并不太了解具体来说是发生了什么错误
我看到后没什么反应, 不知道应不应该追溯下去是什么原因。

想问下硬汉哥,如果小的数据量可以正常发送的话,而大的数据量不行,那是不是应该往什么LWIP的堆栈大小或者是freertos的任务堆栈大小上面考虑?
回复

使用道具 举报

0

主题

6

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 2023-3-30 17:04:16 | 显示全部楼层
576262501 发表于 2023-3-30 14:35
感谢硬汉哥的回复!
已经将4G的那块MPU配置删掉。
我的工程是cubemx生成的,因此默认主RAM是DTCM,且 ...

我又猜想是分配pbuf的时候大小没分配够,因此我在pbuf_alloc的时候多加了一些。
有奇效...数据有时候还是有机会能发过去一次...
但是还是有机会在netconn_send和pbuf_free的时候会报内存错误......
我注意到,在pbuf_free报错的时候, 最后一次free的内存指针是指向了0x300022a0这个地址。
看样子是一块没有配置MPU的内存? 难道是这个问题吗? QAQ
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106749
QQ
发表于 2023-3-31 08:51:23 | 显示全部楼层
576262501 发表于 2023-3-30 14:35
感谢硬汉哥的回复!
已经将4G的那块MPU配置删掉。
我的工程是cubemx生成的,因此默认主RAM是DTCM,且 ...

对,得考虑下堆栈问题了。
回复

使用道具 举报

0

主题

6

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 2023-4-3 15:23:31 | 显示全部楼层
eric2013 发表于 2023-3-31 08:51
对,得考虑下堆栈问题了。

硬汉哥我大概找到问题了, 之前应该是调用的API不太对。
但现在又有一个新的问题,问题主要是出在我如何将自己要发送的数据数组给到LWIP的PBUF里面。
我一开始的解决方式是, 使用netbuf_ref的接口将pbuf的payload指针指向我自己的数组(定义在axi ram中0x24000008), 想着是这样可以不用再把数据复制一遍, 也许性能是最好的。
问题:但发现,stlink调试的时候单步运行的情况下一点问题没有,可以一直循环发送数据,但是将代码下下去,用电源供电程序只能发送一个数据包,然后程序卡死了...
然后我试了试调试中全速运行, 发现会在以太网的接受函数中爆出hardfault.....
下载.png
------------------------------------------------------------------------------------------------------------------------------------------------------------
然后我摸索着尝试解决,就进入netbuf_ref中, 将pbuf中payload的分配方式换成了内存pool或者内存堆都是可以完美运行!!!
我试着dbug找出这些分配方式的不同, 发现这两种思路最大的差距就是在调用udp_send的时候添加udp头部的方案不一样
使用内存池或者内存堆的复制方案会预留头部的空间也就是offset, 但是直接ref的方式没有预留空间。
anyway,

但仍然不清楚是什么原因导致会进入以太网接收函数,并且触发hardfult, 我整个工程代码中都没有任何的以太网接收的任务
------------------------------------------------------------------------------------------------------------------------------------------------------------
最终全速运行
但搞不懂,为什么是在以太网接收函数的时候进入hardfault
在出现hardfault地方打了断点好像也找不到进入hardfault的原因
下载+(1).png
而有的时候,在debug模式下全速运行, 又不会进入以太网接收函数, 并且能够顺利地一直发送数据
请教一下硬汉哥这里应该如何查找这里偶尔会进入以太网接收函数, 并进入hardfault的原因啊?
----------------------------------------------------------------------------------------------------------------------
最终能一直稳定运行的代码是这样的
[C] 纯文本查看 复制代码
    for(;;)
    {  
        if(send_flag)
        {
            //判断是大还是小的数据包
            if(cur_pkg_num == 3 || cur_pkg_num == 6) 
                send_size = SMALL_BUF_SIZE;
            else 
                send_size = LARGE_BUF_SIZE;

            netbuf_ref(buf, send_buf, send_size);
      
            err = netconn_send(conn, buf);
            if (err != ERR_OK) 
            {
                printf("send err\n");
            }
            cur_pkg_cnt += 1;
            cur_pkg_num += 1;
            if (cur_pkg_cnt >= 65535) 
                cur_pkg_cnt = 1;
            if (cur_pkg_num > 6)
                cur_pkg_num = 1;
            vTaskDelay(1000);
        }
    }
}

并且需要手动修改netbuf_ref中pbuf_alloc的参数为PBUF_POOL或者PBUF_RAM
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106749
QQ
发表于 2023-4-4 09:09:56 | 显示全部楼层
576262501 发表于 2023-4-3 15:23
硬汉哥我大概找到问题了, 之前应该是调用的API不太对。
但现在又有一个新的问题,问题主要是出在我如何 ...

在内存pool里面你申请个空间出来,替代自定义的数组(定义在axi ram中0x24000008), 也就是说使用这个内存pllo的RAM块测试。
回复

使用道具 举报

2

主题

37

回帖

43

积分

新手上路

积分
43
发表于 2024-3-20 16:36:22 | 显示全部楼层
这个应该是stm32的官方例程,我按照这个配置,现在会死在MemManage_Handler中。看着像是访问了mpu未分配的内存区域导致的,但是30000000和30004000都配置了,很疑惑
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-4 02:15 , Processed in 0.302793 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表