USB or not: CDC with Processor Expert

I had a PREN student showing up into my office. He wanted to choose a microcontroller for that project. One requirement put on the table was “it needs USB”. Well, I asked why USB is required. I was not surprised by the answer: “to use USB instead of RS-232”. Wow. So what he really wanted was USB CDC (Communication Device Class). Yep. Most notebooks today have no serial COM port (see “Processor Expert Configurations“). But because “USB is serial” does not mean “USB CDC is simple”. Nope. USB is not simple. But it can be with Processor Expert.

RS-232 is simple and not expensive. That’s why I use it in so many designs. If I need a serial communication with my board, then my first choice is RS-232. It is straight forward and just works. Yes, RS-232 it is not plug&play: you have to configure baud and connection settings. But a typical RS-232/SCI/serial implementation in my embedded design takes typically one or two source files with a total of less than 20 KByte of sources code (counting the comments too), and impacting my application with less than 1 KByte of code.

USB on the other hand promises plug&play, plus it can power my typical board. USB means much more than two serial wires plus power: its needs a full-blown communication stack! As such, it is much more complex: the Freescale USB Stack stack for CDC uses more than 32 source files with about 400 KByte of source code. Adding CDC to my application means 10-20 KByte of code! Yikes. So a lot of complexity to send some strings over a serial wire. And if something does not work, I better buy one of these expensive USB protocol analyzer? Definitely not the easiest thing.

But: USB is reality and everywhere. Worse: new notebooks rarely have a physical COM port. I’m lucky that my old Dell still has one :-). Is there no demand any more for ‘engineering notebooks’ with a COM port? Sigh!

With no physical COM port, I end up use a USB-to-Serial converter:

Typical USB-to-Serial Converter Cables
USB-to-Serial Converter Cables on my bench

Yep, that works, but is a pain: multiple drivers. If I’m lucky, I get the 64bit drivers up and running. If I need one, for sure it is in the other lab. I need to make sure that the engineer in the field is equipped with the converters too. Imaging traveling to the customer, only to find out I left the adapter on the bench in the lab :-(.

To avoid that kind of problem, a solution is to add a Serial-To-USB chip on your board: What has been don on the Freescale MC13213 SRB board: it is using the Silicon Labs Dual CP210x UART to USB Bridge. Freescale itself is offering a similar solution presented here. Still, it typically does not solve your drivers problem. But you can use a normal microcontroller without USB capability: the USB interface is added with a separate IC.

SRB Board with Silicon Labs UART to USB Chip
SRB Board with Silicon Labs UART to USB Chip

More and more silicon vendors (including Freescale) are offering microcontrollers with USB on the chip. So no need any more for that converter IC. They offer as well software and USB stacks. Freescale offers the USB stack with PHDC Support, or drivers come with MQX. It comes with documentation and examples and supports many processors and USB modes.

But if you want to integrate this USB stack into your own design, it gets really challenging. It is really hard to isolate the files and functions you need. There has to be a way to make things simpler for me! What I need is a Processor Expert component which I can easily integrate and use with my other Processor Expert components.

The good news is: I have finished a USB CDC stack integration as Processor Expert component. It is using the Freescale USB stack with PHDC Support. Up to switching back and forward between RS-232 and USB CDC as shown in the post on Processor Expert Configurations.

I’ll show in the steps below how to use USB CDC with a DEMOJM board and the MCF51JM128: The application is a bare metal one which is using USB CDC for communication with the host.

DEMOJM Board with MCF51JM128 running USB CDC

DEMOJM Board with MCF51JM128 running USB CDC

The USB CDC support is realized with two components:

  1. The Init_USB_OTG component: this one comes with CodeWarrior to initialize the USB peripheral.
  2. The FSL_USB_Stack component: this one is a wrapper around the Freescale USB Stack. Additionally two circular buffer components implement buffering.

To start, I check the jumper settings on DEMOJM board:

  • IRQ Fault: no jumper
  • VHOST_EN: OFF position
  • VBUS_SEL: VBUS position
  • DN_DOWN/J13: on position
  • DP_DOWN/J14: on position
  • USB_ID: no jumper
  • PULLUP: no jumper

Creating a project and adding USB CDC support is possible in 10 steps:

  1. I Create a new project with the wizard with Processor Expert option enabled (see Quickstart for Processor Expert Project)
  2. For USB I need to configure the clock to 24 MHz: Using the 12 MHz crystal on the board in high gain mode a PLL Engaged:

    Clock Settings for USB

    Clock Settings for USB

  3. I add the FSL_USB_Stack component to the project. I set the device as MCF51JM128:

    FSL_USB_Stack  Settings

    FSL_USB_Stack Settings

  4. The FSL_USB_Stack inherits from the USB_OTG_Init component, so it gets automatically added as ‘sub-component’. All the settings get set up automatically, things like USB_ISR as interrupt name, enablingnecessary interrupts and device settings. So nothing to do here, everything is automatically set up:

    USB_OTG_Init Settings

    USB_OTG_Init Settings

  5. USB has a price: the small data model is not big enough. I need to change the build tools settings to the 32bit code model. I can do this in the project settings for the compiler:

    32bit Code Model for the ColdFire Compiler

    32bit Code Model for the ColdFire Compiler

  6. I add the Wait component to the project and enable Delay100usin the CPU component:

    Enabling Delay100US in the CPU component

    Enabling Delay100US in the CPU component

  7. This is an optional step: A add two LED component to the project. The LED is configured with the Anode on the port side. I configure one LED for pin PTE2, the other for pin PTE3.
  8. Now I generate code with Processor Expert. This generates the linker file which I need to change. To prevent further linker file modification, I disable the generation of the LCF file: For this I select the CPU component, use the Inspector View and change the setting in the Build Options tab:

    Disabled Generation of Linker LCF File in CPU component

    Disabled Generation of Linker LCF File in CPU component

  9. To change the linker file, I open the ProcessorExpert.lcf file. I need to allocate the USB Buffer Data block (BDT). I add the following block between .text and .data:
      .usb_bdt :
      {
        . = ALIGN(512);
        __BDT_BASE = .;
        *(.usb_bdt)
        __BDT_END = .;
      } >> userram
    

    USB BDT allocation in Linker File

    USB BDT allocation in Linker File

  10. I add the following code (e.g. in a separate file) and call CDC_Run() from main().
#include "LED1.h"
#include "LED2.h"
#include "USB1.h"
#include "WAIT1.h"

static uint8_t cdc_buffer[USB1_DATA_BUFF_SIZE];
static uint8_t in_buffer[USB1_DATA_BUFF_SIZE];

void CDC_Run(void) {
	int i;

	for(;;) {
		while(USB1_App_Task(cdc_buffer, sizeof(cdc_buffer))==ERR_BUSOFF) {
		/* device not enumerated */
			LED1_Neg(); LED2_Off();
			WAIT1_Waitms(200);
		}
		LED1_Off(); LED2_Neg();
		if (USB1_GetCharsInRxBuf()!=0) {
			i = 0;
			while(   i<sizeof(in_buffer)-1
				&& USB1_GetChar(&in_buffer[i])==ERR_OK
				)
			{
			i++;
			}
			in_buffer[i] = '\0';
			(void)USB1_SendString((unsigned char*)"echo: ");
			(void)USB1_SendString(in_buffer);
			(void)USB1_SendString((unsigned char*)"\r\n");
		} else {
			WAIT1_Waitms(50);
		}
	}
}

The code runs in an endless loop. It calls the USB application function USB1_App_Task() with a send buffer. USB1_GetCharsInRxBuf() is used to check if there are any incoming characters. USB1_GetChar() is used to get the characters from the input buffer, and USB1_SendString()is used to send strings. The component uses two circular ring buffers: one for the input stream and one for the output stream:

Application Components

Application Components

Time to build, download and run the application. For now I power the board, but do not connect the USB CDC connection to the host. I see the LED1 flashing slowly. Once I plug in the USB CDC cable, LED2 flashes fast to show that the device is enumerated on the USB bus. If not, then your host probably needs some drivers …..

The first time I attach the board on my host, it will show up as JM CDC DEMO in the Device Manager:

JM CDC Demo Device

JM CDC Demo Device

So I need a driver for it? Actually, a .inf file is enough. The FSL_USB_Stack has generated the .inf file based on my settings into the Documentation folder:

USB driver and .inf settings

USB driver and .inf settings

cdc.inf fle created by the component

cdc.inf fle created by the component

There is as well a cdc.inf_readme.txt file: follow the information to install the .inf file. With the driver installed it should show the device as specified in the .inf settings:

Freescale CDC Device

Freescale CDC Device

Now I can connect to COM22 (or whatever port it is) with my terminal:

USB CDC Communication

USB CDC Communication

The above application is a very simple one, and does not use an RTOS. A more complex example using a Shell and FreeRTOS is shown below:

USB CDC Example Project

USB CDC Example Project

The components and the example project can be downloaded from here.

Happy CDC USBeing 🙂


		
Advertisements

64 thoughts on “USB or not: CDC with Processor Expert

  1. Pingback: USB CDC Reloaded | MCU on Eclipse

  2. Pingback: Dissection of MCU10 Projects | MCU on Eclipse

  3. Pingback: Disable my Code Generation | MCU on Eclipse

  4. Excelente el blog, y todos tus post. No hablo muy bien el ingles, pero lo entiendo al leelo, gracias por tus aportes, me serán de gran ayuda. ëxitos..

    Like

  5. Pingback: Tutorial: FreeRTOS on DEMOJM | MCU on Eclipse

  6. Hi,
    just tried the last version of the PE 1.007 version on a S08JM with CW10.2
    I cannot set the TX and RX buffers properties (it remains empty) and I get the following messages like this during PE code generation : ” INTERNAL ERROR: at line 145: “Send Buffer”/TxBuffer has not assigned the component (file: Drivers\sw\FSL_USB_Stack.drv)”.
    Any idea ?

    Like

  7. Pingback: CDE Hacking: Components with Multiple Files | MCU on Eclipse

  8. Thanks Erich,
    that was the problem, I add the component but CW needed to be restarted otherwise it doesn’t update the PE library very well.
    Now it works

    Like

  9. Pingback: Virtual COM/USB CDC for OSBDM/OSJTAG | MCU on Eclipse

  10. Have a nice day. I’m reading your post, good as gold. BU t I have a problem. I create a new project with PE and add the FSL_USB_Stack wrapper. I’m using MCF51JM128 on my demoboard JM128 and I try to change cPu to JM128 and always put on JM64. Of coursem the project was made for JM128VLH (that’s my chip). There’s any problem about license? thanks
    Giovanni

    Like

    • Hi Giovanni,
      no, that does not sound like a licensing problem at all. Where are you going to change the CPU? in the CPU component or in the FSL_USB_Stack? Maybe simple send me some screenshots or even the project with some more information to erich dot styger at hslu dot ch and I’ll have a look.
      Erich

      Like

      • At least I could compile the project but there’s an issue, the LED component can’t be added (I suppouse my license). I can receive data, it seems transmiting data but no answer in serial port manager program I use (Hercules and Termite). I checked once again my DEMO JM conections and are equal than yours. Thanks
        Giovanni

        Like

  11. Pingback: Changing the CPU with Processor Expert | MCU on Eclipse

  12. HI, I use your CDC component for tx data to the PC, but only sends 32bytes and after no more.

    for example:

    for(i = 0;i < 64; i++){
    sprintf(text,"%d",i);
    (void)USB1_SendString((unsigned char*)text);
    }

    This code only transmit 32bytes.

    Thank you.

    Like

    • Hello,
      the FSL_USB_Stack component is using the RingBuffer sub components (Send Buffer and Receive Buffer): have you set them up to more than 32 bytes? If not, then I would understand that you only can send 32 bytes in a piece.

      Like

  13. Now the LEDs work! Thank you very much for your help, and thanks for creating this component.

    I hope that you can make a PE component for HID class device.

    Like

  14. Pingback: Tutorial: USB CDC with the KL25Z Freedom Board | MCU on Eclipse

  15. Hi, thanks for this tutorial it has been very helpful to me.
    I have a little problem whith the FSL_USB_Stack, when i select the CPU, I choose MCF51JM128, but the software puts on the window MCF51JM64, It only happens qhen I select that particular MCU.

    Sincerely, Johnny

    Like

    • Not sure what you mean, and which window? Could you provide some more details on this? Maybe it is this: if you select the JM64, it will internally use the JM128 as it is the same device, but just with less memory.

      Like

  16. Pingback: USB Component Splitted and Updated | MCU on Eclipse

  17. Hi Erich – the tutorial has been very help to me also – I was able to bring in FLS_USB_Stack bean and other associate beans without any real issues. Im using the S08JM60 IC so Im using the USBinit1 component instead of the Init_USB_OTG and everything compiled fine after I made all the necessary changed to enable Extal 12MHZ osc in the CPU bean as you directed above. The issue I am now having is when I run the debug it will automatic run the debug (which has never done before usually I have to hit the go button) and then the program just get caught here while(MCGSC_IREFST != 0U) { /* Wait until external reference is selected */} in the cpu.c file – I guessing it is a simple setting I have not triggered in the software to activity the external crystal but up to now I can not get this working and I’m starting to pull my hair out – Any suggestion for this one? thanks!

    Like

      • thanks for help Erich! – you were correct – I had the external clock set to osc and not crystal. So I was able to get the demo project working up to a point – the driver is working and it looks good in the device manager for the connection to my unit. I run the “run_CDC” routine and it will take the first letter that I hit on the keyboard and grab the “echo: ” from the my device so if I hit P it puts out “echo: p” with the \t\r after it but it then gets caught up in the code at while(transactionOngoing){} and does not cycle but through the routine.
        Again probably something simple not set – if you have any ideas I would appreciate your input – thanks!

        Like

      • Hi Garreth,
        Does it work with the example from http://www.steinerberg.com/EmbeddedComponents/Examples/Example_PE_CDC_V1JM128/PE_CDC_S08JM60_MCU10.3.zip? Otherwise it might be hard to tell what the problem could be. Here are a few tips:
        – verify that you are still getting USB interrupts (set a breakpoint in the interrupt handler). Maybe interrupts are switched off somewhere?
        – try out a different terminal utility or check settings. I’m using mostly Termite (see my screen-shots) with ‘append CR+LF’ settings (so when I hit return, it sends CR+LF)
        Hope this helps.

        Like

      • Erich – yes I used the above link and loaded that project into codewarrior – I have tried changing a lot of the settings in CPU bean and FSL_CDC_STACK bean without any success. the only setting that makes any difference is the Initialization interrupt priority setting in the CPU bean – with it enabled the PC sees the units USB port and initializes the driver correctly and it allows the hyperterminal program get the echo return with 4 or 5 characaters – after that is locks up the hyperterminal program and processor software gets caught here –>while(transactionOngoing){} . I downloaded the termite program and it basically reacts the same way using the settings you suggested. So the only thing that I have set differently from the project download was to set the”initialization interrupt priority” i have spent all of yesterday trying to see if there is another ISR setting that I need to change but without success. Above you mention that “Maybe interrupts are switched off somewhere?” is there any specific place I need to look in to set the interrupts? In the “PE_low_level_init();” I can see that these init’s are called.
        USBInit1_Init();
        Tx1_Init();
        Rx1_Init();
        (void)USB1_Init();
        __EI();
        One other thing: this is an actual board with JM60 on it and not the JMdemo board – would that make any difference? Again any suggestions of help is appreciated – thanks!

        Like

      • Garreth,
        yes, the board can make a difference. Freescale USB devices need very accurate clock for the USB communication: if you have made a custom board, and if for whatever reason your clock is not clean enough or traces are too long, USB communication might fail. The fact that you got the USB enumeration working is a good sign, but maybe communication is not stable enough. If you can, I suggest that you try it with a DEMOJM board to have a working base. As you indicate that the software is the same/fine, it could be hardware problem.

        Like

  18. Hello,

    First, big thanks for you blog, and for all infos inside.
    I have tried to use your PE_CDC_S08JM60 (MCU10.3) (bareboard) example on my DEMOJM equiped with a MC09S08JM60.

    All goes well until the connection to the PC. Both LEDs are OK, and when connecting via USB, i have the following message :

    “One of the USB devices attached to this computer has malfunctioned, and Windows does not recognize it”

    and in the list of USB, it appears as: unknown usb device

    Do you have any idea ?

    Thanks by advance for your help.

    Best regards,

    Stéphane

    Like

    • Hi Stéphane,
      thanks :-).
      I need to dig out my board (I do not have it with me right now). I hope your jumper settings are correct (I’ll pass mine as soon as I have the board). Have you used the cdc.inf already?

      Like

      • Hi Erich,

        Many thanks for your quick answer. Yes, I have tried to use cdc.inf file. But according to the “unknown usb device” status, the driver does not want to be installed…

        I will try again.

        For info, I have directly try with the stack example from Freescale (4.0.3) and it was OK with the generated .inf.

        Best Regards,

        Stéphane

        Like

      • Hi Stéphane,
        strange, I tried it out, and the problem is that the USB module and interrupts are not enabled. I must have missed out something. You should be able to get it running with the example if you put
        CTL_USBEN = 1;
        EnableInterrupts();
        just before CDC_Run().
        just before the

        Like

      • Hi Stéphane, I had to fix another problem in the stack for S08: it was not properly calling the ‘poll’ routine while waiting for the ‘finished’ transfer token. I have updated the sources on GitHub and tested it with KL25Z, S08JM16, S08JM60, MCF51JM128 and MCF52259.

        Like

      • Hi Erich,

        Many thanks for your help and your work.
        I will try your updated prog on monday (was not at home this WE).
        Et encore bravo pour ce blog,
        Un français redevable !

        Like

  19. Hi, thevold component works fine. But the new I don’t undestand what happen!, only add to project and generate a lot of errors:
    Description Resource Path Location Type
    INTERNAL ERROR: at line 2: Command %set cannot be used in this type of script. It can be used in component script only. (file: Beans\FSL_USB_Stack\FSL_USB_Stack.chg) Sensirion1 Processor Expert Processor Expert Problem

    thnx.

    Like

  20. Hi Erich! Thanks a lot for your amazing tutorials!

    I’ve been able to make my FRDM K20D50 work with your CDC code and it is working fine, but now I made my own hardware (PCB with a MK20DN128VFM5 microcontroller) and I am trying to make it work in the same way. Unfortunately, after programming the microcontroller in my board, windows is not recognizing the device and is throwing “The last USB device you connected to this computer malfunctioned, and Windows does not recognize it”. In Ubuntu it says that the “device is not accepting address 24, error -32”. I am using the same FSL_USB_Stack properties as in your code (for the FRDM K20D50). My board has a different crystal (16MHz) but I think I have done the necessary changes such as the master clock is 48MHz.

    I was really hoping you could give me a few hints on solving this.

    Many thanks for your great work again!

    Like

    • Thanks :-).
      About your problem: can you make 100% sure that your settings the same? You need to check that you enabled the clock gates (in the USB Init) and that in the CPU component you have configured the clock output (PLL). If not, errors like the ones you mention will show up.
      Except you have an electrical problem too (wiring on the board, noise, USB connector/cable/etc).

      Like

      • Thank you Erich! It is working now. Bad microcontroller, unfortunately..
        On another note, I am currently using a TimerUnit_LDD with a 4 ms period (counter restart on-match) in processor expert, and I would like to change this period value on the fly. More specifically, my board connects to an android phone and I would like the user to be able to change this timing setting to whatever value they want. Looking into the processor expert generated code, I found that in TU1.h, this is coded in “#define TU1_PERIOD_TICKS 0x04UL”. My problem is: this is not a variable that I can make global to be changed by the user (programming) afterwards. Is there some tool or function that I can use to be able to change this period value (generated by processor expert) on the fly? What is the proper way to do this and how can I do it?

        Many thanks again for your help!

        Like

      • Instead of using the TimerUnit_LDD, I would use the PPG (Programmable Pulse Generator) component: with this one, I can change both the frequency and the duty ratio of the PWM at runtime.

        Like

  21. Hi Erich, do you know if it is possible to instantiate two CDC components, without conflicts? So that i can use two COM ports through the same USB connection?

    Like

      • I have a “FSL_USB_Stack” component which has a “FSL_USB_CDC_Device” subcomponent inside.
        I tried first to add another “FSL_USB_Stack” component, but an error appears with sub-component “Init_USB_OTG”, because of the name USB0 (which is repeated and dont let me change it), and the Device USB0 that is already used by the other component (is logical, because there is only one phisical USB port).

        After this i tried to add a single “FSL_USB_CDC_Device” to the project. Besides it doesnt let me add this into the USB_Stack, when i want to generate PE Code, CW tells me that the following filenames are duplicated in the project:
        USB_Config.h
        cdc.inf
        usb_cdc.c / .h
        usb_descriptor.c / .h
        usb_cdc_pstn.c / .h
        usb_user_config.h

        How could i do to:
        Make second CDC be part of USB_Stack?
        Make both components refer to different files, or change those filenames not to be in conflict?

        Thanks for answering Erich! 😀

        Like

      • Hello,
        that component is not setup/designed for a second instance. This simply is not possible with the way the sources in the USB stack are organized. The issue with the USB0 name can be easily changed by you: you can change the name of the component. But again: you cannot add a second USB CDC that way: you would need to write/extend the USB stack for a combined device, this is not supported out of the box.

        Like

  22. Hi Erich

    I’m trying to use the CDC on my own KL25 board, connecting with a Windows 8.1 computer. When I try to install/update the driver on PC (the same that worked well on Windows 7) I get a Windows message about “driver without digital signature”. Have you some information about this issue? Thank you!

    Like

    • Hi Mauricio,
      I’m not using Windows 8, but if you search the internet for
      windows 8 install unsigned driver
      you will get plenty of good articles on that subject.
      I hope this helps.

      Like

  23. Hi Erich,

    I´ve seen several examples you´ve posted about USB CDC in some different boards. All of them are based on this PEx component you´ve created (FSL_USB_Stack). I´m designing a new board based on a KL27 and I´ve found this component is no longer available for this new platform.
    Is there anything I could do to adapt this PEx component to make it available again?

    Like

    • Hi Juanjo,
      not sure what you mean ‘no longer available for this new platform’? So yes, if there is only the Kinetis SDK for the KL27, that FSL_USB component unfortunately does not work for it. But there is an USB stack inside the Kinetis SDK you could use instead?

      Erich

      Like

  24. I have been successfully using a USB CDC stack on my KL26 design, now I am trying to test a second PCB. Identical firmware, identical hardware, but Windows 7 64 bit refuses to let me install CDC device driver. I’ve been round loop several times, but when I get to the folder with the .inf file in, Windows refuses to cooperate, saying the best driver is already installed(which is rubbish, as it’s listed as unknown device). Is this some problem with two, identical devices, or am I simply missing something?

    Like

  25. OK, false alarm. This design is using NMI as a GPIO. As (bad) luck would have it, on the first PCB I got my hands on, the track from PTA4(NMI) was damaged, so I hi-jacked another pin for that function. Consequently PTA4(NMI) was unconnected. On this PCB the track was intact, and so I had an NMI problem. Now I’ve changed the flash config bytes to disable the NMI, and looks like all is OK.

    Like

  26. Hi Erich,
    Everytime I build the processor expert components in my K22 CDC USB project there is a stub for the interrupt handler ‘PE_ISR(USB_ISR)’ put in my events.c file. And I then have to delete that to be able to compile my working project (the USB_ISR that is used was generated in Generated_Code/usb_dci_kinetis.c)

    Is there a way I can suppress that extra routine from getting generated?

    Like

    • Hi Brynn,
      check the following project setting:
      “Project > Properties > Processor Expert > Generate ISRs” which which should set to ‘no’ (default setting).
      I think you have it set to ‘yes’ somehow?
      I hope this helps,
      Erich

      Like

      • Yes, it was set to YES. Changing it to ‘no’ does indeed keep the extra USB_ISR routine from getting generated

        Thanks Erich!

        Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s