Getting Kinetis SDK examples to work on the Teensy

Status
Not open for further replies.
Not entirely sure if this is useful to anyone else, but I figured I’d rather over-share than under-share in this case.

On NXP’s MCUXpresso website (https://mcuxpresso.nxp.com/en/dashboard), you can obtain examples for the KSDK (version 2.3.0 is current at the time of writing). Unfortunately, the only supported boards are the TWR-K65F180M and the FRDM-K66F, not the Teensy 3.6.

To get the “hello world” example to work on the Teensy, I did the following steps:

1. Adapt the clock configuration for the Teensy’s 16 MHz crystal (the FRDM-K66F uses a 12 MHz crystal):
Code:
diff --git i/board/clock_config.c w/board/clock_config.c
index 805191d..f8a4e7b 100644
--- i/board/clock_config.c
+++ w/board/clock_config.c
@@ -173,8 +173,8 @@ const mcg_config_t mcgConfig_BOARD_BootClockHSRUN =
         .pll0Config =
             {
                 .enableMode = MCG_PLL_DISABLE,    /* MCGPLLCLK disabled */
-                .prdiv = 0x0U,                    /* PLL Reference divider: divided by 1 */
-                .vdiv = 0xeU,                     /* VCO divider: multiplied by 30 */
+                .prdiv = 1,                    /* PLL Reference divider: divided by 1 */
+                .vdiv = 29,                     /* VCO divider: multiplied by 30 */
             },
         .pllcs = kMCG_PllClkSelPll0,              /* PLL0 output clock is selected */
     };

2. Fix the UART setup. Not entirely sure why it’s broken as-is:
Code:
diff --git i/drivers/fsl_uart.c w/drivers/fsl_uart.c
index 819a179..f4511ea 100644
--- i/drivers/fsl_uart.c
+++ w/drivers/fsl_uart.c
@@ -265,8 +265,9 @@ status_t UART_Init(UART_Type *base, const uart_config_t *config, uint32_t srcClo
     base->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK);
 
     /* Write the sbr value to the BDH and BDL registers*/
-    base->BDH = (base->BDH & ~UART_BDH_SBR_MASK) | (uint8_t)(sbr >> 8);
-    base->BDL = (uint8_t)sbr;
+    uint32_t divisor = (((SystemCoreClock * 2) + (config->baudRate_Bps >> 1)) / config->baudRate_Bps);
+    base->BDH = (divisor >> 13) & 0x1F;
+    base->BDL = (divisor >> 5) & 0xFF;
 
 #if defined(FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT) && FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT
     /* Write the brfa value to the register*/

3. I also set the board into HSRUN, and I’m not sure if that’s strictly required. I’ll include it to be on the safe side:
Code:
diff --git i/source/hello_world.c w/source/hello_world.c
index 4e43577..9c9e055 100644
--- i/source/hello_world.c
+++ w/source/hello_world.c
@@ -59,7 +59,7 @@ int main(void)
 
     /* Init board hardware. */
     BOARD_InitPins();
-    BOARD_BootClockRUN();
+    BOARD_BootClockHSRUN();
     BOARD_InitDebugConsole();
 
     PRINTF("hello world.\r\n");

4. On Linux, I made the following changes so that the example would pick up the system installation of the ARM cross-compiler (installed from the Debian packages gcc-arm-none-eabi and libnewlib-arm-none-eabi):

Code:
---
 armgcc.cmake | 27 +++++++++------------------
 1 file changed, 9 insertions(+), 18 deletions(-)

diff --git a/armgcc.cmake b/armgcc.cmake
index 1a11fc7..ce61594 100644
--- a/armgcc.cmake
+++ b/armgcc.cmake
@@ -11,31 +11,21 @@ ENDIF()
 SET (CMAKE_EXECUTABLE_SUFFIX ".elf")
 
 # TOOLCHAIN_DIR AND NANO LIBRARY
-SET(TOOLCHAIN_DIR $ENV{ARMGCC_DIR})
-STRING(REGEX REPLACE "\\\\" "/" TOOLCHAIN_DIR "${TOOLCHAIN_DIR}")
-
-IF(NOT TOOLCHAIN_DIR)
-    MESSAGE(FATAL_ERROR "***Please set ARMGCC_DIR in envionment variables***")
-ENDIF()
-
-MESSAGE(STATUS "TOOLCHAIN_DIR: " ${TOOLCHAIN_DIR})
+#SET(TOOLCHAIN_DIR $ENV{ARMGCC_DIR})
+#STRING(REGEX REPLACE "\\\\" "/" TOOLCHAIN_DIR "${TOOLCHAIN_DIR}")
 
 # TARGET_TRIPLET
 SET(TARGET_TRIPLET "arm-none-eabi")
 
-SET(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_DIR}/bin)
-SET(TOOLCHAIN_INC_DIR ${TOOLCHAIN_DIR}/${TARGET_TRIPLET}/include)
-SET(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_DIR}/${TARGET_TRIPLET}/lib)
-
 SET(CMAKE_SYSTEM_NAME Generic)
 SET(CMAKE_SYSTEM_PROCESSOR arm)
 
-CMAKE_FORCE_C_COMPILER(${TOOLCHAIN_BIN_DIR}/${TARGET_TRIPLET}-gcc${TOOLCHAIN_EXT} GNU)
-CMAKE_FORCE_CXX_COMPILER(${TOOLCHAIN_BIN_DIR}/${TARGET_TRIPLET}-g++${TOOLCHAIN_EXT} GNU)
-SET(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TARGET_TRIPLET}-gcc${TOOLCHAIN_EXT})
+CMAKE_FORCE_C_COMPILER(/usr/bin/arm-none-eabi-gcc GNU)
+CMAKE_FORCE_CXX_COMPILER(/usr/bin/arm-none-eabi-g++ GNU)
+SET(CMAKE_ASM_COMPILER /usr/bin/arm-none-eabi-gcc)
 
-SET(CMAKE_OBJCOPY ${TOOLCHAIN_BIN_DIR}/${TARGET_TRIPLET}-objcopy CACHE INTERNAL "objcopy tool")
-SET(CMAKE_OBJDUMP ${TOOLCHAIN_BIN_DIR}/${TARGET_TRIPLET}-objdump CACHE INTERNAL "objdump tool")
+SET(CMAKE_OBJCOPY /usr/bin/arm-none-eabi-objcopy CACHE INTERNAL "objcopy tool")
+SET(CMAKE_OBJDUMP /usr/bin/arm-none-eabi-objdump CACHE INTERNAL "objdump tool")
 
 SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g" CACHE INTERNAL "c compiler flags debug")
 SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g" CACHE INTERNAL "cxx compiler flags debug")
@@ -47,7 +37,8 @@ SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 " CACHE INTERNAL "cx
 SET(CMAKE_ASM_FLAGS_RELEASE "${CMAKE_ASM_FLAGS_RELEASE}" CACHE INTERNAL "asm compiler flags release")
 SET(CMAKE_EXE_LINKER_FLAGS_RELESE "${CMAKE_EXE_LINKER_FLAGS_RELESE}" CACHE INTERNAL "linker flags release")
 
-SET(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_DIR}/${TARGET_TRIPLET} ${EXTRA_FIND_PATH})
+# SET(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_DIR}/${TARGET_TRIPLET} ${EXTRA_FIND_PATH})
+SET(CMAKE_FIND_ROOT_PATH ${EXTRA_FIND_PATH})
 SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
 SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-- 
2.15.0

5: To convert the ELF file into a hex file as expected by the teensy loader, I used:
Code:
% arm-none-eabi-objcopy -O ihex -R .eeprom DEBUG/hello_world.elf /tmp/hello_world.hex

6: To flash the program onto the Teensy 3.6, I used:
Code:
% teensy_loader_cli/teensy_loader_cli -w -v --mcu=TEENSY36 /tmp/hello_world.hex

Note that further fixes might be required for other examples, but with the above fixes, I do see the hello world string on the serial console.

Hope that helps,
 
Hmm, there is nothing wrong with the UART code in my SDK, i thing your clock configuration is wrong. I have attached a new clock configuration made for Teeny3.6.

It contains 3 different functions (speeds) you can use as you wish. And HS mode does matter, you need different divisors etc.. It also looks wrong in the startup code in the Tensyduino source, the VDIV is set to 29 and should be 45 according to the MCUXpresso clock tool, so the actual clock is 116 Mhz if you select 180 Mhz in the Arduino tools if i'm correct :)

BOARD_BootClockRUN(); 120 Mhz
BOARD_BootClockRUN_HS(); 180 Mhz
BOARD_BootClockRUN_VLPR(); 4 Mhz (low power mode)

View attachment clock_config.c
View attachment clock_config.h

Not entirely sure if this is useful to anyone else, but I figured I’d rather over-share than under-share in this case.

On NXP’s MCUXpresso website (https://mcuxpresso.nxp.com/en/dashboard), you can obtain examples for the KSDK (version 2.3.0 is current at the time of writing). Unfortunately, the only supported boards are the TWR-K65F180M and the FRDM-K66F, not the Teensy 3.6.

To get the “hello world” example to work on the Teensy, I did the following steps:

1. Adapt the clock configuration for the Teensy’s 16 MHz crystal (the FRDM-K66F uses a 12 MHz crystal):
Code:
diff --git i/board/clock_config.c w/board/clock_config.c
index 805191d..f8a4e7b 100644
--- i/board/clock_config.c
+++ w/board/clock_config.c
@@ -173,8 +173,8 @@ const mcg_config_t mcgConfig_BOARD_BootClockHSRUN =
         .pll0Config =
             {
                 .enableMode = MCG_PLL_DISABLE,    /* MCGPLLCLK disabled */
-                .prdiv = 0x0U,                    /* PLL Reference divider: divided by 1 */
-                .vdiv = 0xeU,                     /* VCO divider: multiplied by 30 */
+                .prdiv = 1,                    /* PLL Reference divider: divided by 1 */
+                .vdiv = 29,                     /* VCO divider: multiplied by 30 */
             },
         .pllcs = kMCG_PllClkSelPll0,              /* PLL0 output clock is selected */
     };

2. Fix the UART setup. Not entirely sure why it’s broken as-is:
Code:
diff --git i/drivers/fsl_uart.c w/drivers/fsl_uart.c
index 819a179..f4511ea 100644
--- i/drivers/fsl_uart.c
+++ w/drivers/fsl_uart.c
@@ -265,8 +265,9 @@ status_t UART_Init(UART_Type *base, const uart_config_t *config, uint32_t srcClo
     base->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK);
 
     /* Write the sbr value to the BDH and BDL registers*/
-    base->BDH = (base->BDH & ~UART_BDH_SBR_MASK) | (uint8_t)(sbr >> 8);
-    base->BDL = (uint8_t)sbr;
+    uint32_t divisor = (((SystemCoreClock * 2) + (config->baudRate_Bps >> 1)) / config->baudRate_Bps);
+    base->BDH = (divisor >> 13) & 0x1F;
+    base->BDL = (divisor >> 5) & 0xFF;
 
 #if defined(FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT) && FSL_FEATURE_UART_HAS_BAUD_RATE_FINE_ADJUST_SUPPORT
     /* Write the brfa value to the register*/

3. I also set the board into HSRUN, and I’m not sure if that’s strictly required. I’ll include it to be on the safe side:
Code:
diff --git i/source/hello_world.c w/source/hello_world.c
index 4e43577..9c9e055 100644
--- i/source/hello_world.c
+++ w/source/hello_world.c
@@ -59,7 +59,7 @@ int main(void)
 
     /* Init board hardware. */
     BOARD_InitPins();
-    BOARD_BootClockRUN();
+    BOARD_BootClockHSRUN();
     BOARD_InitDebugConsole();
 
     PRINTF("hello world.\r\n");

4. On Linux, I made the following changes so that the example would pick up the system installation of the ARM cross-compiler (installed from the Debian packages gcc-arm-none-eabi and libnewlib-arm-none-eabi):

Code:
---
 armgcc.cmake | 27 +++++++++------------------
 1 file changed, 9 insertions(+), 18 deletions(-)

diff --git a/armgcc.cmake b/armgcc.cmake
index 1a11fc7..ce61594 100644
--- a/armgcc.cmake
+++ b/armgcc.cmake
@@ -11,31 +11,21 @@ ENDIF()
 SET (CMAKE_EXECUTABLE_SUFFIX ".elf")
 
 # TOOLCHAIN_DIR AND NANO LIBRARY
-SET(TOOLCHAIN_DIR $ENV{ARMGCC_DIR})
-STRING(REGEX REPLACE "\\\\" "/" TOOLCHAIN_DIR "${TOOLCHAIN_DIR}")
-
-IF(NOT TOOLCHAIN_DIR)
-    MESSAGE(FATAL_ERROR "***Please set ARMGCC_DIR in envionment variables***")
-ENDIF()
-
-MESSAGE(STATUS "TOOLCHAIN_DIR: " ${TOOLCHAIN_DIR})
+#SET(TOOLCHAIN_DIR $ENV{ARMGCC_DIR})
+#STRING(REGEX REPLACE "\\\\" "/" TOOLCHAIN_DIR "${TOOLCHAIN_DIR}")
 
 # TARGET_TRIPLET
 SET(TARGET_TRIPLET "arm-none-eabi")
 
-SET(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_DIR}/bin)
-SET(TOOLCHAIN_INC_DIR ${TOOLCHAIN_DIR}/${TARGET_TRIPLET}/include)
-SET(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_DIR}/${TARGET_TRIPLET}/lib)
-
 SET(CMAKE_SYSTEM_NAME Generic)
 SET(CMAKE_SYSTEM_PROCESSOR arm)
 
-CMAKE_FORCE_C_COMPILER(${TOOLCHAIN_BIN_DIR}/${TARGET_TRIPLET}-gcc${TOOLCHAIN_EXT} GNU)
-CMAKE_FORCE_CXX_COMPILER(${TOOLCHAIN_BIN_DIR}/${TARGET_TRIPLET}-g++${TOOLCHAIN_EXT} GNU)
-SET(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TARGET_TRIPLET}-gcc${TOOLCHAIN_EXT})
+CMAKE_FORCE_C_COMPILER(/usr/bin/arm-none-eabi-gcc GNU)
+CMAKE_FORCE_CXX_COMPILER(/usr/bin/arm-none-eabi-g++ GNU)
+SET(CMAKE_ASM_COMPILER /usr/bin/arm-none-eabi-gcc)
 
-SET(CMAKE_OBJCOPY ${TOOLCHAIN_BIN_DIR}/${TARGET_TRIPLET}-objcopy CACHE INTERNAL "objcopy tool")
-SET(CMAKE_OBJDUMP ${TOOLCHAIN_BIN_DIR}/${TARGET_TRIPLET}-objdump CACHE INTERNAL "objdump tool")
+SET(CMAKE_OBJCOPY /usr/bin/arm-none-eabi-objcopy CACHE INTERNAL "objcopy tool")
+SET(CMAKE_OBJDUMP /usr/bin/arm-none-eabi-objdump CACHE INTERNAL "objdump tool")
 
 SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g" CACHE INTERNAL "c compiler flags debug")
 SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g" CACHE INTERNAL "cxx compiler flags debug")
@@ -47,7 +37,8 @@ SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 " CACHE INTERNAL "cx
 SET(CMAKE_ASM_FLAGS_RELEASE "${CMAKE_ASM_FLAGS_RELEASE}" CACHE INTERNAL "asm compiler flags release")
 SET(CMAKE_EXE_LINKER_FLAGS_RELESE "${CMAKE_EXE_LINKER_FLAGS_RELESE}" CACHE INTERNAL "linker flags release")
 
-SET(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_DIR}/${TARGET_TRIPLET} ${EXTRA_FIND_PATH})
+# SET(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_DIR}/${TARGET_TRIPLET} ${EXTRA_FIND_PATH})
+SET(CMAKE_FIND_ROOT_PATH ${EXTRA_FIND_PATH})
 SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
 SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-- 
2.15.0

5: To convert the ELF file into a hex file as expected by the teensy loader, I used:
Code:
% arm-none-eabi-objcopy -O ihex -R .eeprom DEBUG/hello_world.elf /tmp/hello_world.hex

6: To flash the program onto the Teensy 3.6, I used:
Code:
% teensy_loader_cli/teensy_loader_cli -w -v --mcu=TEENSY36 /tmp/hello_world.hex

Note that further fixes might be required for other examples, but with the above fixes, I do see the hello world string on the serial console.

Hope that helps,
 
stapelberg and Jacob.Schultz, thanks for your posts.

I've been trying to get a simple hello world/blinky application running on my Teensy 3.6 with dependencies only on the Kinetis SDK and the ARM GCC toolchain. i.e. I wish to avoid any dependencies on the Arduino IDE or Teensyduino libraries.

I've followed the steps above with the following modifications, but have not got it working. I configured PORT C pin 5 as GPIO (output), and replaced the PRINTF/GETCHAR/PUTCHAR statements with a call to turn on the LED attached to that pin. I did this because I haven't managed to get serial communication between my dev machine and the Teensy working (the USB connected Teensy doesn't appear as a device under "/dev", though this hasn't stopped me in the past interacting with the device using the Teensy Loader). I used the clock_config files provided by Jacob. I tried using fsl_uart.c unmodified, as well as modified as described above. I tried both BOARD_BootClockRUN() and BOARD_BootClockRUN_HS(). My dev platform is OSX (Sierra). I've tried a couple of versions of the ARM GCC toolchain including the current version available from developer.arm.com, and GNU ARM GCC v4.9.3. I'm using only cmake related tools from the command line to build. I have separately managed to get blinky type apps working that were compiled using Teensyduino, so my Teensy is functioning and not broken.

Can you please clarify if the success you achieved with the above approach avoids dependencies on Arduino/Teensyduino?

I'm partly using this exercise to help me understand the ARM cortex M4 boot sequence. My understanding of this process is uncertain and rudimentary at present. Despite that I've described it below, to give others a chance to correct me, and hopefully explain why the hello world app is not functioning as expected. The description includes references to the attached memory map file produced during my build.

  • The boot-loader copies the application code over USB to flash memory on the K66 MCU.
  • A reset is triggered
  • The 32 bit word at address 0x0000 is the address used to initialise the stack pointer
  • The 32 bit word at address 0x0004 is the address to the first code to be executed (the "Reset_Handler").
  • The memory map seems to confirm that the data located at 0x0000000000000000 is sourced from "__isr_vector" in startup_MK66F18.S. Checking that file confirms that the first long is the stack pointer (the symbol correspond to the value in the linker script, which I imagine is assigned a value during linking).
  • The memory map shows that the second long is the "Reset_Handler" address.
  • The Reset_Handler code (also sourced from startup_MK66F18.S.obj) can be seen in the memory map at address 0x00000000000004c4.
  • Among other things, the Reset_Handler code calls "_start", which is sourced from crt0.S, and is located at address 0x0000000000000450.
  • I have looked at a version of this file, but confess that I don't really understand what it does, or if I'm looking at the right version. At one point that contains the code "bl FUNCTION (main)". I suspect that this is implicated in causing "main" from the application code to be called.
  • As mentioned above my main function (and code it delegates to) configures the pin attached to the Teensy 3.6 LED and turns it on.

Thanks in advance for any help.
 

Attachments

  • output.map.txt
    81.2 KB · Views: 254
Last edited:
Hmm, there is nothing wrong with the UART code in my SDK, i thing your clock configuration is wrong. I have attached a new clock configuration made for Teeny3.6.

It contains 3 different functions (speeds) you can use as you wish. And HS mode does matter, you need different divisors etc.. It also looks wrong in the startup code in the Tensyduino source, the VDIV is set to 29 and should be 45 according to the MCUXpresso clock tool, so the actual clock is 116 Mhz if you select 180 Mhz in the Arduino tools if i'm correct :)

I think you must have made a mistake somewhere :).

I just connected my Hantek DSO to GND and a GPIO pin on the FRDM-K66F and on the Teensy 3.6. Then, I programmed the MCUs to set the GPIO pin high for 20ms, then low for 20ms, in an endless loop.

The results are:

The default clock configuration in the MCUXpresso SDK for the FRDM-K66F board (12 MHz crystal!) is correct.
The clock configuration when selecting 180 MHz in the Teensyduino IDE is correct.
My provided modification to make the SDK hello_world work on the Teensy 3.6 (16 MHz crystal!) is correct.

See http://t.zekjur.net/2018-01-06-clock-measurements/ for screenshots of my measurements.

Notably, without my modifications, the PLL doesn’t lock, and the hello_world just doesn’t run.

Measurement setup details:

My delay function uses the cycle counter:
Code:
#define ARM_DEMCR               (*(volatile uint32_t *)0xE000EDFC) // Debug Exception and Monitor Control
#define ARM_DEMCR_TRCENA                (1 << 24)        // Enable debugging & monitoring blocks
#define ARM_DWT_CTRL            (*(volatile uint32_t *)0xE0001000) // DWT control register
#define ARM_DWT_CTRL_CYCCNTENA          (1 << 0)                // Enable cycle count
#define ARM_DWT_CYCCNT          (*(volatile uint32_t *)0xE0001004) // Cycle count register

// delay sleeps for |cycles| (e.g. sleeping for F_CPU will sleep 1s).
// delay’s precision is ± 166 ns (due to 30 cycles of overhead).
void delay(const uint32_t cycles) {
  // Reset cycle counter
    
  ARM_DEMCR |= ARM_DEMCR_TRCENA;
  ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
  ARM_DWT_CYCCNT = 0;

  while (ARM_DWT_CYCCNT < cycles) {
    // busy-loop until time has passed
  }
}

To sleep 20ms on a system running at 180 MHz, I’m calling delay(180000000 / 50 /* 20ms */). If the system is not running at 180 MHz, the resulting delay will be measured at something else than 20ms by the oscilloscope.

It also looks wrong in the startup code in the Tensyduino source, the VDIV is set to 29 and should be 45 according to the MCUXpresso clock tool

You’re mixing up the logical value (multiply by 45) and the VDIV register value (dec 29), see the Registers tab in the clock tool: http://t.zekjur.net/2018-01-06-clock-config-vdiv.png
 
There is no dependencies at all. You can download a working example from the following link: https://drive.google.com/file/d/1VJDUJaGhVrZhsBgG9y9hnUlQUKuJilwT/view?usp=sharing
It's much easier to start on a working example than fighting at bricked Teensy/SDK. Believe me I've been there :) It is configured to 180 Mhz core and 60 Mhz bus speed and 1 ms systicks.

You only have to install cmake and do the following from the root folder:

export ARMGCC_DIR=/usr # your gcc location (dont include the bin dir)
./build_debug.sh
cd debug
arm-none-eabi-objcopy -O ihex -R .eeprom sdcard_fatfs.elf sdcard_fatfs.hex

use the teensyloader and burn the hex file.

It makes some speedtests on random algorithms and print the result on UART0 afterwards it will start blinking on the LED. if you want the original sdcard example you have to copy sdtest.c to main.c in the source folder and recompile the app.

board/bord.c - initializes the hardware.
fatfs/fatfs_include/ffconf.h - contains the fat configuration
drivers - contains the Kinetis SDK drivers, you have to add what you need from the SDK.

You can add/remove source files in CMakeList.txt if you want to continue with cmake.

Let me know if you have any problems.
 
Last edited:
I've followed the steps above with the following modifications, but have not got it working. I configured PORT C pin 5 as GPIO (output), and replaced the PRINTF/GETCHAR/PUTCHAR statements with a call to turn on the LED attached to that pin.

Here’s a known-working source/hello_world.c which blinks PTC5 every 1s:
Code:
#include "fsl_device_registers.h"
#include "fsl_debug_console.h"
#include "board.h"
#include "fsl_common.h"
#include "fsl_port.h"

#include "pin_mux.h"
#include "clock_config.h"
/*******************************************************************************
 * Definitions
 ******************************************************************************/

#include <stdint.h>

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

#define ARM_DEMCR               (*(volatile uint32_t *)0xE000EDFC) // Debug Exception and Monitor Control
#define ARM_DEMCR_TRCENA                (1 << 24)        // Enable debugging & monitoring blocks
#define ARM_DWT_CTRL            (*(volatile uint32_t *)0xE0001000) // DWT control register
#define ARM_DWT_CTRL_CYCCNTENA          (1 << 0)                // Enable cycle count
#define ARM_DWT_CYCCNT          (*(volatile uint32_t *)0xE0001004) // Cycle count register

// delay sleeps for |cycles| (e.g. sleeping for F_CPU will sleep 1s).
// delay’s precision is ± 166 ns (due to 30 cycles of overhead).
void delay(const uint32_t cycles) {
  // Reset cycle counter

  ARM_DEMCR |= ARM_DEMCR_TRCENA;
  ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
  ARM_DWT_CYCCNT = 0;

  while (ARM_DWT_CYCCNT < cycles) {
    // busy-loop until time has passed
  }
}

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Main function
 */
int main(void)
{
    char ch;

    /* Init board hardware. */
    CLOCK_EnableClock(kCLOCK_PortC);
    PORT_SetPinMux(PORTC, 5, kPORT_MuxAsGpio);

    BOARD_BootClockHSRUN();

    GPIO_PinWrite(GPIOC, 5, 0);
    GPIOC->PDDR |= (1U << 5);

    for (;;) {
        GPIO_PortClear(GPIOC, 1U << 5);
        delay(180000000); // 1s

        GPIO_PortSet(GPIOC, 1U << 5);
        delay(180000000); // 1s
    }
}


I did this because I haven't managed to get serial communication between my dev machine and the Teensy working (the USB connected Teensy doesn't appear as a device under "/dev", though this hasn't stopped me in the past interacting with the device using the Teensy Loader).

When pressing the program switch, the bootloader chip (see https://www.pjrc.com/store/ic_mkl02.html) runs a custom firmware (with working USB code) on the Teensy MCU.

The hello_world example does not contain any USB code, hence you don’t see a virtual serial console.

I tested the serial console by connecting a USB-to-serial (specifically https://learn.adafruit.com/adafruit-ft232h-breakout/serial-uart) to the pin header.

I used the clock_config files provided by Jacob.

Don’t do that, I believe they’re incorrect. See my other post.
 
The clock_config is generated with Kinetis own online tool and the speeds are verified. In addition, it uses safe divisors so you can change speeds on the fly without destroying it by accident. If you login on nxp.com and try it with teensyduino's (180 Mhz) parameters things don't add up, but i have more faith in the vendors own clock tool. I have not studied tensyduino closely yet.

The only way to hit a 180 Mhz clock in HS mode exactly with a 16 Mhz crystal with Kinetis tools is the following parameters:

MCG.VDIV.scale, value: '45'
MCG.PRDIV.scale, value: '2'
SIM.OUTDIV2.scale, value: '3' - gives 60 Mhz bus clock


* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!Configuration
name: BOARD_BootClockRUN_HS
description: 180 Mhz core / 60 Mhz bus
outputs:
- {id: Bus_clock.outFreq, value: 60 MHz}
- {id: Core_clock.outFreq, value: 180 MHz}
- {id: Flash_clock.outFreq, value: 180/7 MHz}
- {id: FlexBus_clock.outFreq, value: 60 MHz}
- {id: IRC48MCLK.outFreq, value: 48 MHz}
- {id: LPO_clock.outFreq, value: 1 kHz}
- {id: MCGFFCLK.outFreq, value: 250 kHz}
- {id: MCGIRCLK.outFreq, value: 32.768 kHz}
- {id: OSCERCLK.outFreq, value: 16 MHz}
- {id: OSCERCLK_UNDIV.outFreq, value: 16 MHz}
- {id: PLLFLLCLK.outFreq, value: 48 MHz}
- {id: System_clock.outFreq, value: 180 MHz}
- {id: USB48MCLK.outFreq, value: 48 MHz}
settings:
- {id: MCGMode, value: PEE}
- {id: powerMode, value: HSRUN}
- {id: MCG.FCRDIV.scale, value: '1', locked: true}
- {id: MCG.FLL_mul.scale, value: '640', locked: true}
- {id: MCG.FRDIV.scale, value: '64', locked: true}
- {id: MCG.IREFS.sel, value: MCG.FRDIV}
- {id: MCG.PLLS.sel, value: MCG.PLLCS}
- {id: MCG.PRDIV.scale, value: '2', locked: true}
- {id: MCG.VDIV.scale, value: '45', locked: true}
- {id: MCG_C1_IRCLKEN_CFG, value: Enabled}
- {id: MCG_C2_OSC_MODE_CFG, value: ModeOscLowPower}
- {id: MCG_C2_RANGE0_CFG, value: Very_high}
- {id: MCG_C2_RANGE0_FRDIV_CFG, value: Very_high}
- {id: OSC_CR_ERCLKEN_CFG, value: Enabled}
- {id: OSC_CR_ERCLKEN_UNDIV_CFG, value: Enabled}
- {id: RTC_CR_CLKO_CFG, value: Disabled}
- {id: RTC_CR_OSCE_CFG, value: Enabled}
- {id: SIM.LPUARTSRCSEL.sel, value: OSC.OSCERCLK}
- {id: SIM.OUTDIV2.scale, value: '3', locked: true}
- {id: SIM.OUTDIV3.scale, value: '3', locked: true}
- {id: SIM.OUTDIV4.scale, value: '7', locked: true}
- {id: SIM.PLLFLLSEL.sel, value: IRC48M.IRC48MCLK}
- {id: SIM.RTCCLKOUTSEL.sel, value: RTC.RTC32KCLK}
- {id: SIM.SDHCSRCSEL.sel, value: OSC.OSCERCLK}
- {id: SIM.USBDIV.scale, value: '1', locked: true}
- {id: SIM.USBFRAC.scale, value: '1', locked: true}
- {id: SIM.USBSRCSEL.sel, value: SIM.USBDIV}
- {id: USBClkConfig, value: 'yes'}
- {id: USBPHY.DIV.scale, value: '40', locked: true}
- {id: USBPHY.NO_DIV.scale, value: '1', locked: true}
- {id: USBPHY.PFD_CLK_SEL.sel, value: USBPHY.PFD_FRAC_DIV}
- {id: USBPHY.PFD_FRAC_DIV.scale, value: '24', locked: true}
sources:
- {id: IRC48M.IRC48M.outFreq, value: 48 MHz}
- {id: OSC.OSC.outFreq, value: 16 MHz, enabled: true}
- {id: RTC.RTC32kHz.outFreq, value: 32.768 kHz, enabled: true}
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
/* clang-format on */
 
Last edited:
Indeed anything over 120 MHz requires HS_RUN mode.

PJRC's clocking on the T_3.6's K66 work up to 180 MHz and the three OC'd steps above.

BTW: Thanks again Paul for doing all the heavy lifting and making this work well.
 
Jacob, stapelberg, thanks to you both for your responses.

Jacob, I downloaded the project files you linked, and the resulting app ran successfully without modification. Many thanks.

I analysed the differences between your project and mine, and realised that that the code that was stopping mine from working was the lack of a call to CLOCK_EnableClock(kCLOCK_PortC) (Port C being that used by the Teensy LED). I added that and my application works too.
 
Last edited:
- {id: USBPHY.DIV.scale, value: '40', locked: true}

This value seems incorrect to me. The clock config tool in MCUXpresso lists a multiplier of 30 for a 16 MHz input. pjrc’s USBHost_t36 also sets a multiplier of 30.

I haven’t checked the other values in detail, and I’ll stop posting in this thread, as I don’t see it going anywhere useful. I consider pjrc’s configuration canonical. My post listed listed the minimum required changes to make the FRDM-K66F clock config work with a Teensy 3.6 in the scope of the hello_world example. Other examples and features will need more changes.

I wish the Teensy just used the same oscillator as the FRDM-K66F. That way, the Kinetis examples would be much more compatible :).
 
Be carefull, Don't compare directly. pjrc are using raw register values and Kinetis are using macros to translate human readable values into register values.
So VDIV is 45 in Kinetis world AND and 29 in pjrc world.

But you right, is't not configured i planned to use the internal IRC48M.IRC48M.outFreq for USB for optimal speed. I think it's the only good solution for that clock configuration.
 
Last edited:
IRC48M clock works pefect with USB in current setup. (the highspeed host port needs a different setup)

You only have to define SDK_OS_BAREMETAL for usb_osa.h
and enable KHCI og disable EHCI in usb_device_config.h

/*! @brief KHCI instance count */
#define USB_DEVICE_CONFIG_KHCI (1U)

/*! @brief EHCI instance count */
#define USB_DEVICE_CONFIG_EHCI (0U)
 
Last edited:
Status
Not open for further replies.
Back
Top