azure rtos cdc-ecm example

מנור מויאל 1 Reputation point
2022-11-23T12:02:07.347+00:00

hello microsoft :)

we have the stm32-f746 disco board and we trying to have an operating cdc_ecm host on the mcu side , using the azure rtos usbx,
we did not find any example for usb cdc_ecm host using the stm32 devices .

is there any cdc-ecm host example project on stm32 devices that you can send us ? (for the stm32 f746 it would be best),
or if there is not ,what kinds of support we can get in this case? .

(we tried stm32 community support with no help :( )

tnx, manor.

Azure RTOS
Azure RTOS
An Azure embedded development suite including a small but powerful operating system for resource-constrained devices.
324 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Chaoqiong Xiao 486 Reputation points Microsoft Employee
    2022-11-30T06:11:06.5+00:00

    Hi,

    You can try to modify some existing host example, to enable CDC-ECM support:

    1. Get a working host Example
    2. Confirm modules are ready
      • Check if NetX is included in project
      • Check if ux_host_class_cdc_ecm.* are included in project
      • Check if ux_host_class_asix.* are included in project (if support ASIX devices)
      • Check if ux_network_driver.* are included in project
    3. Modifications in application code

    Assumption for error handling function:

    static INT _halt_line = 0;  
    static inline void _error_halt(int line)  
    {  
        _halt_line = line;  
        while(_halt_line);  
    }  
    

    Assumption for definitions

    #define DEMO_STACK_SIZE             (2 * 1024)  
    
    /* Allocated from USBX memory space.  */  
    #define PAYLOAD_SIZE                UX_MAX(UX_HOST_CLASS_ASIX_NX_PAYLOAD_SIZE, UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE)  
    #define NX_PACKET_POOL_SIZE         ((PAYLOAD_SIZE + sizeof(NX_PACKET)) * 25) /* iPerf not working if it's too small?  */  
    #define HTTP_STACK_SIZE             2048  
    #define IPERF_STACK_SIZE            2048  
    
    #define IP_THREAD_STACK_SIZE        2048  
    #define ARP_THREAD_STACK_SIZE       1024  
    
    #define DEMO_IP_ADDRESS             IP_ADDRESS(192,168,77,77)  
    #define DEMO_NETWORK_MASK           IP_ADDRESS(255,255,255,0)  
    

    To simplify, memories NetX used are allocated through USBX memory allocation, but they can also be prepared other way.
    If DMA is used by USB controller driver, make sure:

    • Controller driver handles caching syncing or
    • The pool memory is in cache safe area.
      In the demo it assumes the memory referenced is always cache safe.

    3-1 Add NetX related things

    Functions prototypes

    void  demo_nx_thread_entry(ULONG arg);  
    
    extern  VOID nx_iperf_entry(NX_PACKET_POOL *pool_ptr, NX_IP *ip_ptr, UCHAR* http_stack, ULONG http_stack_size, UCHAR *iperf_stack, ULONG iperf_stack_size);  
    

    Global variables

    TX_THREAD                           demo_nx_thread;  
    
    NX_PACKET_POOL                      nx_pool;  
    
    NX_IP                               *nx_ip;  
    
    UCHAR                               *nx_pool_memory;  
    
    UCHAR                               *nx_ip_stack;  
    UCHAR                               *nx_arp_stack;  
    
    UCHAR                               *http_stack;  
    UCHAR                               *iperf_stack;  
    

    Start a new thread for NetX, after calling ux_system_initialize

    UCHAR *demo_nx_thread_stack = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, DEMO_STACK_SIZE);  
    status = tx_thread_create(&demo_nx_thread, "nx demo", demo_nx_thread_entry, 0,  
                     demo_nx_thread_stack, DEMO_STACK_SIZE,  
                     30, 30, 1, TX_AUTO_START);  
    if (status)  
        _error_halt(__LINE__);  
    

    NetX demo thread entry is implement as following:

    void  demo_nx_thread_entry(ULONG arg)  
    {  
    
    UINT                status;  
    
        /* Create a packet pool.  */  
        nx_pool_memory = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, NX_PACKET_POOL_SIZE);  
        if (nx_pool_memory == UX_NULL)  
            _error_halt(__LINE__);  
        status = nx_packet_pool_create(&nx_pool, "NetX Main Packet Pool",  
                                       (PAYLOAD_SIZE + sizeof(NX_PACKET)),  
                                       nx_pool_memory, NX_PACKET_POOL_SIZE);  
    
        /* Create IP instance.  */  
        nx_ip = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(NX_IP));  
        if (nx_ip == UX_NULL)  
            _error_halt(__LINE__);  
        nx_ip_stack = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, IP_THREAD_STACK_SIZE);  
        if (nx_ip_stack == UX_NULL)  
            _error_halt(__LINE__);  
        status = nx_ip_create(nx_ip, "NetX IP Instance 0",  
                              DEMO_IP_ADDRESS, DEMO_NETWORK_MASK,  
                              &nx_pool, _ux_network_driver_entry,  
                              nx_ip_stack, IP_THREAD_STACK_SIZE, 1);  
    
        /* Enable packet fragmentation.  */  
        status = nx_ip_fragment_enable(nx_ip);  
        if (status)  
            _error_halt(__LINE__);  
    
        /* Enable UDP traffic.  */  
        status =  nx_udp_enable(nx_ip);  
        if (status)  
            _error_halt(__LINE__);  
    
        /* Enable ICMP.  */  
        status =  nx_icmp_enable(nx_ip);  
        if (status)  
            _error_halt(__LINE__);  
    
        /* Enable TCP traffic.  */  
        status =  nx_tcp_enable(nx_ip);  
        if (status)  
            _error_halt(__LINE__);  
    
        /* Enable ARP and supply ARP cache memory for IP Instance 0.  */  
        nx_arp_stack = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, ARP_THREAD_STACK_SIZE);  
        if (nx_arp_stack == UX_NULL)  
            _error_halt(__LINE__);  
        status =  nx_arp_enable(nx_ip, (void *) nx_arp_stack, ARP_THREAD_STACK_SIZE);  
    
        /* Set the HTTP stack and IPerf stack.  */  
        http_stack = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, HTTP_STACK_SIZE);  
        if (http_stack == UX_NULL)  
            _error_halt(__LINE__);  
        iperf_stack = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, IPERF_STACK_SIZE);  
        if (iperf_stack == UX_NULL)  
            _error_halt(__LINE__);  
    
        /* Call entry function to start iperf test.  */  
        nx_iperf_entry(&nx_pool, nx_ip, http_stack, HTTP_STACK_SIZE, iperf_stack, IPERF_STACK_SIZE);  
    }  
    

    3-2 Modify USBX related things

    Add include file

    #include "ux_host_class_cdc_ecm.h"  
    #include "ux_host_class_asix.h"  
    

    Add global variables

    UX_DEVICE                           *device = UX_NULL;  /* Last operated device.  */  
    UX_HOST_CLASS_ASIX                  *asix = UX_NULL;  
    UX_HOST_CLASS_CDC_ECM               *cdc_ecm = UX_NULL;  
    
    ULONG                               other_event = 0xFFFFFFFF;  
    UX_HOST_CLASS                       *other_class = UX_NULL;  
    VOID                                *other_inst = UX_NULL;  
    

    Find ux_host_stack_initialize, if host change callback is not registered, register a change callback for CDC_ECM interface finding

        /* The code below is required for installing the host portion of USBX.  */  
        status =  ux_host_stack_initialize(demo_system_host_change_function);  
        if (status != UX_SUCCESS)  
            return;  
    

    Change functions prototype:

    UINT  demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst);  
    

    Change functions implement:

    static UINT demo_device_conn_disc(ULONG event, UX_HOST_CLASS *unused, UX_DEVICE *inst)  
    {  
    ULONG                   cfg_index;  
    ULONG                   ifc_index;  
    UX_CONFIGURATION        *cfg;  
    UX_INTERFACE            *ifc;  
    UINT                    status;  
    
    
        /* Log last operated device.  */  
        device = inst;  
    
        /* Removal, there is nothing to do.  */  
        if (event == UX_DEVICE_DISCONNECTION)  
            return(UX_SUCCESS);  
    
        /* Insertion, if it's not configured, check configuration settings.  */  
        if (inst -> ux_device_state == UX_DEVICE_CONFIGURED)  
            return(UX_SUCCESS);  
    
        /* Check if there are multiple configurations.  */  
        if (inst -> ux_device_descriptor.bNumConfigurations <= 1)  
            return(UX_SUCCESS);  
    
        /* Find CDC-ECM.  */  
        for (cfg_index = 0; cfg_index < inst -> ux_device_descriptor.bNumConfigurations; cfg_index ++)  
        {  
            status = ux_host_stack_device_configuration_get(inst, cfg_index, &cfg);  
            if (status != UX_SUCCESS)  
                break;  
    
            /* Check interfaces.  */  
            for (ifc_index = 0; ifc_index < cfg -> ux_configuration_descriptor.bNumInterfaces; ifc_index ++)  
            {  
                status = ux_host_stack_configuration_interface_get(cfg, ifc_index, 0, &ifc);  
                if (status != UX_SUCCESS)  
                    break;  
    
                /* Check interface class/subclass/protocol.  */  
                if (ifc -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS &&  
                    ifc -> ux_interface_descriptor.bInterfaceSubClass == UX_HOST_CLASS_CDC_ECM_CONTROL_SUBCLASS)  
                {  
    
                    /* Activate the configuration.  */  
                    status = ux_host_stack_device_configuration_activate(cfg);  
                    if (status == UX_SUCCESS)  
                        return(UX_SUCCESS);  
    
                    /* Failed, break interface check and try next configuration.  */  
                    break;  
                }  
            }  
        }  
    
        /* Done.  */  
        return(UX_SUCCESS);  
    }  
    static UINT demo_function_ins_rm(ULONG event, UX_HOST_CLASS *cls, VOID *inst)  
    {  
        if (cls->ux_host_class_entry_function == _ux_host_class_asix_entry)  
        {  
            if (event == UX_DEVICE_INSERTION)  
                asix = (UX_HOST_CLASS_ASIX *)inst;  
            else  
                asix = UX_NULL;  
            return(UX_SUCCESS);  
        }  
        if (cls->ux_host_class_entry_function == _ux_host_class_cdc_ecm_entry)  
        {  
            if (event == UX_DEVICE_INSERTION)  
                cdc_ecm = (UX_HOST_CLASS_CDC_ECM *)inst;  
            else  
                cdc_ecm = UX_NULL;  
            return(UX_SUCCESS);  
        }  
        return(UX_ERROR);  
    }  
    UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst)  
    {  
        switch (event)  
        {  
        case UX_DEVICE_CONNECTION:  
        case UX_DEVICE_DISCONNECTION:  
            return(demo_device_conn_disc(event, UX_NULL, (UX_DEVICE *)inst));  
    
        case UX_DEVICE_INSERTION:  
        case UX_DEVICE_REMOVAL:  
            if (demo_function_ins_rm(event, cls, inst) == UX_SUCCESS)  
                return(UX_SUCCESS);  
    
        default:  
            break;  
        }  
        other_event = event;  
        other_class = cls;  
        other_inst = inst;  
        return(UX_SUCCESS);  
    }  
    

    Add class registration Find the code that register storage class via ux_host_stack_class_register and add following code to register CDC-ECM and/or ASIX class.

    /* Register CDC-ECM class.  */  
    status = ux_host_stack_class_register(_ux_system_host_class_cdc_ecm_name, ux_host_class_cdc_ecm_entry);  
    if (status != UX_SUCCESS)  
        return;  
    
    
    /* Register ASIX class.  */  
    status =  ux_host_stack_class_register(_ux_system_host_class_asix_name, ux_host_class_asix_entry);  
    if (status != UX_SUCCESS)  
        return;