stm32H743zit6使用cubemx构建LWIP+Freertos时创建udp客户端任务发送时hardfault
我使用了cubemx进行freertos工程的构建并且完成了基本的ping通任务。因为我使用的是GCC的开发环境,因此是参照的官方LWIP的历程进行的MPU的配置,并且将历程中的ld文件直接复制过来了。
具体的情况如下,目测应该是使用的axi ram作为ram的开始, 然后将以太网的DMA分配到如下位置:
_estack = 0x24080000;
......
.lwip_sec (NOLOAD) : {
. = ABSOLUTE(0x30000000);
*(.RxDecripSection)
. = ABSOLUTE(0x30000200);
*(.TxDecripSection)
. = ABSOLUTE(0x30000400);
*(.Rx_PoolSection)
} >RAM_D2 AT> FLASH
在默认任务中我调用了udp_client_init()函数之前以为是任务空间小了的原因,因此给了4096,但是还是hardfault.......
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
uint8_t send_buf = {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的环境如下:
就是和官方历程一模一样的,将DMA描述符那里设成Device模式,然后LWIP的heap区域设置成noncache的normal内存,并且禁用DTCM...
上述代码在F4的开发板中是可以完美运行的,但是扔到H7的上面就问题重重......我不清楚应该找哪一个地方的问题了,特此来请教硬汉和其它大哥们{:19:}
本帖最后由 576262501 于 2023-3-29 21:25 编辑
MPU部分配置代码如下:
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、硬件异常错误类型是什么,先锁定问题
2、你的主RAM空间的Cache配置的什么
3、发送没有配置是因为ST的底层发送代码做了个Cache手动处理。
4、这个将共享也设置为不使能
5、这个删掉,先不配置
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寄存器
进入hardfault后置位的相关寄存器是precise data bus error 和 bus fault address register(BFAR) valid flag
然后继续追溯到发生错误的bus fault的address 发现是0x0166016e,但是我并不太了解具体来说是发生了什么错误
我看到后没什么反应, 不知道应不应该追溯下去是什么原因。
想问下硬汉哥,如果小的数据量可以正常发送的话,而大的数据量不行,那是不是应该往什么LWIP的堆栈大小或者是freertos的任务堆栈大小上面考虑?
576262501 发表于 2023-3-30 14:35
感谢硬汉哥的回复!
已经将4G的那块MPU配置删掉。
我的工程是cubemx生成的,因此默认主RAM是DTCM,且 ...
我又猜想是分配pbuf的时候大小没分配够,因此我在pbuf_alloc的时候多加了一些。
有奇效...数据有时候还是有机会能发过去一次...
但是还是有机会在netconn_send和pbuf_free的时候会报内存错误......
我注意到,在pbuf_free报错的时候, 最后一次free的内存指针是指向了0x300022a0这个地址。
看样子是一块没有配置MPU的内存? 难道是这个问题吗? QAQ 576262501 发表于 2023-3-30 14:35
感谢硬汉哥的回复!
已经将4G的那块MPU配置删掉。
我的工程是cubemx生成的,因此默认主RAM是DTCM,且 ...
对,得考虑下堆栈问题了。 eric2013 发表于 2023-3-31 08:51
对,得考虑下堆栈问题了。
硬汉哥我大概找到问题了, 之前应该是调用的API不太对。
但现在又有一个新的问题,问题主要是出在我如何将自己要发送的数据数组给到LWIP的PBUF里面。
我一开始的解决方式是, 使用netbuf_ref的接口将pbuf的payload指针指向我自己的数组(定义在axi ram中0x24000008), 想着是这样可以不用再把数据复制一遍, 也许性能是最好的。
问题:但发现,stlink调试的时候单步运行的情况下一点问题没有,可以一直循环发送数据,但是将代码下下去,用电源供电程序只能发送一个数据包,然后程序卡死了...
然后我试了试调试中全速运行, 发现会在以太网的接受函数中爆出hardfault.....
------------------------------------------------------------------------------------------------------------------------------------------------------------
然后我摸索着尝试解决,就进入netbuf_ref中, 将pbuf中payload的分配方式换成了内存pool或者内存堆都是可以完美运行!!!
我试着dbug找出这些分配方式的不同, 发现这两种思路最大的差距就是在调用udp_send的时候添加udp头部的方案不一样。
使用内存池或者内存堆的复制方案会预留头部的空间也就是offset, 但是直接ref的方式没有预留空间。
anyway,
但仍然不清楚是什么原因导致会进入以太网接收函数,并且触发hardfult, 我整个工程代码中都没有任何的以太网接收的任务
------------------------------------------------------------------------------------------------------------------------------------------------------------
最终全速运行
但搞不懂,为什么是在以太网接收函数的时候进入hardfault
在出现hardfault地方打了断点好像也找不到进入hardfault的原因
而有的时候,在debug模式下全速运行, 又不会进入以太网接收函数, 并且能够顺利地一直发送数据
请教一下硬汉哥这里应该如何查找这里偶尔会进入以太网接收函数, 并进入hardfault的原因啊?
----------------------------------------------------------------------------------------------------------------------
最终能一直稳定运行的代码是这样的
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
576262501 发表于 2023-4-3 15:23
硬汉哥我大概找到问题了, 之前应该是调用的API不太对。
但现在又有一个新的问题,问题主要是出在我如何 ...
在内存pool里面你申请个空间出来,替代自定义的数组(定义在axi ram中0x24000008), 也就是说使用这个内存pllo的RAM块测试。 这个应该是stm32的官方例程,我按照这个配置,现在会死在MemManage_Handler中。看着像是访问了mpu未分配的内存区域导致的,但是30000000和30004000都配置了,很疑惑
页:
[1]