Atxmega32A4u: USB HID descriptor error?

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please see end of post for solution/workaround

Hello AvrFreaks,

 

I built a small project with a composite USB 2.0 device containing two HID devices:

 

  • a simple HID keyboard (only one key at a time, no control keys, no LEDs)
  • a generic HID device for data transfer (32 byte endpoint size for IN and OUT)

 

Although the device works in Windows 7 (x64), the app "USB device tree viewer" complains about reading the HID descriptors (ERROR_GEN_FAILURE, see attached report). Windows 10 refuses to enumerate the device, reporting a "Error requesting a device description" (description may be descriptor, had to translate it to English). I suspect the HID report descriptors to have errors, but I wonder if someone could give me a hint.

 

Thank you for reading,

Paule


//
// USB Device Descriptor.
//
// For information about device class, device subclass and device protocol, see:
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff537109(v=vs.85).aspx
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff540054(v=vs.85).aspx
//
__attribute__((__aligned__(2))) struct USB_DeviceDesc udc_device_desc = {
	.bLength                   = sizeof(struct USB_DeviceDesc),
	.bDescriptorType           = USB_DT_DEVICE,
	.bcdUSB                    = USB_V2_0,
	.bDeviceClass              = 0xEF,
	.bDeviceSubClass           = 0x02,
	.bDeviceProtocol           = 0x01,
	.bMaxPacketSize0           = 64,
	.idVendor                  = USB_VID_ATMEL,							/* vendor ID */
	.idProduct                 = USB_PID_ATMEL_ASF_VENDOR_CLASS,		/* product ID */
	.bcdDevice                 = (1 << 8) | 0,							/* major / minor version */
	.iManufacturer             = 1,
	.iProduct                  = 2,
	.iSerialNumber             = 0,
	.bNumConfigurations        = 1
};

/**
 * USB Device Configuration Descriptor for Full Speed.
 */
__attribute__((__aligned__(2))) struct UDC_Desc udc_desc = {
	.confDesc.bLength              = sizeof(struct USB_ConfDesc),
	.confDesc.bDescriptorType      = USB_DT_CONFIGURATION,
	.confDesc.wTotalLength         = sizeof(struct UDC_Desc),
	.confDesc.bNumInterfaces       = USB_DEVICE_NB_INTERFACE,
	.confDesc.bConfigurationValue  = 1,
	.confDesc.iConfiguration       = 0,												/* no string describing this configuration */
	.confDesc.bmAttributes         = USB_CONFIG_ATTR_MUST_SET | USB_CONFIG_ATTR_BUS_POWERED,
	.confDesc.bMaxPower            = USB_CONFIG_MAX_POWER(100),						/* max. consumption of power [mA] */
 	/* HID keyboard (interface #2). Contains single endpoint (INTERRUPT IN, #3) to send HID keyboard reports from device to host. */
	.hidKbdDesc                 =  {
		.iface.bLength             = sizeof(struct USB_InterfaceDesc),
		.iface.bDescriptorType     = USB_DT_INTERFACE,
		.iface.bInterfaceNumber    = 0,
		.iface.bAlternateSetting   = 0,
		.iface.bNumEndpoints       = 1,
		.iface.bInterfaceClass     = HID_CLASS,
		.iface.bInterfaceSubClass  = HID_SUB_CLASS_NOBOOT,
		.iface.bInterfaceProtocol  = HID_PROTOCOL_KEYBOARD,
		.iface.iInterface          = 0,
		.hid.bLength               = sizeof(struct USB_HidDescriptor),
		.hid.bDescriptorType       = USB_DT_HID,
		.hid.bcdHID                = USB_HID_BDC_V1_11,
		.hid.bCountryCode          = USB_HID_NO_COUNTRY_CODE,
		.hid.bNumDescriptors       = USB_HID_NUM_DESC,
		.hid.bRDescriptorType      = USB_DT_HID_REPORT,
		.hid.wDescriptorLength     = sizeof(struct USB_HidKbdReportDesc),
		.ep.bLength                = sizeof(struct USB_EpDesc),
		.ep.bDescriptorType        = USB_DT_ENDPOINT,
		.ep.bEndpointAddress       = ( 1 | USB_EP_DIR_IN),
		.ep.bmAttributes           = USB_EP_TYPE_INTERRUPT,
		.ep.wMaxPacketSize         = 8,
		.ep.bInterval              = 2,
	},
  	/* Generic HID device (interface #3). Contains two endpoints (INTERRUPT IN, #4 and INTERRUPT OUT, #5) to transfer data between device and host.  */
	.hidGenDesc			   = {
		.iface.bLength             = sizeof(struct USB_InterfaceDesc),
		.iface.bDescriptorType     = USB_DT_INTERFACE,
		.iface.bInterfaceNumber    = 1,
		.iface.bAlternateSetting   = 0,
		.iface.bNumEndpoints       = 2,
		.iface.bInterfaceClass     = HID_CLASS,
		.iface.bInterfaceSubClass  = HID_SUB_CLASS_NOBOOT,
		.iface.bInterfaceProtocol  = HID_PROTOCOL_GENERIC,
		.iface.iInterface          = 0,
		.hid.bLength               = sizeof(struct USB_HidDescriptor),
		.hid.bDescriptorType       = USB_DT_HID,
		.hid.bcdHID                = USB_HID_BDC_V1_11,
		.hid.bCountryCode          = USB_HID_NO_COUNTRY_CODE,
		.hid.bNumDescriptors       = USB_HID_NUM_DESC,
		.hid.bRDescriptorType      = USB_DT_HID_REPORT,
		.hid.wDescriptorLength     = sizeof(struct HIDGEN_ReportDesc),
		.ep_in.bLength             = sizeof(struct USB_EpDesc),
		.ep_in.bDescriptorType     = USB_DT_ENDPOINT,
		.ep_in.bEndpointAddress    = ( 2 | USB_EP_DIR_IN),
		.ep_in.bmAttributes        = USB_EP_TYPE_INTERRUPT,
		.ep_in.wMaxPacketSize      = 32,
		.ep_in.bInterval           = 1,
		.ep_out.bLength            = sizeof(struct USB_EpDesc),
		.ep_out.bDescriptorType    = USB_DT_ENDPOINT,
		.ep_out.bEndpointAddress   = ( 3 | USB_EP_DIR_OUT),
		.ep_out.bmAttributes       = USB_EP_TYPE_INTERRUPT,
		.ep_out.wMaxPacketSize     = 32,
		.ep_out.bInterval          = 1,
	}
};

/** Report descriptor for standard HID generic. */
struct HIDGEN_ReportDesc HIDGEN_reportDesc = {
	{
		0x06, 0xFF, 0xFF,	// 04|2   , Usage Page (vendor defined?)
		0x09, 0x01,	// 08|1   , Usage      (vendor defined)
		0xA1, 0x01,	// A0|1   , Collection (Application)
		/* IN report */
			0x09, 0x02,	// 08|1   , Usage      (vendor defined)
			0x09, 0x03,	// 08|1   , Usage      (vendor defined)
			0x15, 0x00,	// 14|1   , Logical Minimum(0 for signed byte?)
			0x26, 0xFF, 0x00,	// 24|1   , Logical Maximum(255 for signed byte?)
			0x75, 0x08,	// 74|1   , Report Size(8) = field size in bits = 1 byte
			0x95, 32,	// 94|1   , ReportCount(size) = repeat count of previous item
			0x81, 0x02,	// 80|1   , IN report (Data,Variable, Absolute)
		/* OUT report */
			0x09, 0x04,	// 08|1   , Usage      (vendor defined)
			0x09, 0x05,	// 08|1   , Usage      (vendor defined)
			0x15, 0x00,	// 14|1   , Logical Minimum(0 for signed byte?)
			0x26, 0xFF, 0x00,	// 24|1   , Logical Maximum(255 for signed byte?)
			0x75, 0x08,	// 74|1   , Report Size(8) = field size in bits = 1 byte
			0x95, 32,	// 94|1   , ReportCount(size) = repeat count of previous item
			0x91, 0x02,	// 90|1   , OUT report (Data,Variable, Absolute)
		0xC0	// C0|0   , End Collection
	}
};

/**
 * Report descriptor for standard HID keyboard.
 * This is not part of the main descriptor, but will instead be send to host on request.
 */
struct USB_HidKbdReportDesc udi_hid_kbd_report_desc = {
	{
		0x05, 0x01,	/* Usage Page (Generic Desktop)      */
		0x09, 0x06,	/* Usage (Keyboard)                  */
		0xA1, 0x01,	/* Collection (Application)          */
			0x05, 0x07,	/* Usage Page (Keyboard)             */
			0x19, 0x00,	/* Usage Minimum (0)                 */
			0x29, 0x65,	/* Usage Maximum (101)               */
			0x15, 0x00,	/* Logical Minimum (0)               */
			0x25, 0x65,	/* Logical Maximum (101)             */
			0x75, 0x08,	/* Report Size (8)                   */
			0x95, 0x08,	/* Report Count (8)                  */
			0x81, 0x00,	/* Input (Data, Array)               */
		0xC0	/* End Collection						 */
	}
};

 


 

USB device tree viewer report

=========================== USB Port8 ===========================

Connection Status        : 0x01 (Device is connected)
Port Chain               : 1-1-8

      ======================== USB Device ========================

        +++++++++++++++++ Device Information ++++++++++++++++++
Device Description       : USB-Verbundgerät
Device Path              : \\?\usb#vid_03eb&pid_2423#6&3c8adf&0&8#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
Device ID                : USB\VID_03EB&PID_2423\6&3C8ADF&0&8
Hardware IDs             : USB\VID_03EB&PID_2423&REV_0100 USB\VID_03EB&PID_2423
Driver KeyName           : {36fc9e60-c465-11cf-8056-444553540000}\0292 (GUID_DEVCLASS_USB)
Driver                   : C:\Windows\system32\DRIVERS\usbccgp.sys (Version: 6.1.7601.18328  Date: 2013-11-27)
Driver Inf               : C:\Windows\inf\usb.inf
Legacy BusType           : PNPBus
Class                    : USB
Class GUID               : {36fc9e60-c465-11cf-8056-444553540000} (GUID_DEVCLASS_USB)
Interface GUID           : {a5dcbf10-6530-11d2-901f-00c04fb951ed} (GUID_DEVINTERFACE_USB_DEVICE)
Service                  : usbccgp
Enumerator               : USB
Location Info            : Port_#0008.Hub_#0003
Location IDs             : PCIROOT(0)#PCI(1D00)#USBROOT(0)#USB(1)#USB(8)
Container ID             : {8c8f9dd6-c5d7-11e7-952e-005056c00008}
Manufacturer Info        : (Standard-USB-Hostcontroller)
Capabilities             : 0x84 (Removable, SurpriseRemovalOK)
Status                   : 0x0180400A (DN_DRIVER_LOADED, DN_STARTED, DN_REMOVABLE, DN_NT_ENUMERATOR, DN_NT_DRIVER)
Problem Code             : 0
Address                  : 8
Power State              : D0 (supported: D0, D3, wake from D0)
 Child Device 1          : USB-Eingabegerät
  Device ID              : USB\VID_03EB&PID_2423&MI_01\7&2C59C785&0&0001
  Class                  : HIDClass
   Child Device 1        : HID-konformes Gerät
    Device ID            : HID\VID_03EB&PID_2423&MI_01\8&37057D7E&0&0000
    Class                : HIDClass
 Child Device 2          : USB-Eingabegerät
  Device ID              : USB\VID_03EB&PID_2423&MI_00\7&2C59C785&0&0000
  Class                  : HIDClass
   Child Device 1        : HID-Tastatur
    Device ID            : HID\VID_03EB&PID_2423&MI_00\8&2DEDB0B2&0&0000
    Class                : Keyboard

        ---------------- Connection Information ---------------
Connection Index         : 0x08 (8)
Connection Status        : 0x01 (DeviceConnected)
Current Config Value     : 0x01
Device Address           : 0x03 (3)
Is Hub                   : 0x00 (no)
Number Of Open Pipes     : 0x03 (3)
Device Bus Speed         : 0x01 (Full-Speed)
Pipe0ScheduleOffset      : 0x00 (0)
Pipe1ScheduleOffset      : 0x00 (0)
Pipe2ScheduleOffset      : 0x00 (0)

      -------------------- Device Descriptor --------------------
bLength                  : 0x12 (18 bytes)
bDescriptorType          : 0x01 (Device Descriptor)
bcdUSB                   : 0x200 (USB Version 2.00)
bDeviceClass             : 0xEF (Miscellaneous)
bDeviceSubClass          : 0x02
bDeviceProtocol          : 0x01 (IAD)
bMaxPacketSize0          : 0x40 (64 bytes)
idVendor                 : 0x03EB
idProduct                : 0x2423
bcdDevice                : 0x0100
iManufacturer            : 0x01 (String Descriptor 1)
 Language 0x0409         : "Atmel"
iProduct                 : 0x02 (String Descriptor 2)
 Language 0x0409         : "HID Keyboard"
iSerialNumber            : 0x00 (No String Descriptor)
bNumConfigurations       : 0x01

    ------------------ Configuration Descriptor -------------------
bLength                  : 0x09 (9 bytes)
bDescriptorType          : 0x02 (Configuration Descriptor)
wTotalLength             : 0x0042 (66 bytes)
bNumInterfaces           : 0x02
bConfigurationValue      : 0x01
iConfiguration           : 0x00 (No String Descriptor)
bmAttributes             : 0x80
 D7: Reserved, set 1     : 0x01
 D6: Self Powered        : 0x00 (no)
 D5: Remote Wakeup       : 0x00 (no)
 D4..0: Reserved, set 0  : 0x00
MaxPower                 : 0x32 (100 mA)

        ---------------- Interface Descriptor -----------------
bLength                  : 0x09 (9 bytes)
bDescriptorType          : 0x04 (Interface Descriptor)
bInterfaceNumber         : 0x00
bAlternateSetting        : 0x00
bNumEndpoints            : 0x01 (1 Endpoint)
bInterfaceClass          : 0x03 (HID - Human Interface Device)
bInterfaceSubClass       : 0x00 (None)
bInterfaceProtocol       : 0x01 (Keyboard)
iInterface               : 0x00 (No String Descriptor)

        ------------------- HID Descriptor --------------------
bLength                  : 0x09 (9 bytes)
bDescriptorType          : 0x21 (HID Descriptor)
bcdHID                   : 0x0111 (HID Version 1.11)
bCountryCode             : 0x00 (00 = not localized)
bNumDescriptors          : 0x01
Descriptor 1:
bDescriptorType          : 0x22 (Class=Report)
wDescriptorLength        : 0x0017 (23 bytes)
Error reading descriptor : ERROR_GEN_FAILURE

        ----------------- Endpoint Descriptor -----------------
bLength                  : 0x07 (7 bytes)
bDescriptorType          : 0x05 (Endpoint Descriptor)
bEndpointAddress         : 0x81 (Direction=IN EndpointID=1)
bmAttributes             : 0x03 (TransferType=Interrupt)
wMaxPacketSize           : 0x0008 (8 bytes)
bInterval                : 0x02 (2 ms)

        ---------------- Interface Descriptor -----------------
bLength                  : 0x09 (9 bytes)
bDescriptorType          : 0x04 (Interface Descriptor)
bInterfaceNumber         : 0x01
bAlternateSetting        : 0x00
bNumEndpoints            : 0x02 (2 Endpoints)
bInterfaceClass          : 0x03 (HID - Human Interface Device)
bInterfaceSubClass       : 0x00 (None)
bInterfaceProtocol       : 0x00 (None)
iInterface               : 0x00 (No String Descriptor)

        ------------------- HID Descriptor --------------------
bLength                  : 0x09 (9 bytes)
bDescriptorType          : 0x21 (HID Descriptor)
bcdHID                   : 0x0111 (HID Version 1.11)
bCountryCode             : 0x00 (00 = not localized)
bNumDescriptors          : 0x01
Descriptor 1:
bDescriptorType          : 0x22 (Class=Report)
wDescriptorLength        : 0x0026 (38 bytes)
Error reading descriptor : ERROR_GEN_FAILURE

        ----------------- Endpoint Descriptor -----------------
bLength                  : 0x07 (7 bytes)
bDescriptorType          : 0x05 (Endpoint Descriptor)
bEndpointAddress         : 0x82 (Direction=IN EndpointID=2)
bmAttributes             : 0x03 (TransferType=Interrupt)
wMaxPacketSize           : 0x0020 (32 bytes)
bInterval                : 0x01 (1 ms)

        ----------------- Endpoint Descriptor -----------------
bLength                  : 0x07 (7 bytes)
bDescriptorType          : 0x05 (Endpoint Descriptor)
bEndpointAddress         : 0x03 (Direction=OUT EndpointID=3)
bmAttributes             : 0x03 (TransferType=Interrupt)
wMaxPacketSize           : 0x0020 (32 bytes)
bInterval                : 0x01 (1 ms)

      -------------------- String Descriptors -------------------
             ------ String Descriptor 0 ------
bLength                  : 0x04 (4 bytes)
bDescriptorType          : 0x03 (String Descriptor)
Language ID[0]           : 0x0409 (English - United States)
             ------ String Descriptor 1 ------
bLength                  : 0x0C (12 bytes)
bDescriptorType          : 0x03 (String Descriptor)
Language 0x0409          : "Atmel"
             ------ String Descriptor 2 ------
bLength                  : 0x1A (26 bytes)
bDescriptorType          : 0x03 (String Descriptor)
Language 0x0409          : "HID Keyboard"

 

Workaround: It seems clock initialization took too long for USB. Switching back to 32 MHz internal RC with PLL (-> 30 MHz CPU clock) did it for me. Although this is slower than using PLL and 2 MHz internal clock, it works everytime.

Last Edited: Sun. Dec 3, 2017 - 02:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The following three lines in USB device descriptor make no sense and have been changed to 0's:

.bDeviceClass = 0xEF,
.bDeviceSubClass = 0x02,
.bDeviceProtocol = 0x01,

They point to a Interface Associate Descriptor (IAD), which is neither present in the descriptor, nor required when doing a composite HID device. I accidentally copied those lines after doing a HID + CDC example.

Still having trouble with the device sometimes not being recognized on attachment.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Failure to recognize on attachment is often because you are not starting up fast enough. I've noticed that USB 3.0 ports are particularly sensitive to this.

 

Slow rising power supply, slow starting oscillator etc.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mojo-chan wrote:

Slow rising power supply, slow starting oscillator etc.

Can you please add more detail to this?

What is the start-up time? The time between attaching the device physically (it is bus-powered) and the time udd_enable() is called?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Pretty much. You can also have issues if you have a lot of other interrupts that delay the USB ones.

 

One day to check is to try different computers. If some are better than others then it's a strong hint that something, probably timing, is marginal.

 

Also note that your MCU supply voltage needs to be at least 3.0V to be reliable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for reply, mojo-chan.

I already set the brown-out detection to delay the start until 3 V are present. It seems it nearly always works on Win7 machines, but only sometimes on Windows 10. Probably USB CV test is my next goal.
I als wonder if setting the STARTUPTIME in fuse bits will make the problem worse (longer start-up time) or go away (more stable system).

EDIT: The USB interrupt is basically the only one used. I also attached the device directly to the host to prevent a broken-cable-problem.

Last Edited: Fri. Dec 1, 2017 - 08:26 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

3.0 is a bit high for the BOD, assuming your supply voltage is 3.3 or 3.6V. I'd try 2.7 or even a bit lower.

 

Basically BOD is there to save you from catastrophe like flash memory corruption. There is some hysteresis too, so if you set it at 3.0V and your supply is only 3.3V it is going to take a while to come out of reset.

 

Try it and see if it helps.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Status: workaround / solution found!

 

What works:
The Atmel example projects used internal 32 MHz RC to generate 48 MHz USB and therefore forced CPU clock to be a maximum of 24 MHz (48 MHz is out of spec for XMega, although it may work). Beside using 24 MHz CPU clock (code block #2), using 30 MHz CPU clock by PLL (48 MHz / 4 / 4 * 10) is also possible (code block #3).

 

What does not work:
Beside 32 MHz RC, I enabled 2 MHz clock and used PLL to multiply it to 32 MHz CPU clock. I either did it wrong, or it takes too long to initialize. See clock init code below (block #1).

 

Code for non-working 32 MHz CPU clock:

/* turn off all peripheral clocks */
uint8_t *reg = (uint8_t *) &PR.PRGEN;		// TODO: nicht alle Register ausschalten?
for (uint8_t i = 0; i <= 6; i++) {
	*(reg++) = 0xff;
}

/* if device has uncalibrated value in the production signature row (early sample part), load sane default calibration value */
uint16_t cal;
MSB(cal) = NVM_readByte(NVM_CMD_READ_CALIB_ROW_gc, offsetof(NVM_PROD_SIGNATURES_t, USBRCOSC));
LSB(cal) = NVM_readByte(NVM_CMD_READ_CALIB_ROW_gc, offsetof(NVM_PROD_SIGNATURES_t, USBRCOSCA));
if (cal == 0xFFFF) {
	cal = 0x2340;
}
DFLLRC32M.CALA = LSB(cal);
DFLLRC32M.CALB = MSB(cal);

/* switch to the initial system clock source (PLL from 2 MHz) */
if (!(OSC.STATUS & OSC_PLLRDY_bm)) {
	OSC.PLLCTRL		= OSC_PLLSRC_RC2M_gc | (16 << OSC_PLLFAC_gp);			/* multiplier = 16, divider = 1 */
	OSC.CTRL		|= OSC_PLLEN_bm;
	while (!(OSC.STATUS & OSC_PLLRDY_bm));
}
CCP_writeIo((uint8_t *)&CLK.CTRL, CLK_SCLKSEL_PLL_gc);

/* enable 32 kHz RC */
uint8_t flags	= INTERRUPT_save();
OSC.CTRL		|= OSC_RC32KEN_bm;
while (!(OSC.STATUS & OSC_RC32KEN_bm)) {
	/* Do nothing */
}
INTERRUPT_restore(flags);

/* enable auto-calibration of 2 MHz RC by 32 kHz RC */
flags			= INTERRUPT_save();
OSC.DFLLCTRL	&= ~(OSC_RC2MCREF_bm);
DFLLRC2M.CTRL	|= DFLL_ENABLE_bm;
INTERRUPT_restore(flags);

Code for working 24 MHz CPU clock:

/* Turn off all peripheral clocks that can be turned off. */
uint8_t * reg = (uint8_t *)&PR.PRGEN;
for (uint8_t i = 0; i <= 6; i++) {
	*(reg++) = 0xff;
}

/* setup system clock prescalers (48 MHz divided by 2 = 24 MHz) */
CCP_writeIo((uint8_t *) &CLK.PSCTRL, CLK_PSADIV_1_gc | CLK_PSBCDIV_1_2_gc);

/* load USB oscillator calibration */
uint16_t cal;
(((uint8_t *) &cal)[1]) = NVM_readByte(NVM_CMD_READ_CALIB_ROW_gc, offsetof(NVM_PROD_SIGNATURES_t, USBRCOSC));
(((uint8_t *) &cal)[0]) = NVM_readByte(NVM_CMD_READ_CALIB_ROW_gc, offsetof(NVM_PROD_SIGNATURES_t, USBRCOSCA));
/* if device has uncalibrated value in the production signature row (early sample part), load a sane default calibration value. */
if (cal == 0xFFFF) {
	cal = 0x2340;
}

DFLLRC32M.CALA = (((uint8_t *) &cal)[0]);
DFLLRC32M.CALB = (((uint8_t *) &cal)[1]);

/* Switch to the selected initial system clock source, unless the default internal 2 MHz oscillator is selected. */
uint8_t flags	= INTERRUPT_save();
OSC.CTRL		|= OSC_RC32MEN_bm;
INTERRUPT_restore(flags);
while (!(OSC.STATUS & OSC_RC32MEN_bm)) {
	/* Do nothing */
}

/* enable auto-calibration of 32 MHz RC by USB SOF */
flags			= INTERRUPT_save();
OSC.DFLLCTRL	&= ~(OSC_RC32MCREF_gm);
/* 48MHz / 1kHz = 0xBB80 */
DFLLRC32M.COMP1 = 0x80;
DFLLRC32M.COMP2 = 0xBB;
OSC.DFLLCTRL	|= OSC_RC32MCREF_USBSOF_gc;
DFLLRC32M.CTRL	|= DFLL_ENABLE_bm;
INTERRUPT_restore(flags);

CCP_writeIo((uint8_t *)&CLK.CTRL, CLK_SCLKSEL_RC32M_gc);

flags = INTERRUPT_save();
OSC.CTRL &= ~OSC_RC2MEN_bm;
INTERRUPT_restore(flags);

 

Code for 30 MHz CPU clock (works!):

/* setup system clock prescalers (48 MHz divided by 4 = 12 MHz) */
CCP_writeIo((uint8_t *) &CLK.PSCTRL, CLK_PSADIV_1_gc | CLK_PSBCDIV_2_2_gc);

/* load USB oscillator calibration */
uint16_t cal;
(((uint8_t *) &cal)[1]) = NVM_readByte(NVM_CMD_READ_CALIB_ROW_gc, offsetof(NVM_PROD_SIGNATURES_t, USBRCOSC));
(((uint8_t *) &cal)[0]) = NVM_readByte(NVM_CMD_READ_CALIB_ROW_gc, offsetof(NVM_PROD_SIGNATURES_t, USBRCOSCA));
/* if device has uncalibrated value in the production signature row (early sample part), load a sane default calibration value. */
if (cal == 0xFFFF) {
	cal = 0x2340;
}

DFLLRC32M.CALA = (((uint8_t *) &cal)[0]);
DFLLRC32M.CALB = (((uint8_t *) &cal)[1]);

/* Switch to the selected initial system clock source, unless the default internal 2 MHz oscillator is selected. */
uint8_t flags	= INTERRUPT_save();
OSC.CTRL		|= OSC_RC32MEN_bm;
INTERRUPT_restore(flags);
while (!(OSC.STATUS & OSC_RC32MEN_bm)) {
	/* Do nothing */
}

/* enable auto-calibration of 32 MHz RC by USB SOF */
flags			= INTERRUPT_save();
OSC.DFLLCTRL	&= ~(OSC_RC32MCREF_gm);
/* 48MHz / 1kHz = 0xBB80 */
DFLLRC32M.COMP1 = 0x80;
DFLLRC32M.COMP2 = 0xBB;
OSC.DFLLCTRL	|= OSC_RC32MCREF_USBSOF_gc;
DFLLRC32M.CTRL	|= DFLL_ENABLE_bm;
INTERRUPT_restore(flags);

CCP_writeIo((uint8_t *)&CLK.CTRL, CLK_SCLKSEL_RC32M_gc);

flags = INTERRUPT_save();
OSC.CTRL &= ~OSC_RC2MEN_bm;
INTERRUPT_restore(flags);

/* switch to the initial system clock source (PLL from 12 MHz) */
if (!(OSC.STATUS & OSC_PLLRDY_bm)) {
	OSC.PLLCTRL		= OSC_PLLSRC_RC32M_gc | (10 << OSC_PLLFAC_gp);		/* multiplier = 10, divider = 4 (implicitly done when using internal 32 MHz RC) */
	OSC.CTRL		|= OSC_PLLEN_bm;
	while (!(OSC.STATUS & OSC_PLLRDY_bm));
}
CCP_writeIo((uint8_t *)&CLK.CTRL, CLK_SCLKSEL_PLL_gc);

 

Thank you, mojo-chan!

 

Last Edited: Sun. Dec 3, 2017 - 02:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I see you use DFLL for the 2MHz oscillator in block 1. Can you actually do that with USB using the 32MHz RC oscillator? I think you have to assign DFLL to that and thus can't use it for anything else, but I could be wrong.