Create the device driver
Now let's see how we can implement communication between the two bus participants. For the communication with my board, I use a Python script and the PyUSB module on the host.
Last updated
Now let's see how we can implement communication between the two bus participants. For the communication with my board, I use a Python script and the PyUSB module on the host.
Last updated
Before the communication can be implemented, some preparations have to be made. First of all, Python (I'm using version 3.7) needs to be installed. The PyUSB module is then installed from the command line:
In order for USB devices to work under PyUSB, an adapted device driver is required, which can be created using the inf-wizard. The inf-wizard is part of libusb and is located in the bin directory.
This program is started as administrator and after clicking on Next you get to a list of recognized USB devices, where the microcontroller is then selected.
The selection is confirmed with Next and the following mask is filled in if necessary. Next takes you to the next menu, but you first have to specify a storage location for the generated files. The generated driver can be installed immediately via Install Now ... . If the installation was successfully completed, the board is listed as a correctly registered USB device in the device manager:
Before the communication between host and device can be started, the end points of the device must be configured. This usually takes place when the device has been successfully initialized by the host, i.e. when the host has assigned an address and selected a configuration. The endpoints should therefore be configured using the configuration change event of the USB_DeviceCallbacks_t object:
When the configuration of both endpoints has been carried out successfully, the green and red LEDs are switched on and the device is ready for operation. Otherwise the device switches to error mode.
Now you can start communicating with the device. The goal should be to read the result of the analog / digital converter of the microcontroller via USB. The measured data are transmitted to the host via the IN endpoint of the microcontroller and the host transmits the requested ADC channel via the microcontroller's OUT endpoint.
In the Python script, the PyUSB module is first imported and checked whether a device with a specific vendor and product id (the id isassigned via the descriptor) is connected to the computer via USB.
If a suitable device has been found, a corresponding configuration (in this example there is only one configuration) can be selected, set and read out:
The addresses of the existing endpoints are also required for communication with the device. The endpoint descriptors should therefore also be read out.
The find_descriptor method requires the current configuration as a parameter as well as a lambda expression that describes the filter rules. Since the current device has only one IN and one OUT endpoint, it is sufficient if the end points are selected according to their transfer direction. The information read out is then output.
Next, the Python script expects a user input. Here the user should enter the desired ADC channel, numbered from 0 to 7. The script checks the input and then throws an exception if necessary.
The entered channel is then written to the OUT endpoint of the target device.
The data packet must now be processed in the microcontroller program. A new function called USB_DeviceTask is created for this. This function is called cyclically and after each call the state machine of the USB controller is queried to check whether the device is ready for use.
Then the OUT endpoint is selected. The software can use the RWAL bit in the UEINTX register of the endpoint to query whether the endpoint is empty and can send data (only for IN endpoints) or whether the endpoint has received data and can be read out (only for OUT endpoints).
It is not allowed to use the RWAL bit for a control end point!
When data has been received, the transmission is confirmed by the device and the data can be read out. With the data byte read out, the ADC channel is selected and an ADC measurement is started.
As soon as the measurement is finished, the ADC jumps into an interrupt and writes the measurement result to the IN end point of the microcontroller. This is done in a similar way to the OUT endpoint:
Chose the endpoint
Check RWAL
Check of the IN endpoint is empty. Set TXINI and FIFOCON if the endpoint is not empty.
Write new data
Transmit the data
The IN endpoint can now be read out using the Python script.
The values are then converted and displayed:
The script is now done. The microcontroller is now still being programmed and connected to the PC. Then the ADC can be read out.
Now the first big milestone of this USB tutorial is complete. The microcontroller is communicating with the host as a device, we can access the microcontroller via USB, start a measurement and read out the measurement result. All of this is done with an unofficial device description, which has been created only very rudimentary. In addition, we are not yet able to use standard drivers such as it exist for a mouse or something else.
Therefore, we want to deal with the implementation of an existing USB device, namely a USB mouse in the next steps. This requires some additional knowledge of the different USB classes and we have to adapt the software for the microcontroller. So the device descriptors are filled in accordingly so that the microcontroller can be controlled by standard drivers. I would like to start with the so-called HID (Human Interface Device) class of the USB protocol.