Home > FRDM K64F, Kinetis > KSDK USB CDC PRINTF

KSDK USB CDC PRINTF

Previously I created a blog post on Printf to UART using Processor Expert, this is a great way to output debug info at runtime to a console using the OpenSDA USB debugger port as found for example on the FRDM K64F board. What if you don’t want to use this USB port or can’t because you don’t have one, for instance on a custom board perhaps. Well if your board provides a USB port that connects direct to the mpu’s USB pins this blog will help you configure all the Processor Expert components and code needed to output to that type of USB port. In this blog I will again use the FRDM K64F board but it has a second USB port that is directly connected to the USB pins of the of the MK64FN1M0VLL12 MCU. I am using KSDK 1.3.0 and Eclipse Neon but I will also try provide notes on how to do this in KSDK 1.2.0, if you want to know how to set up Eclipse you can follow the directions on my blog Toolchain: KSDK 1.2.0 with Eclipse 4.4 (Luna) and GNU ARM Plugin, although that blog covers an older version of Eclipse and KSDK, the steps work perfectly still as long as you download all the latest pieces of software mentioned in that blog.

PLEASE NOTE: I am not an expert with USB on Kinetis devices so I cannot provide any help on any other USB related projects such as Mass storage devices or HID devices. Please do not post comments/questions asking how to perform other types of USB projects.

 

FRDM_K64F_USB

 

  1. Ok to start, create a new Kinetis project.CreateProject_Name
  2. Select the board type. In my case I select the FRDM-K64F board.CreateProject_Board
  3. Select KSDK_1.3.0, Processor Expert and standalone.CreateProject_SDK
  4. Select “GNU C Compiler” and click Finish.CreateProject_Compiler
  5. Switch to Processor Expert perspective and add the component “fsl_usb_framework”. Note this will also automatically add the referenced components “Init_FMC” and “fsl_debug_console”.
    Note: In KSDK 1.2.0 the “Init_FMC” is not automatically added for you but you still add it manually then afterwards.PE_fsl_usb_framework
  6. If you get prompted on how you want to add the “Init_FMC” component, select “New component [KSDK 1.3.0/Init_FMC_VAR1]…”PE_fsl_usb_framework_sharedComp
  7. On the Components window select “usbFmw1:usb_framework” and set the properties as below. Its important that the USB clock is set to 48 MHz. Its also very important that MPU is disabled as the MPU protects the Bus from USB read/writes. Make sure the Mode is set to “DEVICE” then Enable “USBCFG_DEV_CDC” under the Device class driver section.
    Note: In KSDK 1.2.0 the option to disable the MPU is not available on this component, you will need to manually add the component “Init_MPU” and disable it from there.fsl_usb_framework_Properties
  8. Now select the component “FMC:Init_FMC”, this should be already set correctly for us but just note that the important bit here is that the access protection on Master 4 which protects USB memory access areas must be set to “Read only”.
    Note: in KSDK 1.2.0 this is not set for you, you must manually set Master 4 to Read only.Init_FMC_Properties
  9. Next select the “DbgCs1:fsl_debug_console” component, make sure the “Baud rate” is set to 115,200. It’s not important what Pins the Receiver and Transmitter are set to as this will get overridden in code when we initialise this component manually. VERY IMPORTANT, make sure the “Auto initialization” is disabled, as said, we will manually do this in code.fsl_debug_console_Properties
  10. Ok one last configuration then, select the “Cpu:MK64FN1MOVLL12” component (or whatever MPU you are using). Switch to the “Build Options” tab and make sure you set a Heap size because usb stack uses malloc which uses a function called _sbrk(). This function checks if there is heap memory available to allocate to the malloc. The FRDM K64F board has enough memory available for me to set the Heap size to its max on this screen of 0xFFFF, Also make sure you have at least 0x400 allocated to the Stack.
    Note: KSDK 1.2.0 has a bug and does not implement a _sbrk() function, you will need to create your own _sbrk() function to get this to work. See the end of this Blog on how to do this.Cpu_HeapSize
  11. Now generate code from Processor Expert.Components
  12. On the Project Explorer window, expand the folder \SDK\usb\usb_core\device\sources. Create a folder under the sources folder called “classes”.Import the following 3 folders into the classes folder from the path “C:\Freescale\KSDK_1.3.0\usb\usb_core\device\sources\classes”
    • cdc
    • common
    • include

    import_usb_classes

     

  13. We need to add these new folders into the includes. Open up the project properties and add the following 4 folders under “C/C++ Build >> Settings >> Cross ARM C Compiler >> Includes”.Project_Settings_includesOn the Project Explorer window again, Open up the file “\SDK\platform\utilities\fsl_debug_console.c”.  Note around line 49 the following #if block:
#if (defined(USB_INSTANCE_COUNT) &&  (defined(BOARD_USE_VIRTUALCOM)))
  #include "usb_device_config.h"
  #include "usb.h"
  #include "usb_device_stack_interface.h"
  #include "usb_descriptor.h"
  #include "virtual_com.h"
#endif

based on this section of code I can see that the code actually supports using USB and the use of the “VIRTUALCOM”. What is this “VIRTUALCOM”, well if you were to look at the code in the example KSDK project “C:\Freescale\KSDK_1.3.0\examples\twrk64f120m\demo_apps\usb\device\cdc\virtual_com\bm\kds” which is a project for demonstrating how to use USB CDC communication but without the use of the” fsl_debug” component or using Processor expert at all, then you will see that the “VIRTUALCOM” is the main piece of code written for sending and receiving messages over the USB CDC. Great, that means then that we can enable the “fsl_debug_console” to make use of it. So looking at this section of code in “fsl_debug_console.c”, it looks like all we need do is define a symbol for “BOARD_USE_VIRTUALCOM”.

  1. Open up the Properties of the project and under “C/C++ Build >> Settings >> Cross ARM C Compiler >> Preprocessor” add the symbol “BOARD_USE_VIRTUALCOM”. make sure to include the double quotes around the symbol.Project_Settings_Preprocessor
  2. Ok but now the code will complain that it can’t find the included files “usb_descriptor.h” and “virtual_com.h”, so where can this be found. Well actually you can find these files in the same directory where the “fsl_debug_console” files get imported from. So to fix this perform the following imports:import_virtual_com_headersimport_virtual_com_code

     

  3. One last thing to do is make sure we initialise the Debug Console component telling it to use the USB CDC. If you remember we intentionally disabled auto initialising the “fsl_debug_console” in processor expert. This was done for the purpose of providing us the ability to change the device used by the console. So at the start of your main function just after the call to “PE_low_level_init()”, make the call “DbgConsole_Init(BOARD_DEBUG_UART_INSTANCE, DEBUG_UART_BAUD, kDebugConsoleUSBCDC);”.

 

/* ###################################################################
**     Filename    : main.c
**     Project     : K64F_USB_CDC
**     Processor   : MK64FN1M0VLL12
**     Version     : Driver 01.01
**     Compiler    : GNU C Compiler
**     Date/Time   : 2015-12-12, 23:04, # CodeGen: 0
**     Abstract    :
**         Main module.
**         This module contains user's application code.
**     Settings    :
**     Contents    :
**         No public methods
**
** ###################################################################*/
/*!
** @file main.c
** @version 01.01
** @brief
**         Main module.
**         This module contains user's application code.
*/
/*!
**  @addtogroup main_module main module documentation
**  @{
*/
/* MODULE main */

/* Including needed modules to compile this module/procedure */
#include "Cpu.h"
#include "Events.h"
#include "clockMan1.h"
#include "pin_init.h"
#include "osa1.h"
#include "usbFmw1.h"
#include "DbgCs1.h"
#if CPU_INIT_CONFIG
  #include "Init_Config.h"
#endif
/* User includes (#include below this line is not maintained by Processor Expert) */

/*lint -save  -e970 Disable MISRA rule (6.3) checking. */
int main(void)
/*lint -restore Enable MISRA rule (6.3) checking. */
{
  /* Write your local variable definition here */

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
  PE_low_level_init();
  /*** End of Processor Expert internal initialization.                    ***/

  DbgConsole_Init(BOARD_DEBUG_UART_INSTANCE, DEBUG_UART_BAUD, kDebugConsoleUSBCDC);

  PRINTF("Hello CDC!");

  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/
  /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/
  #ifdef PEX_RTOS_START
    PEX_RTOS_START();                  /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
  #endif
  /*** End of RTOS startup code.  ***/
  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
  for(;;){}
  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

/* END main */
/*!
** @}
*/
/*
** ###################################################################
**
**     This file was created by Processor Expert 10.5 [05.21]
**     for the Freescale Kinetis series of microcontrollers.
**
** ###################################################################
*/

 

  1. If you try to compile the code now you will get an error saying the Symbol ‘usb_device_board_init’ could not be resolved within the file “virtual_com.c”. If you navigate to the line where this error is caused all that need to be done is to set the value to NULL instead:

 

cdc_config.board_init_callback.callback = NULL;

 

That’s it then, after that you can make “PRINTF”, “SCANF” or “GETCHAR” calls in your code and it will output to the OTG usb port on your board. Please note, you must capitalise the calls to the functions “PRINTF”, “SCANF” or “GETCHAR” as these are specialised versions of the functions that reside inside the “fsl_debug_console.c” file.

 

You can get a copy of this project on my Github repo at https://github.com/wesleyhunter/centaurian/tree/master/Examples/Eclipse/FRDM-K64F/K64F_USB_CDC

 

Good luck, hope this works well for you all.

 

KSDK 1.2.0 _sbrk() function

 

To implement a _sbrk() function simply add the following block of code to your project:

 

void *_sbrk ( uint32_t incr )
{
	extern char   end __asm ("end");
	extern char   heap_limit __asm ("__HeapLimit");
	static char * heap_end;
	char *        prev_heap_end;

	if (heap_end == NULL)
		heap_end = & end;

	prev_heap_end = heap_end;

	heap_end += incr;

  return (void *) prev_heap_end;
}
Advertisements
  1. Hung
    27/12/2015 at 11:49

    Hi there, I have used your tutorial – an excellent tutorial again – and programmed my custom board. It works like a charm! thanks you very much. Please, keep posting whatever projects you ‘d like to share. I ll definitely follow your website.

  2. 20/01/2016 at 13:05

    Hi!

    Really thank you for this tutorial, it was very helpfull for me.
    I’m working whit the KL27Z256VLH4 and your steps to create this project is working fine on my own board.

    I have some doubts about the USB CDC communication, at this moment my project works just in some terminals like “Tera Term”, “RealTerm” and “Putty”. I’m my own application builded on C++ Builder from Borland,using the “TComPort” and in the “Termite” by CompuPhase it crash. I don’t know what’s happen, like the diferences between the implementation program of this softwares.

    Basically on the “Termite” when I send a character, the device crashes, and in my application too.

    Thank you so much for this article. Keep it available on the web!

    André Lemke

    Electronics Engineering Student

    Brasil

    • 20/01/2016 at 13:26

      Thanks for your comment André. I wouldn’t really know why your custom app has issues communicating, only thing I can guess at is to make sure your connection is using the following settings:

      * 115200 baud rate
      * 8 data bits
      * No parity
      * One stop bit
      * No flow control

      Also, if you are using windows, open up device manager, look for your CDC device, right click and view port settings there. On my pc I can change the settings for the port I just specified above. Both the device manager settings for the port and your C++ application must match up on all the port settings.

  3. 21/01/2016 at 10:18

    Hi, thanks for this tutorial is has been a huge help for me.

    Is there an error in section 12?

    “On the Project Explorer window, expand the folder \SDK\platform\usb\device\sources. Create a folder under the sources folder called “classes”.”

    Looking at your project I downloaded the actual path seems to be.

    /K64F_USB_CDC/SDK/usb/usb_core/device/sources/classes

    Thanks again.
    Jim

    • 21/01/2016 at 13:28

      Thanks Jim, you are correct. I have updated the blog. I put this blog together in quite a rush as my time is very limited now days. I’m grateful for you pointing this out.

  4. 25/01/2016 at 16:05

    Hi, I noticed that SCANF does not echo the characters to the terminal, is that normal behaviour?

    Cheers
    Jim

    • 25/01/2016 at 17:12

      In terms of what the code is doing yes, but its easy enough to change this. I also had some annoyances with PRINTF and SCANF provided by the Kinetis SDK, namely it blocks on PRINTF until a terminal window is attached, but then it also fails to properly check in the SCANF if a terminal window is attached. All of this can be easily fixed by tweaking the code inside of the virtual_com.c file. Try look at that file for your self and if you don’t come right let me know and I’ll post some more info on exactly where to make the changes.

  5. Jiri N.
    12/03/2016 at 10:01

    Hi, thanks ever so much for this guide. It was my first affair with USB in more complex devices and your tutorial guided me through all the “minor details” rarely mentioned elsewhere.

  6. Ian N
    29/07/2016 at 14:05

    Hi, Great guide.
    Just wondered how you solved the blocking issue with the PRINTF, I can see the issue with the VirtualCom_SendDataBlocking function but my attempts at a solution stop the port initialising.

    • 29/07/2016 at 16:45

      Look inside the file /SDK/platform/utilities/src/virtual_com.c. Inside this file search for the function VirtualCom_SendDataBlocking(…). The first line of this function performs an endless while loop until a terminal app is connected to the port. Change this into an if check instead of while loop. Code will look as follows then:

      void VirtualCom_SendDataBlocking(uint32_t baseAddr, const uint8_t *buf, uint32_t count)
      {
      if (USB_Check_Start_Transactions())
      {
      USB_Class_CDC_Send_Data( (cdc_handle_t)baseAddr, DIC_BULK_IN_ENDPOINT, (uint8_t *)buf, count);
      while (!send_complete);
      send_complete = 0;
      }
      }

      • Ian N
        01/08/2016 at 10:42

        great, thanks. All working well now.

  7. Kiran
    23/08/2016 at 18:47

    Excellent tutorial. Helped me a lot in my custom board. Could you provide help in tweaking the code for SCANF?

    • 24/08/2016 at 11:32

      Hi Kiran. Sorry I haven’t been working on this for some time now but from what I remember if PRINTF is working then SCANF should be working as well except I think the first line in the function VirtualCom_SendDataBlocking() in the file \SDK\platform\uilities\src\virtual_com.c might need paying attention to, this function is ultimately the real logic that performs the SCANF. That first line should block the app from proceeding any further until a key is pressed. Just check its logic and make sure its doing what you expect.
      Another area I think that might cause issues is in the function USB_App_Class_Callback() in that same file. put a break point in this function and debug it to check if it is doing what you expect, I seem to remember having to debug some of the logic there but I can’t remember what it was or why.

      Sorry I know my answer isn’t directly helpful but its just been so long. I hope I have given some ideas on where to start looking to debug your issue.

      • Kiran
        24/08/2016 at 16:47

        Thank you for the quick reply. I got it figured out.

  8. Swapnil Vir Lal
    20/03/2017 at 08:58

    My USB_CDC project is running well on Kl26Z (64 pin IC package) development board which is having 8Mhz external crystal. I have similar set-up on custom board with Kl26Z (48 pin IC package) and 16mhz crystal. and my example code is not running. I am unable to debug where I am making mistake. Can anybody help me?

  9. grant
    11/04/2017 at 16:52

    Do you have any suggestions on how to get this working with the FreeRTOS component? I’m having problems getting the USB identified properly by the PC when I incorporate the FreeRTOS.

    Thank you.

    • 12/04/2017 at 07:12

      Unfortunately I have not had this problem myself. I had no real issues using this with FreeRTOS, all I can suggest is to double check all your configurations again. Sorry I can’t help.

  1. No trackbacks yet.

Leave a Reply

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

%d bloggers like this: