 So let's start with the hands-on on how to build the composite device. So the most important thing I showed you in the initial slides was related to the fact that with these USB X-TAC, we can very easily create a device with more than one class in parallel. So in this case, in our example, with USB X native support of multiple classes and integration of the STM42 cube MX, you will see how easy it is to integrate and generate firmware for USB composite device. So with our previous library, you have different manual changes. In this case, into each cube Azure RTOS H7 pack, you already have examples like the one that I'm pointing you to here. For HID, CDC, ACM, so you already have an example. We are basically going to replicate this example. I'm going to explain you how to generate the code, how to build and how the application is made. There will be some differences versus the original example that we distributed that I'm going to underline. In terms of functionality, so apart from building a composite device, in terms of functionality, we are going to test the right functionality of the two classes on HID by seeing periodically the mouse moving, and it's moved from the HID device. So it's meaning a mouse, and the CDC Virtual Comport is going to echo the incoming data packet. So very important for this part, you will need a second USB cable I can anticipate you that should be connected to CN13, which is the USB connector on the opposite side of the SD-Link, so the one you should have currently connected. It's the connector which is on the side of the RJ45 internet connector. Another thing that I'm going to show you is that this time, just to show you a different tool, we are going to start with CubeMX. So I'm going to start with CubeMX. Of course, the two approaches are similar, if not identical. You can of course follow along even with the simple CubeID, but I want to show you CubeMX, which is a tool which is actually integrating different parts from which you can start the project that you see in different ways. So in this case, I'm going to start from the MCU selector. So please select to access to MCU selector. Another different thing that we're going to do is that here, we want directly to start from the chip, not from the nuclear because we will start from an anti-project. So you can type H273VG and select the VGTX device. Okay. After that, you can just click here and start the project. So select STM32. I think I picked up the wrong one. It's ZGTX. Select the 723ZGTX and start the project. Okay, good. So we have the usual helicopter view of the chip. Now, we should concentrate on configuring the peripherals that are needed to run this demonstration. So as a first thing, we are going to go into connectivity. We select USB OTG iSpeed, and we want to enable the internal file for device only. So be sure to select internal full speed file device only and not the external. Once you have selected device only, you will see the data pins of the USB mapped to PA12 and PA11. So if this is done correctly, please do not forget to enable the global iSpeed interrupt. You can enable it from here or eventually, you can also go for an alternative which is system core nested vector interrupt controller. You can flag it from here. So here you have the old interrupt table and now we are enabling just the HS iSpeed USB global interrupt. So we are now a slide number nine of our presentation. So we know that precise clock are mandatory for USB application. In general, for implementing an host, you will need an iSpeed external clock. But for a device, you can typically use HS i48 plus an external low-power crystal oscillator like in STM-42L4. But in case of STM-42H723, you can use HS i and the clock recovery system. So on RCC, which is here, which is a reset and clock controller, you can go to clock recovery system, sync and select USB high speed. So the goal of clock recovery system is actually to obtain a precise enough clock signal to be used by the USB module without the need of any external resonator component. So the preference may function are basically its ability to train the internal oscillator on the flight. So in this way, we can meet the USB protocol requirements and have enough information available for the user and basically no issues into the USB communication. So this is just to give you a little bit of background on why we are doing this. As said, we need the clock recovery, but we also need to clock the peripheral with HS i48. So please click to clock configuration. We do not want to run automatic clock solver, so please click no if a pop-up like that one appears. Here, for those who are new to the STM-42 architecture, you have the clock tree. You see here HSE, LSE. You have the different clock sources inside the pin and you see how the dividers are set to be distributed to the various bus on the MCU, peripheral bus or to the AXI. You will also see that you have some output pin because you can basically enable the main clock output on some of the pins. This feature is available in most of the STM-42 devices. What we want to do in brief is scroll a little bit down, go to USB section and configure the HSE 48 clock for the USB. Once you do that, you receive 48 megahertz reported into the USB block. So it means that you have clocked it correctly with the 48 megahertz. So still being on the clock tree, we want to set the full clock frequency. So the minimum high clock frequency for OTG is typically is 14.2 megahertz. Here we just want to run at full speed. So let's try it into this box, 550 and press enter. If you got a warning like I am getting, just click on okay and the tool will automatically look for a solution. And I can tell you that the solution will be switching the source of the system clock mooks from HSI to PLL. You will see that the PLL here will become blue. We will select the right dividers to achieve the wanted high clock frequency. Very good. So we can come back to pinout and configuration. Let's go back to pinout and configuration and let's click on software packs. And the usual select component you have seen before. So as I told you initially, we still do not have a bare metal implementation of this middleware. So for that reason, we are gonna use ThreadX APIs and you need to enable the ThreadX score. This is very important to do. And you have now to go to USB X that you will find in a tab right after file system interfaces. And here we want to enable the core system. We want to enable the device core stack and we want to enable the device controller. Regarding the specific classes, we want to go for device class HID and device class CDC HAM for the virtual COM port. So maybe here there is a lot of settings to be done so I can enlarge a little bit the screen so you all can see. You have to select the first core system, then the core stack of course, the controller, which is the link in the middleware with the physical peripheral, HID class, and then CDC HAM class device role. So pay attention because on the middle of the chart you will have the host roles. You have to select the device because we are gonna build the device. And I click OK now. I think you have learned along the workshop that once we enable the software pack, we have some new modes to be selected here into this tab. And in our case, we have both ThreadX and a USB X. In Azure RTOS application, we want to set the memory pool size for the USB device and we are gonna put 8224. It's 18224. This is the memory needed for the USB X application. At the end of the presentation, we will analyze in detail why we are using this amount of memory and how this can be optimized. So don't worry, it's not a magic number. You are gonna see in detail why and where does this number come from. On ThreadX, we don't touch anything. Instead, we have to go now to the USB X table. So in the USB X chart, please be sure to select class driver two because we are actually implementing two classes. And this is at the level of device score. Then for HAD, we do not touch anything. And on CDC HM ACM, we want to modify the endpoint's number. So currently in the USB X middleware, the same endpoint cannot be used for in and out endpoint at the same time. So maximum number of USB endpoint is defined by four bits. So from zero to number 15. And for in STM42 USB, we can use a maximum of eight in and eight out endpoints. So what we are gonna do here is that you see that there are some endpoints in numbers that are replicated for the different functionality, command or in and out. So we have to modify those. So instead of one for the in common address, we are gonna put endpoint number two. For the endpoint in address, we are gonna assign number three. And for endpoint out address, we are gonna assign number four. So usually we are gonna use successes, number is starting from one. And in this case, what we did simply was to use endpoint one in for HID, endpoint two for command and control of CDC and endpoint three and four for in and out of CDC HM. Later on, I'm gonna explain you what we did practically, but so far the important message is that in USB X, the same endpoint number cannot be used for in and out at the same time. So two, three and four in class CDC HM. We have not touched HID and we want to use two classes. I'm gonna move to the last step, which is a known step system. We want to use a timer for the time base. So we are using timer six because it's basic timer as you see here. So we don't want to waste resources. You could have used any other basic timer like timer seven. Good. So the configuration is now complete, meaning that we have now to move to project generation. So please click on project manager and go to project and give your example name, like I can call it USB X 2810 as the date of today. We want to generate the project for STM42 cube IDE. Keep everything as default. We can keep even the default EAP and stack settings as memory allocation is now handled directly in Azure middleware. And we can now move to code generation. On congenerator, we flag the option generate peripheral initialization as pair of dot C and dot H files per peripheral. This is needed due to the architecture of USB examples. Please flag generate peripheral initialization as pair of dot C and dot H file. Then let's move to advanced setting and on the rank number three, MX, USB, GTG, HS, PCD unit, please click on do not generate function call. We do not want to generate this because the PCD unit is called directly from appusbxdevice.c. You will see later in detail. If you got to this point already, you can of course click to generate code. And the magic will happen and the code will be generated in your root directory. And you are gonna get now a pop-up window right after code generation, saying if you want to open the folder or open the project. So now we open the project. We're gonna get a screen like this. I'm gonna press on launch, okay. So we have successfully imported the project, which is very good for us to keep on going. Okay, so I show you the structure. The structure is the one that we have already seen from before. So actually in the source, we have the main dot C, but then we directly jump into the operating system and the entry point for our USB app is actually into USB app folder usbxdevice.c. So this is the main file in which we have to work on and you see it's completely empty. So we need to create our own application and for saving some in order to save some time, we have prepared a copy folder content into the installation material that we provided for the webinar. So I'm gonna share you a slide to show you where you should find the files. So the default path files to be copied are contained in Azure, RTOS, workshop material and so on, USBX, USBX copy files. So please go there. It's clear that we need to copy this file into the project folder. So there are several ways to do so. If you want to follow along with me, what we are gonna do is that basically we're gonna take our files from the repository and we need to copy them into the project folder. So in my case, I'm gonna open, I'm gonna click on properties. I will go to the project folder and I will go to USBX and okay, this is my project and on the other end, this is instead my source folder. So what I'm gonna do is that I'm gonna take these files and I'm gonna bring them into the project. I will replace the files in the destination and now I go back, close, I go back to the project, right click on it and press refresh and now I should see something in up USBXdevice.c, meaning that we have copied correctly the file. Now, all is set to run your project into STM42H723. So please just directly run the project with the play button. This will build and will program the STM42H723 via stlink v3. So it's gonna take some time. Okay, so anyway, if you have got to this point, so we're just really a matter of debugging but everything is set to theoretically we have the code generated correctly. Maybe just one thing, I spend another minute and then I move forward. One thing will be to check if you have correctly set the do not generate function call on advanced setting for the USB OTG and generate peripheral initialization as a pair of .c.h file per peripheral. This is just an idea. I'm not sure this is gonna help you but to review the whole passages where we are including some .h file, it's this passage here. Anyway, the idea is you are at 80% of the work. The remaining 20, 25 minutes will be on showing you what we did in practice. So showing you the functionality and the second step, just going through the code to explain you what every line of this up USB X underscore device does. So we can for sure review offline or after the webinar workshop, we are gonna have 30 minutes for open discussion. So this definitely, this will be a good point to review but I'm sure that you can anyway follow along because I'm gonna show you basically how it works practically, what we did practically and good some more and solve it and how to move along reviewing the various part and the various portion of the code. So we have implemented the mouse. So first thing is go to control panel, click on control panel of your Windows machine, hardware and sound, device and printers. You should see STM42 USB device which is exactly the one that we just created. And you see the functionality here is pretty nice. So our mouse cursor is moving once every five seconds. We decided to put this periodicity to helping you any way to use the mouse while the board is connected. But you see the mouse is moving nicely once every five seconds if you don't touch it. So HAD is there. Now let's go and see if a CDC ACM virtual comport is there, I'm gonna use a terminal view. For me is there might before doing that, we need to know exactly where the serial port is connected. So please go into your device manager and have a look at the comport. You see you should have at least, I will say at least two comport, one for the ST link and it's a new serial com device. This is the VCP for the STM42 H7 we created. So it means we need to connect to com seven. So I'm gonna go to com seven and I will enable the echo. So I'm gonna write something and I'm getting the echo back. So it means that the CDC ACM VCP is correctly implemented and we have two classes working in parallel on the same USB device and you have seen how quick and easy is to deal with this composite device using a Tredex and the integration of Cubamax. We are gonna focus on what we got and pasted. So I have basically just cut and paste some code but I really want to go through it to explain you exactly what we did and how this is implemented. So we saw that the entry point is upusbdevice.c and you see that the interesting part starts from line 108 where we have the definition of string descriptor and device descriptor. So we have descriptors for full speed and high speed USB. Of course, the high speed is redundant but mandatory for the USB high speed interface. So in terms of optimization, high speed part can be skipped and then we have the string framework and the language ID framework defined here and which are these two parts. So just to show you in picture, this is the flow we are following. You will see a very similar picture into the Microsoft documentation. So now we are at the device descriptor level. We have defined the device framework for high speed, full speed, the string and the language framework. Now we have to go to move forward and as a first thing, we have to define this number here. BNUM configurations. So the USB device can have multiple configuration which are not used in parallel but are embedded in the device and decided by the host. So I will say mutually exclusives. This is not our use case. So we are gonna use just one configuration. So in our case, BNUM configuration will be equal to one. Please remember this number because we are gonna use it in a few minutes. And now that we have defined it that we are gonna just use one of the two gray blocks, we have to define the interface descriptor. So we are gonna have three interface descriptor, one for HAD, one for the command signal of the virtual comport and another one for the data with the related end points descriptor. So if this is clear and this is the track of what we are gonna do and actually what we have already done and we have to just understand a little bit more in detail. So right after the descriptor initialization, we pass this descriptor to the stack. So we are gonna go through this function later on. For now, it's sufficient to understand that we call in satisfaction, the middleware in it. We are gonna also see how much memory we are gonna use in this step. So we pass to the stack, the descriptor and we initialize the middleware. Now that the descriptor are initialized and pass it to the middleware, we are gonna initialize the classes. The first class is definitely HAD. So we assign to HAD the mouse report descriptor. It's length, it's a report ID and the callback. So the class callback in HAD do control click is empty. There's just a rate on zero. Another interesting thing to notice is that we initialize the HAD class and the class is connected to interface zero, which is this number here and to configuration number one. Because as I said at the beginning, we are just using one configuration. So configuration starts from one and interface number starts from zero in this stack. And here you see how we are basically adding an error handler on each and every step. So the error is propagated on the whole level of the stack. So this gives you an idea on the robustness of the USB X stack. So let's go back to our picture, which is very helpful IO. We have defined the device descriptor now. We are at the class initialization. So we are defining the HAD interface on interface zero. You will see that CDC ACM will use two interfaces, interface one and interface two. So here you will have one one and one two. And HAD will only have one input point and the CDC will have one input point for comments and one for data in and one for data out. So in total four end points are used. We are not gonna use it all the second branch because we are just using one configuration. So we have initialized the class, but now we have to create the thread that are gonna handle the classes and their functionality. So we are now gonna jump into a section of the code where there are functions that should sound familiar to you. We are gonna initialize and allocate, first of all, the stack for the thread, which is the main USB up thread entry. And basically, as you see here, we allocate the memory and we create the thread as we saw before. As you have already seen these thread create function, we also have another thread, which is HAD USB X up thread entry for which we are allocating the stack and we are creating the thread. So I cannot tell you that the first thread, so up USB thread entry is the main thread where we initialize the USB peripheral. We determine the type of file, the end points, the DMA used. It's initialized only one time for the whole application and for HAD we have a dedicated thread which is USB HAD thread entry. So the entry function are clearly USB up thread entry and USB HAD thread entry. So in case of single class device, you see how easy it is. So it will be all, but we are creating a composite device. So everything I told you regarding class initialization, registration of the classes and the thread creation is exactly identical for the CDC. You see the CDC has interface number one and we are creating a new thread for it, just one, because the previous one that was up thread entry is used only one for the whole application. So in this case, we have USB CDC HAD thread entry, priority 22, priority is higher here because instead the mouse is refreshed once every five seconds, so it doesn't need high priority. Just a note, I told you that there is a reading example existing on CDC ACM plus HAD composite device. This is making actually use of two threads because normally you would have one thread for the X and one thread for RX. As here we are using the echo, we are just creating one thread for the communication. So as promised, we are gonna jump into the entry function of the threads we created. So the first one is USB up thread entry. You see that it starts with a delay, with a slip actually, which is not mandatory actually. It's used to let other part of the system initialized before USB communication starts and then it calls MX USB device in it. If we go into it, you see that we have this power-enabled USB voltage detector, which is power-enabled for USB peripheral and it's needed for H7. And we have USB OTGA HSPCT init, which is USB peripheral init based on the setting we did on Cubemax. And then we allocate the memory USB peripheral used for the endpoint with the HAL-PCD-SET-TX-FIFO. And we also have the UX, the CDSTM42 initialize, which is a function in USBX, which is initializing the STM42 USB peripheral. And then we have the HAL-PCD start, which is starting the USB device. So you now understand why this is just called at once in the application. Then for the two threads belonging to the class, the flow is identical. So instead of class here, you could have HID or CDC imagine, but the flow is identical. So we check if the device is configured. We pick the data interface used by the class. We check if the user interface has a expected class parameter. We do some action and we add some sleep. HID uses actually inter-append points, which are periodical and CDC actually is not periodic. So in case of CDC only user thread is used. So this is the prototype of a class thread function. You can imagine the same for CDC and for HID. So we check if the device is correctly configured. We get the data from its interface number. We check if the data are the one that we are expecting, and then we perform some action. So in case of HID, the action can be moved the cursor once every five seconds. And in case of CDC, the action can be writing back the data buffer that we get from the virtual comport. In fact, you should expect to get the data from the right interface number that you have set initially. So as I told you in a USB CDC ACM, we basically have a portion of the code that I can show you here, which is echoing back the message. So if we go to the CDC ACM entry function of the thread, you see that we have a check if the data, if configured, we compares to memory block to see if the data we are getting are the one that are expected. And then what we do is read and write back the same buffer and go to sleep. In case of the HID, instead, you will see that in HID thread entry, the body of the thread is actually sending the event once every five seconds to move the mouse. So there's a device connection check. There is a selection of the right interface and then there is the class action. And at the end, we have the five seconds delay, which is the one that makes our cursor move. So as I promised, I need to explain a little bit the memory consumption and the reason of that magic 18,224 number. So in this case, overall memory consumption with GCC normally optimized for size with the default Q parameter is around 36K of RAM, 27K, sorry, 36K of flash, 27K of RAM. With a little bit of optimization, we can go down to 14K bytes. If compared with our current stack implementation is a little bit higher at the consumption, but this is the price to pay for the quality. So you saw our robustities, you see all the certification tests, you saw how the error is propagated across the different levels of the stack. So it's clear that this will impact a little bit the footprint and you see that actually, the tables shows the consumption of the various element and we have around 15K bytes of allocated memory for USB X. So this is the consumption for every function and there are basically three points to be underlined. The transfer request buffer, which is by default 256, this define the maximum number of bytes received on a control endpoint in the device stack. And the default is 256 bytes. So this is the one that is impacting a little bit more than endpoint data memory, which is by default 2048. It's the space for each user endpoint for our full speed device. So this is another value that is impacting a lot into the memory allocation for this functionality. So just one note, the X and RX CDC threads are currently not used so this can be further optimized. So the total here will be, this explains the 15K bytes are located for USB X. And with that, we are done for this section on USB. I leave you here with a link to the very complete RTOS USB X documentation on Microsoft website. STM42 wiki USB page that is a good summary of what I've just showed you. In fact, if you go straight to the page, you will see all the contents that we spoke about, which are also, I mean, giving additional explanation to the examples, which are included in our H7 pack and are basically these ones. You see the one that it's closer to what we implemented today is this one, UX device, HID CDC ACM. And last but not least, I leave you the link directly to the example project in its cube Azure RTOS H7 package. Having saying that, I would like to thank you for the attention.