# Initialize the USB as a USB device

At the beginning, the microcontroller should act as a USB device. To do this, the USB module must be initialized and configured as a USB device. The initialization takes place in several steps. I beginn with this part of the tutorial, where I deal with the initialization of the microcontroller as a USB device. The next part will deal with the configuration of the USB endpoints and then the descriptors will be created and the device logged on to the host and communication established.

The complete configuration of the USB module is divided into the following steps:

* Configuration of the USB controller (part of this section)
* Configuration of the USB device controller (explained in the next sections)
* Configuration of the USB host controller (part of another chapter)

General configurations have to be done in the USB controller module and the host or device controller is used for the respective operating mode. Since the microcontroller should work as a USB device, both the USB controller and the USB device controller are required.

Before the USB controller can be used, it must be reset so that it is in a defined state. To do this, the *USBE* bit in the *USBCON* register of the USB controller is deleted and immediately set again.

```
USBCON &= ~(0x01 << USBE);
USBCON |= (0x01 << USBE);
```

In the further steps of this program, certain actions should be executed when the USB module is in a certain state (e.g., the enumeration with the host should not be done if the USB controller has not been initialized). Therefore, a state machine needs to be implemented:

```
extern volatile USB_State_t _USBDeviceState;

_USBDeviceState = USB_STATE_UNATTACHED;
```

The next steps can be found in the data sheet.

![](https://2801891837-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvA_nizlqrtUSmfwyso%2F-LxvTOAW6CM3YDPefcFj%2F-LxvXp0O9jqKLTwocjSO%2Fimage.png?alt=media\&token=363219e1-d851-419d-8640-53a1cc553b27)

After a reset, the USB device mode is automatically activated because the external *UID* pin of the microcontroller is deactivated (*UIDE* = 0) and the *UIMOD* bit is set. Furthermore, the PLL for the USB module gets turned off during a reset by setting the *FRZCLK* bit in the *USBCON* register. This bit must also be deleted after a reset.

```
USBCON &= ~(0x01 << FRZCLK);
```

It is recommended to use the internal voltage regulator to ensure the supply voltage of the data lines. This voltage regulator is automatically inactive after a reset and must therefore be activated by setting the *UVREGE* bit in the *UHWCON* register.

```
UHWCON |= (0x01 << UVREGE);
```

In order for the microcontroller to attach to the USB and the host to recognize the new device, the *VBUS* pad must also be activated via the *OTGPADE* bit in the *USBCON* register.

```
USBCON |= (0x01 << OTGPADE);
```

The configurations of the USB controller is done now and ready to use. The USB module is working in device and has to be configured.

The USB speed is controlled via the *LSM* bit in the *UDCON* register. Depending on whether the bit is set or deleted, the pull-up resistor for the data line is connected to either D+ or D- when connecting.

![](https://www.kampis-elektroecke.de/wp-content/uploads/2019/04/USB_Controller2.png)

The microcontroller should work as a low-speed device. For this, the *LSM* bit in the *UDCON* register must be set.

```
UDCON |= (0x01 << LSM);
```

Both the USB controller and the USB device controller have different interrupts to react to external signals.

![](https://2801891837-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvA_nizlqrtUSmfwyso%2F-LxvTOAW6CM3YDPefcFj%2F-LxvZLWT3ktvfnzobJ1n%2Fimage.png?alt=media\&token=d3f6f3db-12fa-4c9e-920c-65ab5aa93d88)

Only the VBUS interrupt is currently required, as this is used for plug-in detection. This interrupt is activated via the *VBUSTE* bit in the *USBCON* register.

```
USBCON |= (0x01 << VBUSTE);
```

The *DETACH* bit in the *UDCON* register must be cleared so  the selected pull-up resistor is connected to the corresponding data line and the device is detected by the host.

```
UDCON &= ~(0x01 << DETACH);
```

A 48 MHz clock is required for the USB controller to work properly, because the 12 MHz clock for full speed or the 1.5 MHz clock for low speed mode is generated from this clock. The 48 MHz clock is generated using an internal PLL from an external 8 MHz crystal.

![](https://2801891837-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvA_nizlqrtUSmfwyso%2F-LxvTOAW6CM3YDPefcFj%2F-LxvZyxTirh7h-JhX-ws%2Fimage.png?alt=media\&token=0c5a7750-3c7c-4c0d-9a87-c83dd3ccaa39)

It makes sense that the PLL is only activated when a connection to a host is detected in order to reduce the power consumption of the device when not in use. The PLL is controlled and configured via the *PLLCSR* register. With an AT90USB1287, an external 8 MHz crystal must be used to generate the USB clock. Furthermore, both the *PLLP1* and the *PLLP0* bit must be set in the *PLLCSR* register.

![](https://2801891837-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvA_nizlqrtUSmfwyso%2F-LxvTOAW6CM3YDPefcFj%2F-Lxv_QmCRg6XOUGaIsGl%2Fimage.png?alt=media\&token=a22ac8c3-06b6-4a10-b379-6a15d711e743)

The PLL is configured in the ISR of the USB controller as soon as a VBUS interrupt has been triggered.

```
ISR(USB_GEN_vect)
{
	if((USBINT & (0x01 << VBUSTI))
	{
		USBINT &= ~(0x01 << VBUSTI);
		if(USBSTA & (0x01 << VBUS))
		{
			PLLCSR = (((0x01 << PLLP1) | (0x01 << PLLP0)) | (0x01 << PLLE));
	 		while(!(PLLCSR & (0x01 << PLOCK)));
			_USBDeviceState = USB_STATE_POWERED;
		}
		else
		{
			PLLCSR = 0x00;
			_USBDeviceState = USB_STATE_UNATTACHED;
		}
	}
}
```

Since the USB controller has only one common interrupt vector for all general USB interrupts, the ISR must first check whether the *VBUSTI* bit is set in the *USBINT* register and whether the VBUS interrupt is activated at all. Then the interrupt flag is cleared and a check is made to determine whether a device is connected by querying the *VBUS* bit in the *USBSTA* register.

The PLL is only configured when all conditions are met. To do this, the prescaler is set using the *PLLP1* and *PLLP0* bits and the PLL is activated using the *PLLE* bit. The query of the *PLOCK* bit waits until the PLL has stabilized.

```
PLLCSR = (((0x01 << PLLP1) | (0x01 << PLLP0)) | (0x01 << PLLE));
while(!(PLLCSR & (0x01 << PLOCK)));
```

Finally, the internal status of the USB driver is updated.

```
_USBDeviceState = USB_STATE_POWERED;
```

The program can now be executed and the microcontroller connected to a host. However, when you plug it in nothing will happen, as the host has so far only recognized that a device is there, but not what kind of device it is. Therefore, the host reports an error when requesting a device description.

![](https://2801891837-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LvA_nizlqrtUSmfwyso%2F-LxvTOAW6CM3YDPefcFj%2F-LxvaRqfyedhK2d1LaEv%2Fimage.png?alt=media\&token=15ae0733-4497-4256-a6b6-01df280fceed)

This problem will be solved in the next parts of the tutorial. But before this issue can be addressed, the control endpoint of the USB device must be initialized. This will be the topic of the next part of the USB tutorial.
