USB CDC Device on a K22FN1M0VLH12 - Device Cannot Start

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

USB CDC Device on a K22FN1M0VLH12 - Device Cannot Start

Jump to solution
3,410 Views
weblar
Contributor V

Hi,

I've taken the K21 USB CDC example from the Freescale USB stack 4.11 and I've customized it to fit my K22 (not much needed changing to be honest).

When the application started, I was prompted to install the drive which Freescale kindly supplied with the aforementioned example code.

Unfortunately, I now always get a "device cannot start" error in device manager against the "Virtual Com Port" device and I can't for the life of me figure out what's going on. The USB_ISR interrupt seems to trigger correctly - my only thought would be as to whether I have correctly configured the clocking for the USB peripheral. I have an 8MHz crystal as the source with the device running at 120MHz, the following code is how I've configured the USB peripheral...

void usb_init(void) {

  // 2 / 5 * 120MHz = 48MHz

  SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(4) | SIM_CLKDIV2_USBFRAC_MASK;

  // Clock the USB from the PLL

  SIM->SOPT2 |= SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK;

  // Enable USB OTG module clock

  SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK;

  USB0->USBTRC0 = 0x40;

  // Allow the USBREGEN bit in SOPT1 to be changed

  //SIM->SOPT1CFG |= SIM_SOPT1CFG_URWE_MASK;

  // Enable the USB regulator

  SIM->SOPT1 |= SIM_SOPT1_USBREGEN_MASK;

  // Clear any pending USB interrupts

  nvic_clear_irq(INT_USB0);

  // Enable the USB interrupt

  nvic_enable_irq(INT_USB0);

}

For reference, here is my mcg init code...

void mcg_init(void) {


  // Select the internal load capacitors for a capacitance of about 18pF

  OSC0->CR = (uint8_t)(OSC_CR_SC2P_MASK | OSC_CR_SC16P_MASK);

  // Enable the 8MHz crystal

  MCG->C2 = (uint8_t)(MCG_C2_EREFS0_MASK | MCG_C2_RANGE0(2));

  // Select the external oscillator and set the FLL reference divider

  MCG->C1 = (uint8_t)(MCG_C1_CLKS(2) | MCG_C1_FRDIV(3));

  // Wait for the oscillator to initialize

  while (!(MCG->S & MCG_S_OSCINIT0_MASK)) { }

  // Wait for the reference clock to switch to the external reference

  while (MCG->S & MCG_S_IREFST_MASK) { }

  // Wait for MCGOUTCLK to switch over to the external reference clock

  while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) { }

  // Divide by 2 for a PLL0 frequency of 4MHz

  MCG->C5 = (uint8_t)(MCG_C5_PRDIV0(1));

  // PLL0 - Multiply by 30 to give 120MHz

  MCG->C6 = (uint8_t)(MCG_C6_CME0_MASK | MCG_C6_PLLS_MASK | MCG_C6_VDIV0(6));

  // Wait for the PLLST bit to be set, when PLLCS has obtained a lock

  while (!(MCG->S & MCG_S_PLLST_MASK)) { }


  // Wait for PLL0 to lock

  while (!(MCG->S & MCG_S_LOCK0_MASK)) { }


  // Set the clocks to the following:

  // CORE_CLK = 120MHz (0 = div 1)

  // BUS_CLK = 60MHz (1 = div 2)

  // FLEXBUS_CLK = 40MHz (3 = div 4)

  // FLASH_CLK = 20MHz (5 = div 6)

  SIM->CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV3(3) | SIM_CLKDIV1_OUTDIV4(5);


  //MCG_C1 &= ~MCG_C1_CLKS_MASK;

  MCG->C1 = (uint8_t)(MCG_C1_CLKS(0) | MCG_C1_FRDIV(3));


  while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) { }

  MPU->CESR = 0x00;

}

As far as I'm aware, this is all correct as per the K21 example - apart from my device running up at 120MHz.

I'd be grateful if anyone could provide any hints or tips as to what may be the cause.

Thanks in advance,

Kevin

Tags (2)
0 Kudos
1 Solution
2,017 Views
mjbcswitzerland
Specialist V

Hi Kevin

I didn't have problems with the .bin file that I tested in the TWR-K21F120 but maybe there was something in there still that the K22 doesn't like (?) I found that ADC1 was being sampled at 8kHz and passed to DAC0 using DMA (after 1 second delay) so I have disabled this in the attached version (although both devices have ADC1 and DAC0 so I wouldn't expect this to affect operation).

However I have loaded your bin to my board and have some results:

- After installing the driver (using fsl_ucwxp.inf) I get the same error message that you have

- The basic problem is that the enumeration doesn't work fully. It works enough for the driver to be installed but fails when the host requests the Configuration descriptor from the device.

The configuration descriptor informs the host about the interface (that it is a communication control class, its power consumption, the endpoints that are used and the requiremenst of these endpoints). Most of the data content is correct but the overall data is malformed. There is one not-quite-right setting where the device says that it is self-powered but still needs 100mA, but this doesn't cause the failure. The failure actually comes from the fact that the data returned is an incorrect length - there are 198 extra zeroes sent back and the host presumably rejects it due to this.

I took a quick look at the Freescale USB Stack v4.1.1 and have the feeling that the define for the length of the data is incorrect.

It is defined as

uint_8 USB_DESC_CONST g_config_descriptor[CONFIG_DESC_SIZE] =

and there are various sources for the define CONFIG_DESC_SIZE, whereby it looks like the following may be used

#define CONFIG_DESC_SIZE              (CONFIG_ONLY_DESC_SIZE + 28 +   \
                                      (CIC_NOTIF_ELEM_SUPPORT & 0x01) \
                                      * 7 + DATA_CLASS_SUPPORT * 23)

Possibly you have used some configuration/project setting that breaks the code because I don't think that there is any compiler dependency involved.

I would try removing the length from the definition of the g_config_descriptor[] because it is not needed. I would also ensure that any code using g_config_descriptor[] works with the array length and not the CONFIG_DESC_SIZE.

Eg. a routine sending this descriptor would better use a pointer to g_config_descriptor and sizeof(g_config_descriptor) and not a pointer to g_config_descriptor and CONFIG_DESC_SIZE.

I expect that the CDC driver essentially works but I see that there are a handful of devices supported, each with its own set of project files and some local defines. Probably the code based on the define is "difficult to maintain" code since it may need to be right in all device types/configurations. It may work in one but not work in another because it hasn't been tested or corrections were not made at all locations where neeed. As noted above I don't see any need for this critical define value since the array size should take care of itself.

Regards

Mark

P.S. Such errors are not easy to identify without a HW analyser and I recomment investing in one if working with USB based projects.

View solution in original post

0 Kudos
21 Replies
1,956 Views
weblar
Contributor V

For reference, I'm running Windows 7 on an AMD64 bit processor - whether this is a driver related issue, I'm not sure.

0 Kudos
1,956 Views
weblar
Contributor V

I've since downloaded the Microsoft Message Analyzer tool to try and help diagnose whats going on. To be honest, I don't really know what I'm looking for but as far as I can see, everything appears to be normal - no errors are highlighted.

Here is a screenshot of the message trace.

trace.png

I guess the next thing to do is to compare it to another USB to serial device, such as an FTDI board I have.


Hmmm....

0 Kudos
1,956 Views
weblar
Contributor V

So technically, I'm not comparing apples to apples but I think the test is good enough. Here's a capture of the FTDI trace and there's a lot more stuff going on.

trace2.png

For a start there is an "Internal URB_FUNCTION_CONTROL_TRANSFER" which happens immediately after the "URB_FUNCTION_SELECTION_CONFIGURATION" which happens to be the last message in my non-working trace.

Could this then be an issue with the Freescale USB stack? Anyone from Freescale able to help with this?

Kind regards,

Kevin

0 Kudos
1,956 Views
mjbcswitzerland
Specialist V

Kevin

I don't know how to interpret the message analyzer outputs - also FTDI is probably using a different driver to the standard inbuilt one (usbser.sys).

Attached is an application using USB-CDC on the K21F120 - since the USB-MSD operates on your board this should do also (it doesn't use any other peripherals). There are .bin and .srec version plus  uTaskerFreescaleVirtualCOM.inf and uTaskerFreescaleVirtualCOM_64bit.inf which will be needed so that Windows can install the driver (probably you need the 64 bit one). This uses usbser.sys (standard one available in Windows). When connected to the interface there will be a command line menu with various possibilities and all debug output is sent there.

To clear up the basic issue faster it may be best if you send me your own bin or srec file so that I can load it to the TWR K21F120 board - with my USB analysers I can quickly see if and where there is a problem. HW analysers see much more that the SW ones, which I never found of much use unless you have a fully working system and need to just check up on application layer messages.

Regards

Mark

Note also that you can download the uTasker project at KINETIS Project Code which contains the USB stack that works out-of-the-box on all KL or K processors with USB (supporting various classes). It can be used with CW10.x, KDS, CooCox, IAR, Keil, Rowley or GCC - for any board it takes 5 project settings to get USB-CDC operating [set the processor type, set the board type, set the linker script to match the processor, enable USB interface, select USB-CDC class]

The USB interface is documented here http://www.utasker.com/docs/uTasker/USB_User_Guide.PDF

The advantages of the USB stack in the uTasker project are that

- it has been proven over several years operation in various industrial projects (also in Coldfire ones using essentially the same software).

- It has small footprint.

- Constructed from three files it is easy to understand and manage, is compatible with all KL and K devices and all build tools
    -- HW driver - handling all HW details

    -- generic USB module - handling all generic USB needs
    -- USB application - defining the class and the application layer function

- the generic and application/class code is used also in Coldfire V2 projects with no change (the HW driver is in fact 90% identical to the Coldfire one too).
- it allows all USB operation to be emulated in the uTasker Kinetis simulator so complete USB projects can be developed, tested and debugged using VisualStudio (free Express edition is adequate). This avoids HW debugging which can otherwise be tricky with USB protocols. The simulator also allows studing and learning USB by executing the emulation process and stepping through the code (including all USB interrupts that take place)

- The project has a powerful MODBUS extension which supports MODBUS TCP or serial masters and slaves. The USB-CDC interface implementation directly allows MODBUS ASCII over USB!

0 Kudos
1,956 Views
weblar
Contributor V

Mark,

Thanks for your comprehensive reply - your comments and feedback are greatly appreciated.

I shall give the firmware you've supplied a try in a tick once I've figured out why the J-Flash software keeps crashing.

Attached is my bin file.

Thanks again for your help!

Kind regards,

Kevin

0 Kudos
1,956 Views
weblar
Contributor V

Hi Mark,

After much faffing around with both IAR and Segger J-Flash, I can confirm that the bin/srec files you supplied for a CDC do not work on my board.

I've tried erasing and re-programming several times without success.

I can re-load the MSD example you sent me and that enumerates correctly however the CDC device does not.

Regards,

Kevin

0 Kudos
2,018 Views
mjbcswitzerland
Specialist V

Hi Kevin

I didn't have problems with the .bin file that I tested in the TWR-K21F120 but maybe there was something in there still that the K22 doesn't like (?) I found that ADC1 was being sampled at 8kHz and passed to DAC0 using DMA (after 1 second delay) so I have disabled this in the attached version (although both devices have ADC1 and DAC0 so I wouldn't expect this to affect operation).

However I have loaded your bin to my board and have some results:

- After installing the driver (using fsl_ucwxp.inf) I get the same error message that you have

- The basic problem is that the enumeration doesn't work fully. It works enough for the driver to be installed but fails when the host requests the Configuration descriptor from the device.

The configuration descriptor informs the host about the interface (that it is a communication control class, its power consumption, the endpoints that are used and the requiremenst of these endpoints). Most of the data content is correct but the overall data is malformed. There is one not-quite-right setting where the device says that it is self-powered but still needs 100mA, but this doesn't cause the failure. The failure actually comes from the fact that the data returned is an incorrect length - there are 198 extra zeroes sent back and the host presumably rejects it due to this.

I took a quick look at the Freescale USB Stack v4.1.1 and have the feeling that the define for the length of the data is incorrect.

It is defined as

uint_8 USB_DESC_CONST g_config_descriptor[CONFIG_DESC_SIZE] =

and there are various sources for the define CONFIG_DESC_SIZE, whereby it looks like the following may be used

#define CONFIG_DESC_SIZE              (CONFIG_ONLY_DESC_SIZE + 28 +   \
                                      (CIC_NOTIF_ELEM_SUPPORT & 0x01) \
                                      * 7 + DATA_CLASS_SUPPORT * 23)

Possibly you have used some configuration/project setting that breaks the code because I don't think that there is any compiler dependency involved.

I would try removing the length from the definition of the g_config_descriptor[] because it is not needed. I would also ensure that any code using g_config_descriptor[] works with the array length and not the CONFIG_DESC_SIZE.

Eg. a routine sending this descriptor would better use a pointer to g_config_descriptor and sizeof(g_config_descriptor) and not a pointer to g_config_descriptor and CONFIG_DESC_SIZE.

I expect that the CDC driver essentially works but I see that there are a handful of devices supported, each with its own set of project files and some local defines. Probably the code based on the define is "difficult to maintain" code since it may need to be right in all device types/configurations. It may work in one but not work in another because it hasn't been tested or corrections were not made at all locations where neeed. As noted above I don't see any need for this critical define value since the array size should take care of itself.

Regards

Mark

P.S. Such errors are not easy to identify without a HW analyser and I recomment investing in one if working with USB based projects.

0 Kudos
1,956 Views
weblar
Contributor V

Hi Mark,

Sorry for the late response - I've only just managed to sit down to try your code and also to try the change you suggested.

Unfortunately, loading your new binary still makes no difference - the device won't even enumerate. Also, I've implemented the changed you suggest regarding the g_config_descriptor but it seems to make no difference, I still get a "device cannot start" error message.

I'm now utterly confused as your initial USB MSD example worked perfectly.

Thank you again for all your help with this.

Regards,

Kevin

0 Kudos
1,956 Views
mjbcswitzerland
Specialist V

Hi Kevin

Unfortunately I can't explain why the application doesn't want to work (either generally or in relation to the USB interface) on your board since it runs correctly on my TWR-K21F120 and I didn't notice any difference between basic configurations of the K21F120 boot loader (USB-MSD) and the application.

You could load the complete project from KINETIS Project Code if you like and then you may be able to work out why - I can't imagine it is something big but I can't think what at the moment. Assuming you are using CW10.x you just need to do the following:

1. Copy the CW10.x project settings from \Applications\uTaskerV1.4\KinetisCodeWarrior\ProjectSettings to the top of the project directory (the latest version has KDS files there and they can't co-exist)

2. Import to CW10.6
3. In \Applications\uTaskerV1.4\config.h enable KINETIS_K20 and TWR_K21F120M to select base family and the board (that should be compatible)

4. In the same file make sure that USB_INTERFACE is enanble to activate USB support

5. In the same file make sure that USE_USB_CDC is enabled (and not other classes)

6. In CW10.x processor settings make sure that Cortex-M4 (and not Cortex-M0+) is used
7. In the CW10.x linker script setting ensure that the linker script matches the device  K_1M_128.lc or K_512_128.lc would be OK, for example

By adjusting 3, 6 and 7 appropriately I can can switch between all K and KL processors/boards that I have (almost all existing ones...) and USB-CDC runs correctly (K22F120 should essentially be a subset of K21F120 since there is no eval board for it).

I am also surprised that you don't detect a difference if the g_config_descriptor length has been corrected - it was certainly the (first) problem since the USB analyser called it a "malformed" frame.

If you send me the latest binary I could give it another go to see whether it gets past this and discovers a further problem (it didn't get any further the last time and there are a number of enumeration steps still to go...) to determine whether there are good chances of a quick fix.

Regards

Mark

0 Kudos
1,956 Views
weblar
Contributor V

Hi Mark,

I also can't understand why, its really not making any sense to me - especially given that the MSD works perfectly. Given that the silicon is presumably very similar to the K21 devices plus there is nothing in any errata which highlights a USB issue then I would have assumed that it would just work.

I'm actually using IAR but I believe uTasker supports this environment?

Changing the g_config_descriptor length makes absolutely no difference. I'll do a build again tomorrow (I've put the code back as-was) and I'll upload it here.

It probably would be beneficial if a Freescale FAE could comment, or maybe someone involved in the stack development.

For reference, what hardware USB analyser do you use? I've used an Ellisys Explorer 200 before now but they're a bit pricey - especially for a home user!

Regards,

Kevin

0 Kudos
1,952 Views
mjbcswitzerland
Specialist V

Kevin

Yes, uTasker builds with IAR (as well as GCC, Keil, CW, KDS, Rowley or CooCox).

Only differences in the setup steps are:

- open \Applications\uTaskerV1.4\IAR6_Kinetis\uTaskerV1.4.eww (rather than importing)
- chose processor part K22F120 drectly
- check the linker script is correct (K_1M_128.icf or K_512_128.icf for example)

I use an Ellisys Explorer 200 and Total Phase Beagle USB 480.

The Ellisys cost about $5'000 some 6 years ago but have become somewhat cheaper in the meantime. Unfortunately, at the time, it was without class decoders which would have been several thousands more for the SW. When I decided it was time to have class decoding to speed up work with new classes I had the choice of buying the decoder SW upgrade (at reduced price for about $1'200 but with limited classes) or a Beagle which includes them as standard for about $1'500 total. So I went for the Beagle so that I have class decoding (I still like the Ellisys though, when I am not interested in the class details) and a second analyser in case the first one should fail for some reason.

Regards

Mark

0 Kudos
1,949 Views
weblar
Contributor V

Doh! I think I know what it could be... possibly.

Freescale define TRUE as 1 and FALSE as 0 - whereas I use 0xFF as TRUE.

In the #define CONFIG_DESC_SIZE statement there is "DATA_CLASS_SUPPORT * 23" which should be interpreted as 1 * 23 however I have 0xFF * 23.

Obviously, this wouldn't explain why the binary you sent to me didn't work however this may be the solution for the Freescale stack.

Regards,

Kevin

0 Kudos
1,956 Views
weblar
Contributor V

One brief observation is that in the Freescale code in usb_descriptor.c at line 485 which is in the USB_Desc_Get_Descriptor function.

I've added a printf statement which outputs the type of descriptor and the size of the descriptor being requested, as follows:

else if (type < USB_MAX_STD_DESCRIPTORS+1)

    {

        /* Set return val for descriptor and size */

        *descriptor = (uint8_t*)g_std_descriptors [type];

        /* if there is no descriptor then return error */

        if(*descriptor == NULL)

        {

            return USBERR_INVALID_REQ_TYPE;

        }

        *size = g_std_desc_size[type];

       printf("Type: %d, Size: %d\r\n", type, *size);

    }

I've sent a breakpoint on the first line of the "if" clause and I can see that this code executes 5 times throughout the enumeration process. After the first 3 times, device manager reports no issue with the device, it enumerates and appears available for use. The next two times the code executes seems to be where the error occurs and if I allow the code to continue, the device then reports that it cannot start.

The output from the printf is this...

Type: 1, Size: 18

Type: 1, Size: 18

Type: 2, Size: 5711

Type: 1, Size: 18

Type: 2, Size: 5711

Its late so I'm now giving up for the night. It won't beat me!

0 Kudos
1,956 Views
mjbcswitzerland
Specialist V

Kevin

The sizes should be as follows for USB-CDC:

1, 18

1, 18

2, 67

1, 18

2, 67

1 is the device descriptor which is always 18 bytes in length . The host always requests this a number of times.

2 is the configuration descriptor, again the host usually requests it about twice. The length of this coulld vary slightly (a couple of bytes) depending on exact settings but your values look to be huge.
It could be that there is a different problem since I saw only that there were about 196 additional zeroes being sent but this may have been limited by the routine not sending more that than and it could have been trying to send thousands too many in the first place...

Regards

Mark

0 Kudos
1,956 Views
weblar
Contributor V

Ok, this requires further investigation.

Thanks for updating what the sizes should be - one thing about the Freescale code that does get baffling, which you've highlighted previously, is the number of #defines accounting for almost every variation of device. It makes it really difficult to follow the path which the code will take.

Kind regards,

Kevin

0 Kudos
1,956 Views
mjbcswitzerland
Specialist V

Kevin

I don't have a K22 board to test on but I believe that the K22F120 is identical to the K21F120 in terms of USB and clocks and your clock setup does look to match a K21F120.

Presumably you don't have a USB analyser to monitor the enumeration but if the enumeration is succesful (there will be a point in the code where you could set a breakpoint to determine this) there is probably a driver problem.

It often makes sense to try with USB-HID mouse or USB-MSD first since these are user-friendlier and don't have potential driver issues - if they operate, USB-CDC will presumably operate as well (baring driver problems).

There is a USB-MSD loader (binary) for the K21F120 tower board (uses 8MHz oscillator and the USB should be HW independent) at µTasker Test Software and Demos which you could load to your K22. If it appears as a hard-drive it would prove basic USB operation on your board and you could do a register dump of the clock registers to be sure that there are no differences to your setup (it also configures for 120MHz PLL operation).

Regards

Mark

1,956 Views
weblar
Contributor V

Hi Mark,

Thanks for your comments.

Unfortunately, I don't have a hardware USB analyzer but I do have a software one which I've been using however I'm still unable to determine the root cause. Enumeration doesn't seem to complete successfully however the USB_ISR enters as I expect it to.

Good idea about getting a much simpler project up and running - I guess when I initially designed the K22 into my project, I had hoped for a few more examples from Freescale but like you've mentioned, the K21 is almost identical.

Thanks for the link, I shall give the uTasker demo a try although admittedly, I've never used uTasker before so I may be in touch with further questions.

Kind regards,

Kevin

0 Kudos
1,956 Views
weblar
Contributor V

Ok, I've downloaded the uTasker demo.

Presumably, I need to program on the uTaskerSerialLoader first? Or can I just blast the USB_software_1.4.003.bin file on?

Regards,

Kevin

0 Kudos
1,956 Views
mjbcswitzerland
Specialist V

Kevin

Program the file "uTaskerSerialLoader_K21_F120.S19" to the board to see whether it appears as a hard drive when connected via USB.

The other files are applications that can be downloaded via the USB connection but are probably not of further interest in checking that the USB is OK.

Regards

Mark

1,956 Views
weblar
Contributor V

Hi Mark,

I've just loaded the file in using the Segger J-Flash application. I was prompted to confirm that overwriting location 0 might read-protect the chip but I clicked OK anyway.

Having power cycled my board, nothing seems to be happening - could the firmware be looking for other peripherals that aren't present?

Regards,

Kevin

0 Kudos