eclipse-threadx / netxduo

Eclipse ThreadX - NetXDuo is an advanced, industrial-grade TCP/IP network stack designed specifically for deeply embedded real-time and IoT applications
https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/netx-duo/index.md
MIT License
230 stars 131 forks source link

NX_PHYSICAL_HEADER修改为14后,DHCP IP Checksum计算错误 #110

Closed chengshuihang closed 2 years ago

chengshuihang commented 2 years ago

您好,我的以太网驱动是USB ECM,为了使能USB DMA功能我需要4字节对齐,当NX_PHYSICAL_HEADER为16时,在USB需要设置以太网帧包头(14字节),这将导致数据包地址不是4字节对齐的,因此我需要将NX_PHYSICAL_HEADER修改为14.设置完成后,我发现DHCP计算的IP Checksum与NX_PHYSICAL_HEADER为16的IP Checksum不一致,且NX_PHYSICAL_HEADER为14时,DHCP服务器不会响应。 下面截图是两次DHCP报文 image 我该怎么样,才能达成目的?

bo-ms commented 2 years ago

Hi @chengshuihang 谢谢你的提问,NX_PHYSICAL_HEADER定义成16是为了保证TCP/IP 头四字节对齐,可以参考这个issue106看是否能够解决问题。

chengshuihang commented 2 years ago

我看了https://github.com/azure-rtos/netxduo/issues/106,我与他的目的的一致的。但是在解答中没有提供 零拷贝 DMA的解决方案。看来只能放弃了,这个后续不考虑,添加下吗?毕竟DMA偏移功能不是都有的

bo-ms commented 2 years ago

保证4字节对齐是为了提高效率,不需要1字节1字节的进行解析和处理,这是NetXDuo的处理方法。遇到DMA没有偏移功能的,可能需要准备一个buffer复制数据,然后再传输给NetX。

xiaocq2001 commented 2 years ago

About USB DMA that is based on STM32 HCD, it seems there is no zero-copy solution the rough code attempt to create copy of aligned buffer could be: In ux_hcd_stm32_request_bulk_transfer.c, change code to allocate aligned cache safe buffer for DMA, and copy data:

#if 1 /* Auto align buffer - allocate and copy if buffer is unaligned.  */
    /* In case DMA enabled, check data buffer alignment.  */
    ed -> ux_stm32_ed_data = transfer_request->ux_transfer_request_data_pointer;
    if (hcd_stm32 -> hcd_handle -> Init.dma_enable &&
        length > 0 &&
        ((ULONG)ed -> ux_stm32_ed_data & (~0x3ul)) != 0)
    {
        /* Allocate new aligned cache safe memory.  */
        ed -> ux_stm32_ed_data = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, length);
        if (ed -> ux_stm32_ed_data == UX_NULL)
            return(UX_MEMORY_INSUFFICIENT);
        /* Copy data if it's OUT.  */
        if (direction == 0)
            _ux_utility_memory_copy(ed -> ux_stm32_ed_data, transfer_request->ux_transfer_request_data_pointer, length);
    }

    /* Submit the transfer request.  */
    HAL_HCD_HC_SubmitRequest(hcd_stm32 -> hcd_handle, ed -> ux_stm32_ed_channel,
                             direction,
                             EP_TYPE_BULK, USBH_PID_DATA,
                             ed -> ux_stm32_ed_data,
                             length, 0);
#else
    /* Submit the transfer request.  */
    HAL_HCD_HC_SubmitRequest(hcd_stm32 -> hcd_handle, ed -> ux_stm32_ed_channel,
                             direction,
                             EP_TYPE_BULK, USBH_PID_DATA,
                             transfer_request->ux_transfer_request_data_pointer,
                             length, 0);
#endif

In ux_hcd_stm32_callback.c::HAL_HCD_HC_NotifyURBChange_Callback, change code to use allocated buffer and free it after transfer done:

#if 1 /* Auto align buffer - request again.  */
                        /* Submit the transmit request.  */
                        HAL_HCD_HC_SubmitRequest(hcd_stm32 -> hcd_handle, ed -> ux_stm32_ed_channel,
                                 0, ed -> ux_stm32_ed_type, USBH_PID_DATA, 
                                 ed -> ux_stm32_ed_data +
                                    transfer_request -> ux_transfer_request_actual_length, 
                                 ed -> ux_stm32_ed_packet_length, 0);
#else
                        /* Submit the transmit request.  */
                        HAL_HCD_HC_SubmitRequest(hcd_stm32 -> hcd_handle, ed -> ux_stm32_ed_channel,
                                 0, ed -> ux_stm32_ed_type, USBH_PID_DATA, 
                                 transfer_request->ux_transfer_request_data_pointer +
                                    transfer_request -> ux_transfer_request_actual_length, 
                                 ed -> ux_stm32_ed_packet_length, 0);
#endif
#if 1 /* Auto align buffer - copy and free buffer (if allocated).  */
            if (ed -> ux_stm32_ed_data != transfer_request -> ux_transfer_request_data_pointer)
            {
                if (ed -> ux_stm32_ed_dir)
                {
                    _ux_utility_memory_copy(transfer_request -> ux_transfer_request_data_pointer,
                                            ed -> ux_stm32_ed_data,
                                            transfer_request -> ux_transfer_request_actual_length);
                }
                _ux_utility_memory_free(ed -> ux_stm32_ed_data);
                ed -> ux_stm32_ed_data = UX_NULL;
            }
#endif

            /* Invoke callback function.  */
            if (transfer_request -> ux_transfer_request_completion_function)
                transfer_request -> ux_transfer_request_completion_function(transfer_request);

In ux_hcd_stm32_endpoint_destroy.c and ux_hcd_stm32_endpoint_reset.c, add code to free allocated buffer on abnormal stops:

#if 1 /* Auto align buffer - free buffer (if allocated).  */
    if (ed -> ux_stm32_ed_data &&
        ed -> ux_stm32_ed_data != endpoint -> ux_endpoint_transfer_request -> ux_transfer_request_data_pointer)
        _ux_utility_memory_free(ed -> ux_stm32_ed_data);
#endif
chengshuihang commented 2 years ago

谢谢!

bo-ms commented 2 years ago

Closing

chengshuihang commented 1 year ago

@xiaocq2001 您好!我按照您的方案进行了一些修改,使用的STM32H743,打开了高速缓存,现在USB它可以完成枚举,但是无法完成DHCP,我无法确认我bulk是否正确,您能帮我确认下吗?截图是修改的位置,附件中是修改后的文件。 ux_hcd_stm32_request_bulk_transfer.c修改内容: image image ux_hcd_stm32_periodic_schedule.c修改内容: image image ux_hcd_stm32_request_control_transfer.c修改内容: image image image image image ux_hcd_stm32_callback.c修改内容: image image image image image ux_hcd_stm32.h修改内容: image usb_dma.zip

xiaocq2001 commented 1 year ago

The use of transfer_request -> ux_transfer_request_packet_length is not safe, since in upper layer it's used as a base to check if short packet is expected, please use some driver local field to replace it, e.g., UX_HCD_STM32_ED::ux_stm32_ed_packet_length. Leave it unchanged in HCD.

chengshuihang commented 1 year ago

我不确定是不是transfer_request -> ux_transfer_request_packet_length原因,我运行一段时间后,系统中会发生死锁,死锁位置是_ux_utility_memory_allocate,非常无奈,我将_ux_utility_memory_free移回各个_ux_utility_memory_allocate的函数里面,保证了数据同步,这样系统不会再发生死锁了,然后我发现软件中会出现数据翻转的错误,我正在排查问题。截图如下: image 这是端点信息 image

xiaocq2001 commented 1 year ago

transfer_request -> ux_transfer_request_packet_length is used in upper layer as max packet size for zero length packet appending check. E.g., in CDC-ECM if OUT total length is multiple of this packet length, a ZLP is appended to terminate the transfer. That's why you can see a 0 byte OUT follows 42 bytes OUT in your tracing figure.

chengshuihang commented 1 year ago

是的,这个空包是正常的,但是两次数据包都是DATA1,却让我无法理解

chengshuihang commented 1 year ago

image 现在驱动发送0长度数据包,DATA0/DATA1不会切换,关闭dma是正常的,我需要找下问题。

chengshuihang commented 1 year ago

image 驱动这里,当长度为0时,dma打开之后数据包不会翻转,不开dma会翻转,同理这个问题在in中也存在如下图 image 我明天尝试修改这里,看看能不能正常工作

xiaocq2001 commented 1 year ago

Yes. It's a bug in HAL, hhcd->hc[ch_num].xfer_count should be used instead of hhcd->hc[ch_num].XferSize

liydu commented 1 year ago

A fix is underway from ST and will release soon.

chengshuihang commented 1 year ago

@liydu 非常感谢,另外这个最新USB驱动库好像还是有点问题。如果不使用dma的话,数据发送了一段时间后会停止发送。我添加了一些输出代码,用于输出信息吗,观测现象

xiaocq2001 commented 1 year ago

Thanks for sharing the debugging information. Not sure which version of STM HAL you are using, but I'll share it with ST.

chengshuihang commented 1 year ago

IDE是STM32CubeIDE 1.12.0,软件包是HAL版本是H7的1.11.0,使用ECM做主机,用中断进行通信。上面的修改在移除测试代码test_can_send后,还是不能正常工作。我之后修改了如下的代码,已经运行了一个晚上了,目前运行状态良好。

c1f55eb66223c6949fa495013c8490b