This tutorial was extracted from Erich Styger blog http://mcuoneclipse.wordpress.com with his agreement.
In “A shell for the Freedom board” I used the UART-to-USB OpenSDA capability of the Freescale FRDM-KL25Z FRDM-KL25Z Freedom board: The KL25Z processor uses the OpenSDA K20 microprocessor as Serial-to-USB converter. But this only works because of the P&E OpenSDA USB CDC (Communication Device Class) implementation. If I create my board without OpenSDA, I need a different approach: I want to do USB CDC with the KL25Z.
For several months I’m using successfully my Processor Expert FSL_USB_CDC component since early this year, in several projects and with different boards. What is missing is support for the Kinetis KL25Z. So this is what this tutorial is about. It takes you maybe around 30 minutes, and you will have USB support with your Freedom board. As for myself, after learning all the knowledge needed, it takes me less than 10 minutes.
I’m using CodeWarrior for MCU10.3 with my Processor Expert components. If you followed my earlier Freedom Board tutorials, then I hope you are familiar with loading more user components. Otherwise, have a look at the section “Additional Processor Expert Component Installation” in this post. In this tutorial I’m using following components:
- FSL_USB_Stack: Freescale USB Stack as Processor Expert component.
- Wait: Universal realtime waiting functions.
- Optional: LED: Universal LED driver.
The FSL_USB_Stack Processor Expert component has been updated to version V1.008 to support the KL25Z
Step 1: Creating the Project (or reuse an existing one)
In this tutorial I start from a clean sheet and create a new project. Of course it is possible to add USB CDC support to any of the other tutorials I have published for the Freedom KL25Z board, e.g. Tutorial: Enlightening the Freedom KL25Z Board. In that case, you can skip this step.
To create a new project, I select the menu File > New > Bareboard Project and give it a project name :
New Bareboard Project
Next is to select the device:
Selecting Device
I’m going to debug the board with OpenSDA only, so I deselect the default P&E Multilink, and select Open Source SDA:
OpenSDA Selection
The next dialog is about the language and build tools options: I go with the defaults:
Language and Build Tools Options
In the next dialog I make sure I select Processor Expert:
Processor Expert Project Option
Pressing Finish will create the project:
Project created
Hint: In case the extra Processor Expert views are not already open: I use the menu ‘Processor Expert > Show Views’.
Step 2: Adding the Components
The next step is to add my other component(s): I select the component(s) in the Components Library view and add it to my project. If I already have the Wait component in my project, of course no need to add it again.
Selecting and Adding Components
This will add the components to my project. And the USB component shows a red (x) telling me that it needs to be configured:
Need to configure the FSL_USB_Stack
I need to component Inspector to configure the properties.
Idea: The context menu ‘Inspector’ on a component opens the Component Inspector View.
If I inspect the properties of the USB component, it shows me that I need to set up the CPU and the USBInit property:
Need to configure component
So I select the CPU for my KL25Z board, and select Init_USB_OTG_VAR0 to initialize the USB peripheral for it:
USB component configured for KL25Z
No idea why Freescale has decided to name that Kinetis component as ‘Init_USB_OTG_VAR0′. A name like ‘Init_USB_OTG_Kinetis’ would have been *much* easier to use and remember.
The next thing is to inspect the USBInit component. And it is good to pay close attention to the warnings:
Warnings in USBInit
Enabling the Clock gateensures that the USB module is clocked. And as I have no external clock pin, I select to use the PLL/FLL clock source:
Enabled Clock Gate and configured clock source
The inspector informs me about a very important thing: the USB module requires a 48 MHz clock. So I need to make sure that this is configured properly.
Warning: Failing to configure the USB clock properly is probably the most common source of failure. For myself I can count endless hours debugging and inspecting my projects, and in many cases I made a mistake in the clock configuration. Unlike many other USB enabled devices, the Freescale ones need an external crystal, and that crystal has to be used to generate a very stable and accurate clock signal. Otherwise it will *not* work.
Step 3: Configuring the Clock
According to the FRDM-KL25Z Schematics (SPF-27556_D).pdf have a 8 MHz crystal on the board:
8 MHz Crystal on FRDM-KL25Z
IMPORTANT: I’m using in this post the ‘white’ pre-production Freedom Board. The black production board board has several differences (see Completing the FRDM-KL25Z Board). An important difference is that the black board has the 1.0MOhm resistor R25 nearby the 8 MHz: with that resistor *not* populated, the clock will *not* run in high gain mode. So for the black Freedom board with that resistor *not* populated, the clock mode has to be in ‘low power’ mode.
The configuration of the clock is in the CPU component. For this I select the CPU to configure the properties:
CPU component to configure the clocks
I can have multiple oscillator settings, but here I just need one. So I enable the ‘System oscillator 0′ setting, and configure it to use an 8 MHz external crystal in High gain mode (for the white pre-production board which has the R25 (see above) populated, but in Low Power mode for the black production board:
Setting 8 MHz external crystal with High Gain (White board only!!!)
As the black Freedom board has no R25 populated, the Oscillator operating mode has to be ‘Low power’ instead:
Low Power Oscillator Mode required if R25 not populated (black Freedom board)
Next is to select the PEE (PLL Engaged External) clock mode: in this mode, the PLL is using the external reference clock. Remember that the USB block needs an 48 MHz PLL signal? So I need to configure it to 96 MHz as it will be divided by a factor of 2 until it reaches the USB block:
PEE MCG Mode
With my clock changes, the core clock is not set correctly:
Error for core clock
With my base clock of 8 MHz, I can set the CPU core clock to 48 MHz and a Bus clock of 24 MHz:
Core and Bus Clock
Now I could think that everything is just fine. But there is one possible glitch, and maybe this is even a silicon problem (?): I need to *disable* the Internal and External reference clock, otherwise my board will crash during clock configuration. So I need to *disable* the reference clocks:
Internal and External Reference Clock disabled
Checking my USB module again, it shows that it is now properly clocked with 48 MHz:
USB with 48 MHz PLL clock
Processor Expert still warns about the need for 48 MHz clock, even I have it set up with 48 MHz? Anyway, the important thing is that it *is* clocked with 48 MHz.
Step 4: Adding Application Code
I keep things very simple here: no RTOS. All what I add in Processor Expert is a simple loop-back which does an echo of what I type into the terminal window.
To show the current enumeration status, I’m using my code from my earlier Tutorial: Enlightening the Freedom KL25Z Board.
Hint: An easy way to copy Processor Expert components from one project to another is using copy-paste. If you do not want to use the LEDs, then simply remove the code for the LEDs in the code below.
I’m adding the function CDC_Run()
to the ProcessorExpert.c
as below and call it from main()
:
001 | /** ################################################################### |
002 | ** Filename : ProcessorExpert.c |
003 | ** Project : ProcessorExpert |
004 | ** Processor : MKL25Z128VLK4 |
005 | ** Version : Driver 01.01 |
006 | ** Compiler : GNU C Compiler |
007 | ** Date/Time : 2012-10-07, 12:33, # CodeGen: 0 |
008 | ** Abstract : |
009 | ** Main module. |
010 | ** This module contains user's application code. |
011 | ** Settings : |
012 | ** Contents : |
013 | ** No public methods |
014 | ** |
015 | ** ###################################################################*/ |
016 | /* MODULE ProcessorExpert */ |
017 |
018 | /* Including needed modules to compile this module/procedure */ |
019 | #include "Cpu.h" |
020 | #include "Events.h" |
021 | #include "WAIT1.h" |
022 | #include "USB1.h" |
023 | #include "USBInit1.h" |
024 | #include "Tx1.h" |
025 | #include "Rx1.h" |
026 | #include "LED1.h" |
027 | #include "LED2.h" |
028 | #include "LED3.h" |
029 | #include "GPIO1.h" |
030 | #include "GPIO2.h" |
031 | /* Including shared modules, which are used for whole project */ |
032 | #include "PE_Types.h" |
033 | #include "PE_Error.h" |
034 | #include "PE_Const.h" |
035 | #include "IO_Map.h" |
036 |
037 | /* User includes (#include below this line is not maintained by Processor Expert) */ |
038 | static uint8_t cdc_buffer[USB1_DATA_BUFF_SIZE]; |
039 | static uint8_t in_buffer[USB1_DATA_BUFF_SIZE]; |
040 |
041 | static void CDC_Run( void ) { |
042 | int i; |
043 |
044 | for (;;) { |
045 | while (USB1_App_Task(cdc_buffer, sizeof (cdc_buffer))==ERR_BUSOFF) { |
046 | /* device not enumerated */ |
047 | LED1_Neg(); LED2_Off(); |
048 | WAIT1_Waitms(10); |
049 | } |
050 | LED1_Off(); LED2_Neg(); |
051 | if (USB1_GetCharsInRxBuf()!=0) { |
052 | i = 0; |
053 | while ( i< sizeof (in_buffer)-1 |
054 | && USB1_GetChar(&in_buffer[i])==ERR_OK |
055 | ) |
056 | { |
057 | i++; |
058 | } |
059 | in_buffer[i] = '\0' ; |
060 | ( void )USB1_SendString((unsigned char *) "echo: " ); |
061 | ( void )USB1_SendString(in_buffer); |
062 | ( void )USB1_SendString((unsigned char *) "\r\n" ); |
063 | } else { |
064 | WAIT1_Waitms(10); |
065 | } |
066 | } |
067 | } |
068 |
069 | /*lint -save -e970 Disable MISRA rule (6.3) checking. */ |
070 | int main( void ) |
071 | /*lint -restore Enable MISRA rule (6.3) checking. */ |
072 | { |
073 | /* Write your local variable definition here */ |
074 |
075 | /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/ |
076 | PE_low_level_init(); |
077 | /*** End of Processor Expert internal initialization. ***/ |
078 |
079 | CDC_Run(); |
080 |
081 | /*** Don't write any code pass this line, or it will be deleted during code generation. ***/ |
082 | /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/ |
083 | #ifdef PEX_RTOS_START |
084 | PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */ |
085 | #endif |
086 | /*** End of RTOS startup code. ***/ |
087 | /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/ |
088 | for (;;){} |
089 | /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/ |
090 | } /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/ |
091 |
092 | /* END ProcessorExpert */ |
093 | /* |
094 | ** ################################################################### |
095 | ** |
096 | ** This file was created by Processor Expert 10.0 [05.03] |
097 | ** for the Freescale Kinetis series of microcontrollers. |
098 | ** |
099 | ** ################################################################### |
100 | */ |
Step 5: Running the Application
Now I can generate code for my drivers, e.g right click on the ProcessorExpert.pe file and selecting "Generate Processor Expert Code":
Generate Processor Expert Code
Followed by building the sources (menu Project > Build Project ). And then download/debug it.
With the USB plug disconnected, the red LED is on:
USB disconnected: red LED on
With connecting the USB cable to the KL25Z, it enumerates the device and the green LED is on:
USB enumerated: green LED on
Additionally it has been enumerated as device on my host machine:
Freescale CDC Device
In case it is the first time you use such a CDC device: the driver .inf file is generated in the ‘Documentation’ folder (for details see USB CDC, reloaded):
cdc.inf driver files
I connect to the virtual CDC COM port with a terminal program. And the application will echo what I send to it:
Terminal Connection with Echo
Summary
Setting up and using an USB stack is definitely not a trivial task, as a lot of settings needs to work correctly. I hope that with the above information it should be much easier to do this now for the Freescale FRDM-KL25Z board. Using Processor Expert makes things definitely a lot easier. While the above project is bare-metal (no RTOS), it is easy to add an RTOS to it. That’s actually how I use it like in the Freedom Shell project.
The above project can be downloaded here or from the link on http://www.steinerberg.com/EmbeddedComponents/Examples/Examples.htm