MCUXpresso SDK Knowledge Base

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MCUXpresso SDK Knowledge Base

Labels

Discussions

Sort by:
NXP provides multicore sw components for heterogenous multicore MCU and MPU parts within the MCUXpressoSDK. It deals with Multicore Software Development Kit (MCSDK) that provides comprehensive software support for NXP dual/multicore devices. It consists of the following software components: Multicore Manager (MCMGR) This library provides a number of services for multicore systems. The main MCMGR features are: Maintains information about all cores in system. Secondary/auxiliary cores startup and shutdown. Remote core monitoring and event handling. The MCMGR library is available for several MCU parts and can be obtained from an MCUXpressoSDK packages. Visit https://mcuxpresso.nxp.com to configure, build and download these packages. To get the board list with multicore support (MCMGR included) use filtering based on Middleware and search for 'multicore' string. Once the selected package with the multicore middleware is downloaded, see the <MCUXpressoSDK_install_dir>/middleware/multicore/mcmgr folder. For detailed information about the MCMGR library, see the documentation available in the <MCUXpressoSDK_install_dir>/middleware/multicore/mcmgr/doc folder. Another possibility how to get the MCMGR library is the mcux-sdk-middleware-multicore GitHub repo. Remote Processor Messaging - Lite (RPMsg-Lite) RPMsg-Lite is a lightweight implementation of the RPMsg protocol. The RPMsg protocol defines a standardized binary interface used to communicate between multiple cores in a heterogeneous multicore system. Compared to the legacy OpenAMP implementation, RPMsg-Lite offers a code size reduction, API simplification, and improved modularity. The main RPMsg protocol features are: Shared memory interprocessor communication. Virtio-based messaging bus. Application-defined messages sent between endpoints. Portable to different environments/platforms. Available in upstream Linux OS. The RPMsg-Lite library is available for several MCU and MPU parts and can be obtained from an MCUXpressoSDK packages. Visit https://mcuxpresso.nxp.com to configure, build and download these packages. To get the board list with multicore support (RPMsg-Lite included) use filtering based on Middleware and search for 'multicore' string. Once the selected package with the multicore middleware is downloaded, see the <MCUXpressoSDK_install_dir>/middleware/multicore/rpmsg-lite folder. For detailed information about the RPMsg-Lite, see the RPMsg-Lite User’s Guide located in the <MCUXpressoSDK_install_dir>/middleware/multicore/rpmsg_lite/doc folder. Another possibility how to get the RPMsg-Lite library is the rpmsg-lite GitHub repo. Embedded Remote Procedure Call (eRPC) The Embedded Remote Procedure Call (eRPC) is the RPC system created by NXP. The RPC is a mechanism used to invoke a software routine on a remote system via a simple local function call. When a remote function is called by the client, the function's parameters and an identifier for the called routine are marshaled (or serialized) into a stream of bytes. This byte stream is transported to the server through a communications channel (IPC, TPC/IP, UART, and so on). The server unmarshaled the parameters, determines which function was invoked, and calls it. If the function returns a value, it is marshaled and sent back to the client. RPC implementations typically use a combination of a tool (erpcgen) and IDL (interface definition language) file to generate source code to handle the details of marshaling a function's parameters and building the data stream. Main eRPC features are: Scalable from BareMetal to Linux OS - configurable memory and threading policies. Focus on embedded systems - intrinsic support for C, modular, and lightweight implementation. Abstracted transport interface - RPMsg is the primary transport for multicore, UART, or SPI-based solutions can be used for multichip. The eRPC library is available for several MCU and MPU parts and can be obtained from an MCUXpressoSDK packages. Visit https://mcuxpresso.nxp.com to configure, build and download these packages. To get the board list with multicore support (eRPC included) use filtering based on Middleware and search for 'multicore' string. Once the selected package with the multicore middleware is downloaded, see in the <MCUXpressoSDK_install_dir>/middleware/multicore/erpc folder. For detailed information about the eRPC, see the documentation available in the <MCUXpressoSDK_install_dir>/middleware/multicore/erpc/doc folder. Another possibility how to get the eRPC library is the eRPC GitHub repo.   Where to find multicore examples Multicore and multiprocessor examples can be found within NXP MCUXpressoSDK packages. They are located in <MCUXpressoSDK_install_dir>/boards/<board_name>/multicore_examples  and <MCUXpressoSDK_install_dir>/boards/<board_name>/multiprocessor_examples subfolders. Another way of getting NXP MCUXpressoSDK multicore and multiprocessor examples is using the mcux-sdk Github repo. Follow the description how to use the West tool to clone and update the mcuxsdk repo in readme Overview section. Once done the armgcc examples can be found in mcuxsdk/examples/<board_name>/multicore_examples and mcuxsdk/examples/<board_name>/multiprocessor_examples subfolders.   Based on application needs, different multicore sw components can be utilized in a project. This depends on the complexity, required speed, memory resources or system design. The MCSDK brings users the possibility for quick and easy development of multicore and multiprocessor applications.
View full article
This tutorial is introducing the eRPC (embedded remote procedure call) open-source project.   The eRPC (Embedded Remote Procedure Call) is a Remote Procedure Call (RPC) system created by NXP. An RPC is a mechanism used to invoke a software routine on a remote system using a simple local function call. The remote system may be any CPU connected by an arbitrary communications channel: a server across a network, another CPU core in a multicore system, and so on. To the client, it is just like calling a function in a library built into the application. The only difference is any latency or unreliability introduced by the communications channel.   Important links:  Everything related to the eRPC development is placed GitHub - eRPC base. The eRPC development is placed GitHub - eRPC development.  The eRPC releases are placed GitHub - eRPC Releases. The eRPC documentation is placed Github - eRPC wiki  The eRPC as Python Package on pypi    The eRPC is supporting multicore and multiprocessor types of applications.    Where to find eRPC examples   Plenty of eRPC multicore and multiprocessor examples can be found in NXP MCUXpressoSDK packages. Visit https://mcuxpresso.nxp.com to configure, build and download these packages. To get the board list with multicore support (eRPC included) use filtering based on Middleware and search for 'multicore' string. Once the selected package with the multicore middleware is downloaded, see <MCUXpressoSDK_install_dir>/boards/<board_name>/multicore_examples for eRPC multicore examples (RPMsg_Lite or Messaging Unit transports used) or <MCUXpressoSDK_install_dir>/boards/<board_name>/multiprocessor_examples for eRPC multiprocessor examples (UART or SPI transports used). eRPC examples use the 'erpc_' name prefix. Another way of getting NXP MCUXpressoSDK eRPC multicore and multiprocessor examples is using the mcux-sdk Github repo. Follow the description how to use the West tool to clone and update the mcuxsdk repo in readme Overview section. Once done the armgcc eRPC examples can be found in mcuxsdk/examples/<board_name>/multicore_examples or in mcuxsdk/examples/<board_name>/multiprocessor_examples folders. You can use the evkmimxrt1170 as the board_name for instance. Similar to MCUXpressoSDK packages the eRPC examples use the 'erpc_' name prefix.  
View full article
A collection of Questions and Answers from a recent webinar held with AWS / FreeRTOS and SEGGER tools. 
View full article
1  TraceX Introduction Azure RTOS TraceX is Microsoft’s host-based analysis tool that provides developers with a graphical view of real-time system events and enables them to visualize and better understand the behavior of their real-time systems. With Azure RTOS TraceX, developers can se clearly the occurrence of system events like interrupts and context switches that occur out of view of standard debugging tools.   This article explains how to start the traceX debug with MCUXpresso SDK Hardware: MIMXRT1060-EVK & 1 Micro-USB cable Software: SDK_2_10_1_EVK-MIMXRT1060   2 Installing TraceX   You can obtain the TraceX app from the Microsoft App Store by searching for TraceX, or by going directly to the TraceX page. Then install the TraceX according to the pop up manuals.   3 Enabling Trace Inside the application 3.1 Add required preprocessor symbols Trace-dependent code is activated using TX_ENABLE_EVENT_TRACE define. It must be added in the preprocessor section of the compiler. This must be done for the application itself and for the linked libraries. (e.g. ThreadX library)         3.2 Declare the trace buffer A buffer area for storing the trace events occurring at run-time must be specified and then further instruct the ThreadX trace sub-system to use it. Buffer can be a global variable, just like in the example below:  /*Trace buffer*/ #ifdef TX_ENABLE_EVENT_TRACE UCHAR trace_buffer[64000]; #endif     3.3 Enable trace Trace must be explicitly enabled inside the application by calling tx_trace_enable(). This can be achieved by adding the below code.  #ifdef TX_ENABLE_EVENT_TRACE /* * Enable event tracing using the global “trace buffer”. * Allow a maximum of 30 ThreadX objects in the registery. */   UINT status =  tx_trace_enable(&trace_buffer, sizeof(trace_buffer), 30); if (status != TX_SUCCESS) {     for (; ; ) { } } #endif   It is recommended to enable trace inside tx_application_define( ).   3.4 compile Compile the ThreadX lib (the compiled library will be in the Debug folder). After successful build and compilation, a new library appears in the Debug / Release directory. It has a name like libevkimixrt1060_threadx_lib.a. Please rename it to libthreadx.a and copy it to the directory, azure-rtos/binary/treadx/mcux/, in the evkmimxrt1060_threadx_demo project to replace the original one.   Replace the libthreadx.a files in the threadx_demo project         4 Exporting Trace 4.1 Configuration of Trace Export feature   Trace Export feature is controlled by a list of preferences that can be accessed and further modified via window->Preference page.   4.2 Trace Export button Pause your application and the Trace Export button is located in the Debug view’s toolbar, as illustrated in the screenshot below.     4.3 Exporting Trace Once the Trace Expert button is clicked, a modal dialog window will be presented.  A file path must be specified and then click the Export button. The exported file can be imported in Azure RTOS TraceX tool afterwards.       5 Display with Azure RTOS TraceX tool From Azure RTOS TraceX, we can open the imported file. System summary line contains a summary of the context as well as the corresponding event summary underneath.     Azure RTOS TraceX provides a built-in execution profile for all executed contexs       Azure RTOS TraceX provides a build in performance statistics report for the currently loaded trace file       Reference doc: https://docs.microsoft.com/en-us/azure/rtos/      
View full article
1 Introduction Azure RTOS is an embedded development suite including a small but powerful operating system that provides reliable, ultra-fast performance for resource-constrained devices. Azure RTOS include 5 components. In project, it is compiled as 5 libs Azure RTOS ThreadX: It is the kernel of Azure RTOS, it provides advanced scheduling. Azure RTOS FileX(LevelX): An embedded FAT file system that offers optional fault tolerant features. Azure RTOS NetX Duo: An IPv4/IPv6 network stack. Azure RTOS GUIX: a complete design environment and run-time to create and maintain 2D graphical user interfaces Azure RTOS USBX: A USB stack that provides host, device and OTG support.   2  Basic Threadx Structure Below picture shows the initialization process of Azure RTOS.   2.1 main function In main function, we can set up the processor, initialize the board. For most applications, the main function simply calls tx_kernel_enter, which is the entry into threadx. 2.2 tx_kernel_enter This function is the first ThreadX function called during initialization. It is important to note that this routine never returns. The processing of this function is relatively simple. It calls several ThreadX initialization functions, calls the application define function, and then invokes the scheduler. 2.3 Application Definition Function The tx_application_define function defines all of the initial application threads, queues, semaphores, mutexes, event flags, memory pools, and timers. It is also possible to create and delete system resources from threads during the normal operation of the application. However, all initial application resources are defined here. When tx_application_define returns, control is transferred to the thread scheduling loop. This marks the end of initialization. 2.4 your thread entry Every thread is just an infinite loop, that is what your code mainly about. 2.5 important files tx_api.h : C header file containing all system equates, data structures, and service prototypes. All application files that use ThreadX api should include this header file. tx_port.h : C header files containing all development-tool and target specific data definitions and structures. 3 Build a ThreadX application There are four steps required to build a ThreadX application. Include the tx_api.h file in all application files that use ThreadX services or data structures. Create the standard C main function. This function must eventually call tx_kernel_enter to start ThreadX. Application-specific initialization that does not involve ThreadX may be added prior to entering the kernel. Create the tx_application_define function. This is where the initial system resources are created. Examples of system resources include threads, queues, memory pools, event flags groups, mutexes, and semaphores. Compile application source and link with the ThreadX run-time library tx.lib. The resulting image can be downloaded to the target and executed! 4  Simple demo #include "tx_api.h" unsigned long my_thread_counter = 0; TX_THREAD my_thread; main( ) {     /* Enter the ThreadX kernel. */     tx_kernel_enter( ); } void tx_application_define(void *first_unused_memory) {     /* Create my_thread! */     tx_thread_create(&my_thread, "My Thread",     my_thread_entry, 0x1234, first_unused_memory, 1024,     3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); } void my_thread_entry(ULONG thread_input) {     /* Enter into a forever loop. */     while(1)     {         /* Increment thread counter. */         my_thread_counter++;         /* Sleep for 1 tick. */         tx_thread_sleep(1);     } }   5  Debug with TAD The Thread Aware Debugging (TAD) tool is a useful and powerful instrument to debug the Azure RTOS application. With MCUXpresso IDE 11.4.1, we can show the Azure RTOS ThreasX TAD views. We take the evkmimxrt1060_threadx_demo as example.     Theads view shows the threads in a table, we can see the priority, state, stack usage for each thread.   Message Queues view shows the message queues in a table   Semaphores view shows the semaphores in a table Suspended means the threads that are suspended and waiting for access to current resource.   Mutexes View shows the information about mutexes used inside the application   Event flags view shows the event flags in a table. Suspended : threads that are suspended and waiting for access to current resource.     Reference doc: https://docs.microsoft.com/en-us/azure/rtos/    
View full article
  Introduction TCP Client & Server establishes a two-way connection between a server and a client. It is the most common communication model used by applications such as HTTP, Telnet, FTP, SSH and others LwIP is a free light-weight TCP/IP stack in MCUXpresso SDK. It has three application programming interfaces (API): RAW API:  it is the native API of LwIP. It enables the development of applications using event callbacks. Netconn API:  it is a high level sequential API that requires the services of a real-time system (RTOS), The Netconn API enables multi-threaded operations BSD Socket API: it is developed on top of the Netconn API. In this article, I will introduce how to implement a TCP client & Server demo with LwIP Netconn API.  One EVK-RT1060 acts as TCP server, and others boards act as TCP clients.  They are connected through an Ethernet router.  They communicate via TCP protocol. If you press SW8 on the client board, it will toggle a LED on the Server board.     This article is for beginners to understand the Netconn API on NXP MCUXpresso SDK.   2. Hardware configuration PHY settings: In this demo, we use phyksz8081, that is the default PHY in EVK-RT1060 board.  ENET port 0. /*! @brief The ENET PHY address. */ #define BOARD_ENET0_PHY_ADDRESS (0x02U) /* Phy address of enet port 0. */   /* Address of PHY interface. */ #define EXAMPLE_PHY_ADDRESS BOARD_ENET0_PHY_ADDRESS   /* MDIO operations. */ #define EXAMPLE_MDIO_OPS enet_ops   /* PHY operations. */ #define EXAMPLE_PHY_OPS phyksz8081_ops   /* ENET clock frequency. */ #define EXAMPLE_CLOCK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk)   Configure the external PHY, pull up the ENET_INT before RESET.       GPIO_PinInit(GPIO1, 9, &gpio_config);     GPIO_PinInit(GPIO1, 10, &gpio_config);     /* pull up the ENET_INT before RESET. */     GPIO_WritePinOutput(GPIO1, 10, 1);     GPIO_WritePinOutput(GPIO1, 9, 0);     delay();     GPIO_WritePinOutput(GPIO1, 9, 1);   MAC settings: In this demo, MAC address is defined in Macro configMAC_ADDR   /* MAC address configuration. */ #define configMAC_ADDR                     \     {                                      \         0x02, 0x12, 0x13, 0x10, 0x15, 0x11 \     }  3. Starting a network interface To create a new network interface, the user allocates space for a new struct netif (but does not initialize any part of it) and calls netifapi_netif_add:     IP4_ADDR(&fsl_netif0_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3);     IP4_ADDR(&fsl_netif0_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3); IP4_ADDR(&fsl_netif0_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2, configGW_ADDR3);       netifapi_netif_add(&fsl_netif0, &fsl_netif0_ipaddr, &fsl_netif0_netmask, &fsl_netif0_gw, &fsl_enet_config0,                        ethernetif0_init, tcpip_input); Pass tcpip_input API to netif_add API as input callback function that is called to pass ingress packets up in the protocol layer stack next we need to bring the interface up An interface that is “up” is available to your application for input and output, and “down” is the opposite state. Therefore, before you can use the interface, you must bring it up. This can be accomplished depending on how the interface gets its IP address.  We can use static IP address  or DHCP. Set the network interface as the default network interface netifapi_netif_set_default(&fsl_netif0);   Bring the interface up, available for processing     netifapi_netif_set_up(&fsl_netif0);   4. LwIP Initialization Call tcpip_init to create a tcpip_thread, this thread has exclusive access to LwIP core functions. Other threads communicate with this thread using message boxes. It also starts all the timers to make sure they are running in the right thread context. tcpip_init(NULL, NULL);   5. TCP Client & Server Implementation For TCP communications, one host listens for incoming connection requests. When a request arrives, the server accepts it and data is transferred between the server and the client. The sequence of function calls for the client and a server participating in a TCP connection is show in below picture. The steps for establishing a TCP connection on the client side are the following: Create a netconn using the netconn_new() function. Connect the connection to the address of the server using the netconn_connect() function. Send and receive data by means of the netconn_recv() and netconn_send() functions. Close the connection by means of the netconn_close() function.   The steps in establishing a TCP connection on the server side are as follows Create a connection with netconn_new() function; Bind the connection to an address using the netconn_bind() function. Listen for connections with the netconn_listen() function. Accept a connection with the netconn_accept() function, this blocks until a client connects. Send and receive data by means of netconn_send() and netconn_recv(). Close the connection by means of the netconn_close() function.   5.1 TCP SERVER IMPLEMENTATION   netconn_new() is used to create a new connection.     conn = netconn_new(NETCONN_TCP); netconn_bind() binds a connection to a local IP address and port.   netconn_bind(conn, IP_ADDR_ANY, TCP_CUSTOM_PORT); netconn_listen() function sets a TCP connection into a listening TCP connection.   /* Tell connection to go into listening mode. */   netconn_listen(conn);   netconn_accept() function accepts an incoming connection on a listening TCP connection.    err = netconn_accept(conn, &newconn); netconn_recv() function receives a message from a netconn. netconn_send() function sends data to the currently connected remote IP/Port.   In this demo, if server board receives a ‘TOGGLE’ message from the client board, it will toggle a LED. (GPIO1/3,  need to connect a LED manually)           while ((err = netconn_recv(newconn, &buf)) == ERR_OK) {         PRINTF("Received  %s\n", buf->p->payload);         do {              netbuf_data(buf, &data, &len);              tcp_rx_buf = (void *)data;                if (tcp_rx_buf[0] == 'T')              {                  PRINTF("LED was toggled from client\r\n");                 GPIO_PortToggle(EXAMPLE_LED_GPIO, 1u << EXAMPLE_LED_GPIO_PIN);                 netconn_write(newconn, TcpReply, sizeof(TcpReply) , NETCONN_COPY );              }         } while (netbuf_next(buf) >= 0);         netbuf_delete(buf);       } //end of while(( err     5.2 TCP CLIENT IMPLEMENTATION For the client side, the netconn structure is created:   conn = netconn_new(NETCONN_TCP); netconn_connect():  when a user issues a connect command, the stack creates a connection with another host. Before connect can instruct the stack to establish a connection, the user must pass a netconn and a sockaddr_in structure containing the destination IP address and port. In TCP, the handshaking packets will be exchanged.     memset(&server_addr, 0, sizeof(server_addr));   server_addr.sin_family = AF_INET;   server_addr.sin_port = PP_HTONS(TCP_CUSTOM_PORT);   server_addr.sin_addr.s_addr = server_ip_addr.addr;     err = connect(client_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));   LWIP_ASSERT("connect fail, please start TCP server first !  ",  err == 0);   In this demo, a GPIO is initialized and interrupt is enabled. When SW8 is pressed, the client board will send ‘Toggle’ command to the TCP server.   while (1)   {       if (g_InputSignal)       {           delay();           if (1 == GPIO_PinRead(EXAMPLE_SW_GPIO, EXAMPLE_SW_GPIO_PIN))           {               PRINTF("%s is turned on.\r\n", EXAMPLE_SW_NAME);               err = send(server_sock, Sendtext, sizeof(Sendtext) / sizeof(Sendtext[0]), 0);             }           /* Reset state of switch. */           g_InputSignal = false;       }  //end of if (g_InputSignal)   }                      
View full article
Introduction TCP Client&Server establishes a two-way connection between a server and a client. It is the most common communication model used by applications such as HTTP, Telnet, FTP, SSH and others LwIP is a free light-weight TCP/IP stack in MCUXpresso SDK. It has three application programming interfaces (API): RAW API:  it is the native API of LwIP. It enables the development of applications using event callbacks. Netconn API:  it is a high level sequential API that requires the services of a real-time system (RTOS), The Netconn API enables multi-threaded operations. BSD Socket API: it is developed on top of the Netconn API.   In this article, I will introduce how to implement a TCP client & Server demo with LwIP socket API.  One EVK-RT1060 acts as TCP server, and others boards act as TCP clients.  They are connected through an Ethernet router.  They communicate via TCP protocol. If you press SW8 on the client board, it will toggle a LED on the Server board.   This article is for beginners to understand the Socket API on NXP MCUXpresso SDK.    2. Hardware configuration PHY settings: In this demo, we use phyksz8081, that is the default PHY in EVK-RT1060 board.  ENET port 0. /*! @brief The ENET PHY address. */ #define BOARD_ENET0_PHY_ADDRESS (0x02U) /* Phy address of enet port 0. */   /* Address of PHY interface. */ #define EXAMPLE_PHY_ADDRESS BOARD_ENET0_PHY_ADDRESS   /* MDIO operations. */ #define EXAMPLE_MDIO_OPS enet_ops   /* PHY operations. */ #define EXAMPLE_PHY_OPS phyksz8081_ops   /* ENET clock frequency. */ #define EXAMPLE_CLOCK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk)   Configure the external PHY, pull up the ENET_INT before RESET.       GPIO_PinInit(GPIO1, 9, &gpio_config);     GPIO_PinInit(GPIO1, 10, &gpio_config);     /* pull up the ENET_INT before RESET. */     GPIO_WritePinOutput(GPIO1, 10, 1);     GPIO_WritePinOutput(GPIO1, 9, 0);     delay();     GPIO_WritePinOutput(GPIO1, 9, 1);     MAC settings: In this demo, MAC address is defined in Macro configMAC_ADDR   /* MAC address configuration. */ #define configMAC_ADDR                     \     {                                      \         0x02, 0x12, 0x13, 0x10, 0x15, 0x11 \     }    3. Starting a network interface  To create a new network interface, the user allocates space for a new struct netif (but does not initialize any part of it) and calls netifapi_netif_add:       IP4_ADDR(&fsl_netif0_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3);     IP4_ADDR(&fsl_netif0_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3); IP4_ADDR(&fsl_netif0_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2, configGW_ADDR3);       netifapi_netif_add(&fsl_netif0, &fsl_netif0_ipaddr, &fsl_netif0_netmask, &fsl_netif0_gw, &fsl_enet_config0,                        ethernetif0_init, tcpip_input);   Pass tcpip_input API to netif_add API as input callback function that is called to pass ingress packets up in the protocol layer stack next we need to bring the interface up An interface that is “up” is available to your application for input and output, and “down” is the opposite state. Therefore, before you can use the interface, you must bring it up. This can be accomplished depending on how the interface gets its IP address.  We can use static IP address  or DHCP. Set the network interface as the default network interface netifapi_netif_set_default(&fsl_netif0);   Bring the interface up, available for processing     netifapi_netif_set_up(&fsl_netif0);    4. LwIP Initialization   Call tcpip_init to create a tcpip_thread, this thread has exclusive access to LwIP core functions. Other threads communicate with this thread using message boxes. It also starts all the timers to make sure they are running in the right thread context.   tcpip_init(NULL, NULL);    5. TCP Client & Server Implementation   For TCP communications, one host listens for incoming connection requests. When a request arrives, the server accepts it and data is transferred between the server and the client. The sequence of function calls for the client and a server participating in a TCP connection is show in below picture.   The steps for establishing a TCP socket on the client side are the following: Create a socket using the socket() function. Connect the socket to the address of the server using the connect() function. Send and receive data by means fo the recv() and send() functions. Close the connection by means of the close() function.   The steps in establishing a TCP socket on the server side are as follows Create a socket with socket() function; Bind the socket to an address using the bind() function. Listen for connections with the listen() function. Accept a connection with the accept() function, this blocks until a client connects. Send and receive data by means of send() and receive(). Close the connection by means of the close() function.    4.1 TCP SERVER IMPLEMENTATION   Socket is a standard set of function calls used at application level. When user calls the function socket(), it creates a socket and returns references a number for the socket. In this demo, a socket structure was created and filled in this way:     /* Create a new socket. */     server_sock = socket(AF_INET, SOCK_STREAM, 0);   LWIP_ASSERT("server_sock >= 0 ", server_sock >= 0);     server_addr.sin_family = AF_INET;   server_addr.sin_port = PP_HTONS(TCP_CUSTOM_PORT);   server_addr.sin_addr.s_addr = INADDR_ANY;     Bind function allows user to associate a socket with a particular local port and IP address.     err = bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)); Listen() function prepares the given socket to accept incoming TCP requests.     /* Tell connection to go into listening mode. */   err = listen(server_sock, 0);  Accept() function detects incoming connection requests on the listening socket. This call will cause a task to wait until a connection request is received.       /* Grab new connection. */     client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_len);   The recv() function receives a message from a socket. The send() function initiates transmission of a message from the specified socket to its peer. In this demo, if server board receives a ‘TOGGLE’ message from the client board, it will toggle a LED. (GPIO1/3,  need to connect a LED manually)       while ( recv(client_sock, rxbuf, rx_len, 0 ) > 0 )     {          uint8_t *tcp_rx_buf;          delay();           tcp_rx_buf = (void *)rxbuf;         tcp_rx_buf[rx_len]= '\0';         PRINTF("Received :  %s \r\n", rxbuf);           if ( (tcp_rx_buf[0] == 'T') || (tcp_rx_buf[0] == 't')    )         {            PRINTF("LED was toggled from client\r\n");            GPIO_PortToggle(EXAMPLE_LED_GPIO, 1u << EXAMPLE_LED_GPIO_PIN);              /*send a message to client*/            send(client_sock, SendReply, sizeof(SendReply), 0);         }       }   4.2 TCP CLIENT IMPLEMENTATION For the client side, the socket structure is created:   client_sock = socket(AF_INET, SOCK_STREAM, 0);   connect():  when a user issues a connect command, the stack creates a connection with another host. Before connect can instruct the stack to establish a connection, the user must pass a socket and a sockaddr_in structure containing the destination IP address and port. In TCP, the handshaking packets will be exchanged.     memset(&server_addr, 0, sizeof(server_addr));   server_addr.sin_family = AF_INET;   server_addr.sin_port = PP_HTONS(TCP_CUSTOM_PORT);   server_addr.sin_addr.s_addr = server_ip_addr.addr;     err = connect(client_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));   LWIP_ASSERT("connect fail, please start TCP server first !  ",  err == 0);   In this demo, a GPIO is initialized and interrupt is enabled. When SW8 is pressed, the client board will send ‘Toggle’ command to the TCP server.     while (1)   {         if (g_InputSignal)       {           delay();           if (1 == GPIO_PinRead(EXAMPLE_SW_GPIO, EXAMPLE_SW_GPIO_PIN))           {               PRINTF("%s is turned on.\r\n", EXAMPLE_SW_NAME);               err = send(server_sock, Sendtext, sizeof(Sendtext) / sizeof(Sendtext[0]), 0);             }           /* Reset state of switch. */           g_InputSignal = false;       }  //end of if (g_InputSignal)     }                            
View full article
Introduction   Azure RTOS is a comprehensive suite of multithreading facilities, middleware and Windows tools for developing embedded IoT applications. It features Azure RTOS ThreadX, a small, fast, reliable real-time operating system that is already powering more than 6.2 billion devices worldwide. Most of the volume are components in smart phones, cellular modems, WiFi, Bluetooth, GPS, etc. Now Azure RTOS is integrated into MCUXpresso SDK2.8.5 and is available from our SDK builder site (https://mcuxpresso.nxp.com) and also directly from MCUXpresso IDE. Support is currently available for i.MX RT1050, i.MX RT1060 and i.MX RT1064 MCUs. Please select Azure RTOS before you download it.     Code Structure   Below picture is the code structure of evkmimxrt1064_threadx_demo. Azure RTOS kernel is provided as a library, libthreadx.a.  You can import the evkmimxrt1064_threadx_lib to generate this library.      Tx_initialize_low_level.S : an assembly file that contains the low level initialization for ThreadX. The primary function of this file is to set up the System Tick handler, which controls the internal timing of ThreadX.   Tx_user.h   configuration options. Options defined in tx_user.h are applied only if the application and ThreadX library are built with TX_INCLUDE_USER_DEFINE_FILE defined. Thread_demo.c The Thread_demo.c file contains the application entry point main(). This function is responsible for the following: Entering the ThreadX kernel Initializing the board Start the main application thread   Create a ThreadX application   There are four steps required to build a ThreadX application Include the tx_api.h file in all application files that uses ThreadX services or data structures. Create the standard C main function. This function must eventually call  tx_kernel_enter to start ThreadX. Tx_kernel_enter: The entry function coordinates initialization of various ThreadX data structures and then call the application’s definition function tx_application_define. Create the tx_application_define function. It executes after the basic ThreadX initialization is complete. It is responsible for setting up all of the initial system resources, including threads, queues, semaphores, mutexes, event flags, and memory pools. After tx_application_define completes, control is transferred to the thread scheduler and from there to each individual thread.   The small Example system is as below picture shows.   #include "tx_api.h" unsigned long my_thread_counter = 0; TX_THREAD my_thread; main( ) { /* Enter the ThreadX kernel. */ tx_kernel_enter( ); } void tx_application_define(void *first_unused_memory) { /* Create my_thread! */ tx_thread_create(&my_thread, "My Thread", my_thread_entry, 0x1234, first_unused_memory, 1024, 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); } void my_thread_entry(ULONG thread_input) { /* Enter into a forever loop. */ while(1) { /* Increment thread counter. */ my_thread_counter++; /* Sleep for 1 tick. */ tx_thread_sleep(1); } }   4  Compile evkmimxrt1064_threadx_demo and debug   Console output:   THREADX example ... start thread 0 ... start thread 5 ... start thread 3 ... start thread 4 ... start thread 6 ... start thread 7 ... start thread 1 ... start thread 2 ...    
View full article
  FreeRTOS supports multiple heap allocation schemes. Scheme 5 allows the heap to span multiple non adjacent (non-contiguous) memory regions. Heap_5 is useful when RAM provided by the system on which FreeRTOS is running does not appear as a single contiguous block in the system’s memory map. With heap_5, developers can combine multiple memory blocks for a virtual combined memory heap. In this article, I will take FrdmK82f hello_world_freertos as an example to illustrate how to use FreeRTOS heap 5 memory scheme with MCUXpresso SDK. Like some other Kinetis MCUs, Frdmk82f has two memory controllers, one for the SRAM_UPPER (192k byters) and one or SRAM_Lower as below (64K byters).  With FreeRTOS heap_4, application developers cannot have memory objects crossing that memory boundary 0x2000,000, they can only use SRAM_UPPER or SRAM_LOWER as FreeRTOS heap, with heap_5, they can combine SRAM_UPPER and SRAM_LOWER as a huge virtual FreeRTOS memory map. 1    Define multiple memory blocks Each separate memory areas is described by a structure of type HeapRegion_t. A description of all the available memory areas is passed into vPortDefineHeapRegions( ) as an array of HeapRegion_t structures. /* Used by heap_5.c to define the start address and size of each memory region that together comprise the total FreeRTOS heap space. */ typedef struct HeapRegion {     uint8_t *pucStartAddress;     size_t xSizeInBytes; } HeapRegion_t;   We can create an array of these structures to define our different memory blocks that can be assigned to the heap. For FrdmK82f, we can define two memory blocks, SRAM_UPPER and SRAM_LOWER. But SRAM_UPPER is the main RAM, it is not possible to allocate all the RAM to heap, leaving no RAM free for use by other variables. It is good to declare an array called ucHeap, it becomes part of the data allocated to RAM by linker. /*define the start address and size of SRAM_LOWER region not used by the the linker*/ #define SRAM_LOWER_START_ADDRESS  ( (uint8_t*) 0x1fff0000 ) #define SRAM_LOWER_SIZE           ( 0X10000)   /*Declare an array that will be part of the heap used by heap_5.  The array will be placed in SRAM_UPPER by the linker*/ #define SRAM_UPPOER_HEAP_SIZE (80 * 1024) static __attribute__ ((used,section(".noinit_RAM2"))) uint8_t ucHeap[SRAM_UPPOER_HEAP_SIZE]; /* placed in in no_init section inside SRAM_UPPER */   /*Create an array of HeapRegion_t definitions. this array will be passed to vPortDefineHeapRegions( ) */   const HeapRegion_t xHeapRegions[] = {         {SRAM_LOWER_START_ADDRESS, SRAM_LOWER_SIZE },         {ucHeap, SRAM_UPPOER_HEAP_SIZE },         {NULL, 0} };   Please note that the array should be terminated with a NULL zero sized region definition and the memory regions defined in the array must appear in address order from low address to high address.   2     FreeRTOS heap_5 Initialization   Heap_5 memory allocation scheme must be explicitly initialized before pvPortMalloc( ) can be used.  Heap_5 is initialized using the vPortDefineheapRegions( ) API function. It is used to specify the start address and size of each separate memory area that together makes up the total memory used by heap_5. When heap_5 is used, vPortDefineHeapRegions( ) must be called before any kernel objects (tasks, queues, semaphores, etc) can be created.  Usually this API is called in main function.       vPortDefineHeapRegions(xHeapRegions);   /*pass the array into vPortDefineHeapRegions(), must be called first*/   3    Configure FreeRTOS memory scheme To use Scheme, make sure heap_5.c is used in the application as below picture shows. ConfigFRTOS_MEMORY_SCHEME should be configured to ‘5’ in FreeRTOSConfig.h.         4     Using multiple FreeRTOS memory regions and Debugging Next I will allocate 100K memory with pvPortMalloc API in the hello_task.   int i;     unsigned char *handle;     for (i=0; i<10; i++)     {         handle =  pvPortMalloc(10*1024);         if (NULL == handle)         {             PRINTF("Malloc failed \r\n");         }         else         {             PRINTF("allocated buffer[%d], size 10K, address is 0x%x\r\n", i, handle);         }     } The console output is as below picture.  From the allocated address, we can see that 60K is allocated from SRAM_LOWER and 40K is from SRAM_UPPER.   SEGGER J-Link GDB Server V6.86e - Terminal output channel heapsize is 147432!. allocated buffer[0], size 10K, address is 0x1fff09c8 allocated buffer[1], size 10K, address is 0x1fff31d0 allocated buffer[2], size 10K, address is 0x1fff59d8 allocated buffer[3], size 10K, address is 0x1fff81e0 allocated buffer[4], size 10K, address is 0x1fffa9e8 allocated buffer[5], size 10K, address is 0x1fffd1f0 allocated buffer[6], size 10K, address is 0x20000298 allocated buffer[7], size 10K, address is 0x20002aa0 allocated buffer[8], size 10K, address is 0x200052a8 allocated buffer[9], size 10K, address is 0x20007ab0   From the heap and usage view, we can see the detailed memory info.            
View full article
LwIP can be used in two basic modes: Mainloop mode (“NO_SYS”)(no OS/RTOS running on target system) or OS mode (TCPIP thread) (there is an OS running on the target system). In mainloop mode, only raw API can be used. In OS mode, raw API and sequential APIs can be used. The raw API is an event-driven and non thread-safe API designed to be used without an operation system.  A particular application may register to be notified via a callback function for events such as incoming data available, outgoing data sent, error notifications, poll timer expiration, connection closed, etc. The callback functions will be called from the LwIP core layer when the corresponding event occurs. This post is focused on how to use raw API with MCUXpresso SDK. For sequential-style and socket API, please refer to below thread. https://community.nxp.com/docs/DOC-344955 Starting a network interface To create a new network interface, the user allocates space for a new struct net_if  and calls netif_add,  LwIP needs an IP address. LwIP can use either DHCP or a static IP address. IP4_ADDR(&fsl_netif0_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3); IP4_ADDR(&fsl_netif0_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3); IP4_ADDR(&fsl_netif0_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2, configGW_ADDR3);     netif_add(&fsl_netif0, &fsl_netif0_ipaddr, &fsl_netif0_netmask, &fsl_netif0_gw, &fsl_enet_config0, ethernetif0_init,              ethernet_input); netif_set_default(&fsl_netif0); netif_set_up(&fsl_netif0);   Pass ethernet_input API to netif_add API as input callback function that is called to pass ingress packets up in the protocol layer stack. LwIP Initialization Call lwip_init to init lwIP stack and all of its subsystems.   void lwip_init(void) { #ifndef LWIP_SKIP_CONST_CHECK   int a = 0; #ifdef LWIP_NOASSERT /* Caused compiler warning. */   LWIP_UNUSED_ARG(a); #endif   LWIP_ASSERT("LWIP_CONST_CAST not implemented correctly. Check your lwIP port.", LWIP_CONST_CAST(void *, &a) == &a); #endif #ifndef LWIP_SKIP_PACKING_CHECK   LWIP_ASSERT("Struct packing not implemented correctly. Check your lwIP port.", sizeof(struct packed_struct_test) == PACKED_STRUCT_TEST_EXPECTED_SIZE); #endif     /* Modules initialization */   stats_init(); #if !NO_SYS   sys_init(); #endif /* !NO_SYS */   mem_init();   memp_init();   pbuf_init();   netif_init(); #if LWIP_IPV4   ip_init(); #if LWIP_ARP   etharp_init(); #endif /* LWIP_ARP */ #endif /* LWIP_IPV4 */ #if LWIP_RAW   raw_init(); #endif /* LWIP_RAW */ #if LWIP_UDP   udp_init(); #endif /* LWIP_UDP */ #if LWIP_TCP   tcp_init(); #endif /* LWIP_TCP */ #if LWIP_IGMP   igmp_init(); #endif /* LWIP_IGMP */ #if LWIP_DNS   dns_init(); #endif /* LWIP_DNS */ #if PPP_SUPPORT   ppp_init(); #endif   #if LWIP_TIMERS   sys_timeouts_init(); #endif /* LWIP_TIMERS */ } LwIP Raw—Main loop   In the while 1 loop,  we need to Poll the driver to get packets.  When a packet is ready, call function ethernetif_linkinput()  to handle the actual reception of the bytes from the network interface. Then the type of the received packet is determined and the appropriate input function is called. Handle all system timeouts for all core protocols.   Please refer to tcpecho server demo in MCUXpresso SDK. evkbimxrt1050_lwip_tcpecho_bm\source\lwip_tcpecho_bm.c /*!  * @brief Main function.  */ int main(void) {     struct netif fsl_netif0; …       time_init();   …     lwip_init();   …       tcpecho_raw_init();   …     while (1)     {         /* Poll the driver, get any outstanding frames */         ethernetif_input(&fsl_netif0);           sys_check_timeouts(); /* Handle all system timeouts for all core protocols */     } }   When using the netconn and socket API, the timers are handled in the background and the user typically does not need to manually implement them.  In the raw mode, the user must manually implement any required timers. Evkbimxrt1050_lwip_tcpecho_bm/lwip/port/sys_arch.c void time_init(void) { #ifdef __CA7_REV     /* special for i.mx6ul */     SystemSetupSystick(1000U, (void *)time_isr, 0U);     SystemClearSystickFlag(); #else     /* Set SysTick period to 1 ms and enable its interrupts */     SysTick_Config(USEC_TO_COUNT(1000U, sourceClock)); #endif }     Using Raw API The LwIP raw API is designed around a series of callbacks, your application registers callback functions to process specific events. Most callbacks are centered around a “protocol control block”, or PCB. evkbimxrt1050_lwip_tcpecho_bm\lwip\contrib\apps\tcpecho_raw\tcpecho_raw.c tcpecho_raq_init is called for initializing the TCP echo server application.   void tcpecho_raw_init(void) {   tcpecho_raw_pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);   if (tcpecho_raw_pcb != NULL) {     err_t err;       err = tcp_bind(tcpecho_raw_pcb, IP_ANY_TYPE, 7);     if (err == ERR_OK) {       tcpecho_raw_pcb = tcp_listen(tcpecho_raw_pcb);       tcp_accept(tcpecho_raw_pcb, tcpecho_raw_accept);     } else {       /* abort? output diagnostic? */     }   } else {     /* abort? output diagnostic? */   } }     Tcpecho_raw_init calls tcp_new_ip_type for creating a new TCP protocol control block (PCB) tcpecho_raw_pcb. Tcp_bind is used to bound the new created tcpecho_raw_pcb to a local IP address and port. Next, function tcp_listen is called in order to start TCP listening process on the TCP PCB. Finally a callback function tcpecho_raw_accept is assigned for handling incoming TCP connections on the TCP PCB (tcpecho_raw_pcb). This is done by using  function tcp_accept. After that, the TCP echo server is ready to accept any incoming connection from remote clients. The following example shows how incoming TCP connections are handled by the user callback function tcpecho_raw_accept. static err_t tcpecho_raw_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {   err_t ret_err;   struct tcpecho_raw_state *es;     LWIP_UNUSED_ARG(arg);   if ((err != ERR_OK) || (newpcb == NULL)) {     return ERR_VAL;   }     /* Unless this pcb should have NORMAL priority, set its priority now.      When running out of pcbs, low priority pcbs can be aborted to create      new pcbs of higher priority. */   tcp_setprio(newpcb, TCP_PRIO_MIN);     es = (struct tcpecho_raw_state *)mem_malloc(sizeof(struct tcpecho_raw_state));   if (es != NULL) {     es->state = ES_ACCEPTED;     es->pcb = newpcb;     es->retries = 0;     es->p = NULL;     /* pass newly allocated es to our callbacks */     tcp_arg(newpcb, es);     tcp_recv(newpcb, tcpecho_raw_recv);     tcp_err(newpcb, tcpecho_raw_error);     tcp_poll(newpcb, tcpecho_raw_poll, 0);     tcp_sent(newpcb, tcpecho_raw_sent);     ret_err = ERR_OK;   } else {     ret_err = ERR_MEM;   }   return ret_err; }   The new TCP connection is passed to callback function tcpecho_raw_accept through the parameter ‘newpcb’ Structure ‘es’ maintains application status. Tcp_arg specifies the program state shat should be passed to all other callback functions.  ‘es’ is passed as an argument to the connection TCP PCB ‘newpcb’. Tcp_recv sets the callback function that will be called when new data arrives. ‘tcpecho_raw_recv’ is assigned to handle all the data traffic. tcp_err specifies the function (tcpecho_raw_error) that should be called when a fatal error has occurred on the connection. tcp_poll specifies the polling interval and the callback function (tcpecho_raw_poll) that should be called to poll the application. tcp_sent specifies the callback function (tcpecho_raw_sent) that should be called when data has successfully received (i.e ackknowledged) by the remote host. Finally tcpecho_raw_sent will call tcp_write Configuration LwIP lwipopts.h is a user file that you can use to fully configure lwIP and all of its modules. You do not need to define every option that lwIP provides; if you do not define an option, a default value will be used. Therefore, your lwipopts.h provides a way to override much of the behavior of lwIP. Use Mainloop mode, we do not run an OS. We need to #define NO_SYS to 1. Please refer to lwipopts.h in MCUXpresso SDK. evkbimxrt1050_lwip_tcpecho_bm\source\lwipopts.h … /**  * NO_SYS==1: Bare metal lwIP  */ #define NO_SYS 1 /**  * LWIP_NETCONN==0: Disable Netconn API (require to use api_lib.c)  */ #define LWIP_NETCONN 0 /**  * LWIP_SOCKET==0: Disable Socket API (require to use sockets.c)  */ #define LWIP_SOCKET 0   /**  * LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT=1: we need to free PBUF_RAM pbufs  * from ISR context on LPC.  */ #if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) #ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT #define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 1 #endif #endif …            
View full article
LwIP can be used in two basic modes: Mainloop mode (“NO_SYS”)(no OS/RTOS running on target system) or OS mode (TCPIP thread) (there is an OS running on the target system). In mainloop mode, only raw API can be used. In OS mode, raw API and sequential APIs can be used. In OS mode, the lwip stack and the application run in separate tasks. The application communicates with the LwIP stack through sequential API calls that sue the RTOS mailbox mechaniam for inter-process communicatioin. This post is focusing on how to design a LwIP applicatioin in OS mode with sequential API in MCUXpresso SDK. It is for LwIP beginners. The code snipperts is from MCUXpresso SDK2.6. For how to design a LwIP applicaton in mainloop mode (bare metal mode) with raw API, please refer to below link: Developing LwIP Applications with Raw API       Generally, a LwIP application inlcudes network interface setting up, LwIP stack initialization , using LwIP API, and configuration.   1. Starting a network interface To create a new network interface, the user allocates space for a new struct netif (but does not initialize any part of it) and calls netifapi_netif_add:     IP4_ADDR(&fsl_netif0_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3);     IP4_ADDR(&fsl_netif0_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3); IP4_ADDR(&fsl_netif0_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2, configGW_ADDR3);       netifapi_netif_add(&fsl_netif0, &fsl_netif0_ipaddr, &fsl_netif0_netmask, &fsl_netif0_gw, &fsl_enet_config0,                        ethernetif0_init, tcpip_input); Pass tcpip_input API to netif_add API as input callback function that is called to pass ingress packets up in the protocol layer stack   next we need to bring the interface up An interface that is “up” is available to your application for input and output, and “down” is the opposite state. Therefore, before you can use the interface, you must bring it up. This can be accomplished depending on how the interface gets its IP address.  We can use static IP address  or DHCP. Set the network interface as the default network interface netifapi_netif_set_default(&fsl_netif0);   Bring the interface up, available for processing     netifapi_netif_set_up(&fsl_netif0); 2. Initializing LwIP stack   Call tcpip_init to create tcpip_thread, this thread has exclusive access to LwIP core functions. Other threads communicate with this thread using message boxes. It also starts all the timers to make sure they are running in the right thread context.   tcpip_init(NULL, NULL);   void   tcpip_init(tcpip_init_done_fn initfunc, void *arg) {   lwip_init();     tcpip_init_done = initfunc;   tcpip_init_done_arg = arg;   if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) {     LWIP_ASSERT("failed to create tcpip_thread mbox", 0);   } #if LWIP_TCPIP_CORE_LOCKING   if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) {     LWIP_ASSERT("failed to create lock_tcpip_core", 0);   } #endif /* LWIP_TCPIP_CORE_LOCKING */     sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); } Priority of user task should not exceed the priority of tcpip_thread   - In lwipopts.h, the priority of tcpip_thread     #define TCPIP_THREAD_PRIO              2   3. Using sequential API  As shown in the below figure, the steps for establishing a TCP connection on the client side are the following: Create a connection using the netconn_new() function; Connect to the address of the server using the netconn_connect() function; Send and receive data by means of the netconn_recv() and netconn_write() functions. Close the connection by means of the netconn_close() function. The steps involved in establishing a TCP connection on the server side are as follows: Create a TCP connection with the netconn_new() function; Bind the server to an address using the netconn_bind() function; Listen for connections with the netconn_listen() function; Accept a connection with the netconn_accept() function. This call typically blocks until a client connects with the server. Send and receive data by means of netconn_write() and netconn_recv(). Close the connection by means of the netconn_close() function.   Middleware/lwip/contrib/appa/tcpecho/tcpecho.c static void tcpecho_thread(void *arg) {   struct netconn *conn, *newconn;   err_t err;   LWIP_UNUSED_ARG(arg);     /* Create a new connection identifier. */   /* Bind connection to well known port number 7. */ #if LWIP_IPV6   conn = netconn_new(NETCONN_TCP_IPV6);   netconn_bind(conn, IP6_ADDR_ANY, 7); #else /* LWIP_IPV6 */   conn = netconn_new(NETCONN_TCP);   netconn_bind(conn, IP_ADDR_ANY, 7); #endif /* LWIP_IPV6 */   LWIP_ERROR("tcpecho: invalid conn", (conn != NULL), return;);     /* Tell connection to go into listening mode. */   netconn_listen(conn);     while (1) {       /* Grab new connection. */     err = netconn_accept(conn, &newconn);     /*printf("accepted new connection %p\n", newconn);*/     /* Process the new connection. */     if (err == ERR_OK) {       struct netbuf *buf;       void *data;       u16_t len;             while ((err = netconn_recv(newconn, &buf)) == ERR_OK) {         /*printf("Recved\n");*/         do {              netbuf_data(buf, &data, &len);              err = netconn_write(newconn, data, len, NETCONN_COPY); #if 0             if (err != ERR_OK) {               printf("tcpecho: netconn_write: error \"%s\"\n", lwip_strerr(err));             } #endif         } while (netbuf_next(buf) >= 0);         netbuf_delete(buf);       }       /*printf("Got EOF, looping\n");*/       /* Close connection and discard connection identifier. */       netconn_close(newconn);       netconn_delete(newconn);     }   } }   From the tcpecho thread, we can see First, one new TCP connection was called with parameter NETCONN_TCP  by API netconn_new. #define netconn_new(t)                  netconn_new_with_proto_and_callback(t, 0, NULL) struct netconn * netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) {   struct netconn *conn;   API_MSG_VAR_DECLARE(msg);   API_MSG_VAR_ALLOC_RETURN_NULL(msg);     conn = netconn_alloc(t, callback);   if (conn != NULL) {     err_t err;       API_MSG_VAR_REF(msg).msg.n.proto = proto;     API_MSG_VAR_REF(msg).conn = conn;     err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg));     if (err != ERR_OK) {       LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);       LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); #if LWIP_TCP       LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); #endif /* LWIP_TCP */ #if !LWIP_NETCONN_SEM_PER_THREAD       LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));       sys_sem_free(&conn->op_completed); #endif /* !LWIP_NETCONN_SEM_PER_THREAD */       sys_mbox_free(&conn->recvmbox);       memp_free(MEMP_NETCONN, conn);       API_MSG_VAR_FREE(msg);       return NULL;     }   }   API_MSG_VAR_FREE(msg);   return conn; }   Then, the newly created connection is then bound to port 7 (echo protocol) by calling the API function netconn_bind.   Next, the application starts the listening process on the connection by calling the API function netconn_listen. In the infinite while(1) loop, the application waits for a new connection by calling the API function netconn_accept. This API will block the application task when there is no incoming connection. When there is an incoming connection, the application can start receiving data by calling the API function netconn_recv. Incoming data are received in a netbuf.       Application can get the received data by calling the netbuf API function netbuf_data. err_t netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len) {   LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);   LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);   LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);     if (buf->ptr == NULL) {     return ERR_BUF;   }   *dataptr = buf->ptr->payload;   *len = buf->ptr->len;   return ERR_OK; }   The received data is sent back (echoed) to the remote TCP client by calling the API function netconn_write. Netconn_close and netconn_delete are used to respectively close and delete the netconn connection     4. Configuration LwIP lwipopts.h is a user file that you can use to fully configure lwIP and all of its modules. You do not need to define every option that lwIP provides; if you do not define an option, a default value will be used. Therefore, your lwipopts.h provides a way to override much of the behavior of lwIP. In multi theads mode, . We need to #define NO_SYS to 0. Please refer to evkbimxrt1050_lwip_tcpecho_freertos\source\lwipopts.h … #if USE_RTOS   /**  * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain  * critical regions during buffer allocation, deallocation and memory  * allocation and deallocation.  */ #define SYS_LIGHTWEIGHT_PROT 1   /**  * NO_SYS==0: Use RTOS  */ #define NO_SYS 0 /**  * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)  */ #define LWIP_NETCONN 1 /**  * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)  */ #define LWIP_SOCKET 1   /**  * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and  * SO_RCVTIMEO processing.  */ #define LWIP_SO_RCVTIMEO 1 …          
View full article
This article describes how to configure a peripheral timer in a FreeRTOS project with MCUXpresso config tools. Software and Tools In this article, I’m using the following: MCUXpresso IDE 10.2.1   www.nxp.com/mcuxpresso MCUXpresso SDK 2.4.1 for  Frdm-k66f  board.  With Amazon FreeRTOS v10 . You can get it from https://mcuxpresso.nxp.com FRDM-K66 board  www.nxp.com/frdm-k66f First make sure you have a working FreeRTOS project. Please refer to below link for creating a new FreeRTOS project.  https://community.nxp.com/docs/DOC-341972 To open the tool, simply right click on the project in Project Explorer and select the appropriate Open command: With the peripheral Tool, we can use it to configure initialization of selected peripherals and generate code for them. we are picking the FTM0 timer ,of course we could use any other timer too. Click OK, then configure the timer to 10KHz. We will use the timer interrupt to increase a counter, so don’t forget to turn on the interrupt To update the generated code in the related tool chain project, click the Update Project button. Click OK, new code will be generated. Please check peripheral.c & peripheral.h Timer ISR Next we add the timer interrupt code to the application. #include "fsl_ftm.h"   /*******************************************************************************  * Variables  ******************************************************************************/ volatile bool ftmIsrFlag = false; volatile uint32_t milisecondCounts = 0U;       void FTM_1_IRQHANDLER(void) {     /* Clear interrupt flag.*/     FTM_ClearStatusFlags(FTM0, kFTM_TimeOverflowFlag);     ftmIsrFlag = true; } Adding Timer Drivers The project won’t compile yet, because the necessary drivers are not part of the project yet. To add them, use the ‘Manage SDK components’ button: Then check the ftm driver and press OK and get the extra driver sources added to the project. We can see that fsl_ftm.c & fsl_ftm.h added into this project. Adding timer to FreeRTOS application: In this task, the FTM interrupt will trigger a message printed to the terminal /*!  * @brief Task responsible for printing message with FTM0.  */ static void my_task(void *pvParameters) {       uint32_t cnt;     uint32_t loop = 2U;     uint32_t secondLoop = 1000U;     const char *signals = "-|";       cnt = 0;       while (true)     {         if (ftmIsrFlag)         {             milisecondCounts++;             ftmIsrFlag = false;             if (milisecondCounts >= secondLoop)             {                 PRINTF("%c", signals[cnt & 1]);                 cnt++;                 if (cnt >= loop)                 {                     cnt = 0;                 }                 milisecondCounts = 0U;             }         }         __WFI();     } } Run the demo console output: For information about how to use MCUXpresso pins tool in a FreeRTOS project, please see the following document. https://community.nxp.com/docs/DOC-341987 For information about how to create an FreeRTOS project with MCUXpresso IDE, please see the following document https://community.nxp.com/docs/DOC-341972 
View full article
This documents describes who to use this tool in order to generate the routing and muxing for pins. Pins Tool Overview The Pins Tool is an easy-to-use way to configure the pins of the device. The Pins Tool software enables you to create, inspect, change, and modify any aspect of the pin configuration and muxing of the device. This document introduces you to the Pins Tool. It describes the basic components of the tool and lists the steps to configure and use the tool to configure the pins. This tool is provided as an online WEB application. You need to generate a downloadable MCUXpresso SDK v.2 package. The below link shows the steps for do that. Generating a downloadable MCUXpresso SDK v.2 package  Selecting Pins Tool SDK v.2 package. The below link sh
View full article
Generating a downloadable MCUXpresso SDK v.2 package   Follow these steps to get your MCUXpresso SDK v.2 package for your Kinetis or LPC-based MCU solution.   1) Go to the MCUXpresso Config Tools page:   Welcome | MCUXpresso SDK Builder    2) Click on the Select Development board option:     3) If you are not logged in you will be redirected to the Sign in page:   4) After signing in you will be directed to select a development board, to do this you need to select the corresponding processor, board or kit to be used and click on Build MCUXpresso SDK:     5) By default the package will be built for Windows and for the MCUXpresso IDE, this can be changed by clicking on drop-down menus:     6) You can also specify the included middleware, RTOS and development preferences for your MCUXpresso SDK package.        7) After specifying the required settings make sure the configuration information shown on the right hand side is correct click on Download SDK:     Note: You may be asked to fill your User basic information on the Preferences page before downloading the package.   😎 Agree to the Software Terms and Conditions:     9) The download of your MCUXpresso SDK package should start automatically:         Related links: Introducing MCUXpresso SDK v.2 for LPC54xxx Series  How to start with SDK v.2.0 for LPC5411x using LPCXpresso IDE  Using the MCUXpresso Pins Tool   MCUXpresso Config Tools is now available!  
View full article