Other Parts Discussed in Thread: SYSCONFIG
Back in February I asked about "Implementing other USB device classes," and I went down a rabbit hole and sorta got lost in it all and put it aside as other pressing work demanded attention.
I just got back onto this. I did a survey of other processors that could do what I wanted -- USB High Speed support, 100 Mbit Ethernet and an external bus interface. Tiva M4 ticks all of the boxes, so I started digging back in.
I chose the USB MIDI class for two reasons. One, it's simple. Two, I need it for a design. So it makes sense to use it as a demonstration of how to implement USB device classes not supported by TivaWare. That USB MIDI is supported by all of the major operating systems means no custom host drivers, unlike the TivaWave USB Bulk demo.
I started basically from scratch. I updated to CCS 10 and TivaWave 2.2. I used the PinMux tool (now SysConfig) to generate the pinout file. I added the device driver library and the USB library to my project. I put the class device descriptors into the format that the TivaWare USB Library wants. (I developed the descriptors for a Silicon Labs EFM8UB2, so I know they are correct as that design is working.)
I used the usbdbulk device driver as a guide, but got rid of the stuff that is meant to support a composite device (that is, two instances of the same device class). For starters my goal was to just get the device to enumerate, with data transfer on the bulk endpoints to follow, so the handlers set up in tCustomHandlers are just stubs. The USB0DeviceIntHandler is put into the startup source in the correct place. All of the structures for the device information get set up as in the examples, and I call USBDCDInit().
And then nothing happened. There is no attempt at enumeration -- no USB traffic at all according to my analyzer.
Stepping through the code doesn't help as you can't step through the compiled library. So I deleted the library reference from the linker options and pulled all of the sources into the project. That compiles, now I can step through. And I see that it's doing what I expect, and even gets to "attach the device using the soft connect" and "enable the USB interrupt." Nothing happens after that connect.
But! "enable the USB interrupt." Is the interrupt even being triggered? And the answer is ... NO. Why the heck not? It's enabled. Global interrupts are enabled. The bulk example works, but mine does not. What is different? I start stepping through the bulk example, I get into the PinoutSet() function. Since bool bUSB is true, it initializes the USB-related pins. I checked my code to see what SysConfig created in pinout.c.
In SysConfig I enabled the USB peripheral, and checked the DM, DP, VBUS and EPEN signals. This results in a pinout.c that calls GPIOPinType for each of those pins.
Back in the USB bulk example's pinout, I see the same calls for the pins, except there's an addition:
HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; HWREG(GPIO_PORTD_BASE + GPIO_O_CR) = 0xff; MAP_GPIOPinConfigure(GPIO_PD6_USB0EPEN);
OK, what the heck is GPIO_LOCK_KEY? And what does this have to do with pin PD6?
Whatever -- I add that snippet to my code and voila -- enumeration as a USB MIDI device. I seem to be up and running.
The data sheet tells us that USB0EPEN can be assigned to pin PD6 and is "optionally used in Host mode to control an external power source to supply power to the USB bus." I'm a device, so who cares. But what is the lock all about?
-
10.3.4 Commit Control
The GPIO commit control registers provide a layer of protection against accidental programming of critical hardware peripherals. Protection is provided for the GPIO pins that can be used as the four JTAG/SWD pins and the NMI pin (see “Signal Tables” on page 1772 for pin numbers). Writes to protected bits of the GPIO Alternate Function Select (GPIOAFSEL) register (see page 770), GPIO Pull Up Select (GPIOPUR) register (see page 776), GPIO Pull-Down Select (GPIOPDR) register (see page 778), and GPIO Digital Enable (GPIODEN) register (see page 781) are not committed to storage unless the GPIO Lock (GPIOLOCK) register (see page 783) has been unlocked and the appropriate bits of the GPIO Commit (GPIOCR) register (see page 784) have been set.
None of this has to do with JTAG/SWD or NMI -- so is this lock requirement something particular to the eval kit board or is it generally required?