Timing problem with Teensy 3.2

sbreheny

New member
Hi all,

I have a bizarre timing issue with a project which uses the (older) Teensy 3.2.

I am using IntervalTimer to trigger a portion of my main code once every 100us. This part of the code sets an IO pin high for 25us (using delayMicroseconds()) and then sets it low again, before waiting for the next trigger (via a flag variable) from the IntervalTimer ISR.

When I run this with F_CPU set to 48MHz, it works fine. The period of the output signal is 100us and the high portion is 25us.

When I change F_CPU to 72MHz, however, the period decreases to 75us and the high portion INCREASES to 37.5us. Note that neither of these changes follows the ratio of the F_CPU change (I increased F_CPU by 1.5, the IntervalTimer period changed by 0.75, and the delayMicroseconds is executing 1.5 times SLOWER)

I am changing F_CPU in the Makefile. The main.cpp file is not changed at all between the two test cases.

I did notice that IntervalTimer uses F_BUS and not F_CPU, and in kinetis.h, when F_CPU=48MHz, it sets F_BUS to 48MHz also, but if F_CPU=72MHz, it sets F_BUS to 36MHz, which seems like an odd thing to do. In any event, though, I would expect that IntervalTimer and delayMicroseconds would both compensate for the F_CPU and F_BUS settings as needed to maintain the correct timing.

Any idea what is wrong?

Thanks,

Sean

C++ source:

Code:
// NOTE: We have Teensy 3.2 with MK20DX256VLH7 processor
// which is has KINETISK defined


#include "WProgram.h"
#include "IntervalTimer.h"

#define PIN_EN_SPD_CTRL 0
#define PIN_EN_CURR_CTRL 1
#define PIN_TEST 2
#define PIN_SPD_CURR_SEL 3
#define PIN_OL_WARN 4
#define PIN_OL_FAULT 5
#define PIN_UNUSED0 6
#define PIN_UNUSED1 7
#define PIN_UNUSED2 8
#define PIN_PWM_SPD 9
#define PIN_PWM_CURR 10
#define PIN_UNUSED3 11
#define PIN_UNUSED4 12
#define PIN_LED_CTRL 13
#define PIN_UNUSED5 14
#define PIN_UNUSED6 15
#define PIN_ENCA 16
#define PIN_ENCB 17
#define PIN_A_CURR_FB 18
#define PIN_A_SPD_CMD 19
#define PIN_A_CURR_CMD 20
#define PIN_UNUSED7 21
#define PIN_UNUSED8 22
#define PIN_UNUSED9 23


volatile uint8_t timerflag=0;

IntervalTimer myTimer;

void mytimerfunction ( void )
{
	timerflag=1;
	
}

int main(void)
{
	
		
	
	pinMode(PIN_OL_WARN, OUTPUT);
	pinMode(PIN_OL_FAULT, OUTPUT);
	pinMode(PIN_UNUSED0, OUTPUT);
	pinMode(PIN_LED_CTRL, OUTPUT);
		
	myTimer.begin(mytimerfunction,100); // Interrupt happens every 100 microseconds
	
	// LAMP TEST
	digitalWriteFast(PIN_LED_CTRL, HIGH);
	digitalWriteFast(PIN_OL_WARN, HIGH);
	digitalWriteFast(PIN_OL_FAULT, HIGH);
	
	delay(1000);
	
	// END LAMP TEST
	digitalWriteFast(PIN_LED_CTRL, LOW);
	digitalWriteFast(PIN_OL_WARN, LOW);
	digitalWriteFast(PIN_OL_FAULT, LOW);
	
	while (1)
	{
		while(!timerflag);
		timerflag=0;
		digitalWriteFast(PIN_UNUSED0,HIGH);
		delayMicroseconds(25);
		digitalWriteFast(PIN_UNUSED0,LOW);
	}	


}

Makefile (the only thing I am changing is the -DF_CPU setting)

Code:
# set your MCU type here, or make command line `make MCU=MK20DX256`
MCU=MK20DX256

# make it lower case
LOWER_MCU := $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(MCU)))))))))))))))))))))))))))
MCU_LD = $(LOWER_MCU).ld

# The name of your project (used to name the compiled .hex file)
TARGET = main

# Those that specify a NO_ARDUINO environment variable will
# be able to use this Makefile with no Arduino dependency.
# Please note that if ARDUINOPATH was set, it will override
# the NO_ARDUINO behaviour.
ifndef NO_ARDUINO
$(warning I see it)
# Path to your arduino installation
ARDUINOPATH ?= ~/Desktop/teensyutils/arduino-1.8.5
#ARDUINOPATH ?= ../../../..
endif

# configurable options
OPTIONS = -DF_CPU=72000000 -DLAYOUT_US_ENGLISH -DUSING_MAKEFILE

# options needed by many Arduino libraries to configure for Teensy 3.0
OPTIONS += -D__$(MCU)__ -DARDUINO=10613 -DTEENSYDUINO=132


# Other Makefiles and project templates for Teensy 3.x:
#
# https://github.com/apmorton/teensy-template
# https://github.com/xxxajk/Arduino_Makefile_master
# https://github.com/JonHylands/uCee


#************************************************************************
# Location of Teensyduino utilities, Toolchain, and Arduino Libraries.
# To use this makefile without Arduino, copy the resources from these
# locations and edit the pathnames.  The rest of Arduino is not needed.
#************************************************************************

ifdef ARDUINOPATH

# path location for Teensy Loader, teensy_post_compile and teensy_reboot (on Linux)
TOOLSPATH = $(abspath $(ARDUINOPATH)/hardware/tools)

# path location for Arduino libraries (currently not used)
LIBRARYPATH = $(abspath $(ARDUINOPATH)/libraries)

# path location for the arm-none-eabi compiler
COMPILERPATH = $(ARDUINOPATH)/hardware/tools/arm/bin

else
# Default to the normal GNU/Linux compiler path if NO_ARDUINO
# and ARDUINOPATH was not set.
COMPILERPATH ?= "/home/sbreheny/Desktop/teensy utils/arduino-1.8.5/hardware/tools/arm/bin/"

endif

#************************************************************************
# Settings below this point usually do not need to be edited
#************************************************************************

# CPPFLAGS = compiler options for C and C++
CPPFLAGS = -Wall -g -Os -mcpu=cortex-m4 -mthumb -MMD $(OPTIONS) -I.

# compiler options for C++ only
CXXFLAGS = -std=gnu++0x -felide-constructors -fno-exceptions -fno-rtti

# compiler options for C only
CFLAGS =

# linker options
LDFLAGS = -Os -Wl,--gc-sections,--defsym=__rtc_localtime=0 --specs=nano.specs -mcpu=cortex-m4 -mthumb -T$(MCU_LD)

# additional libraries to link
LIBS = -lm


# names for the compiler programs
CC = $(COMPILERPATH)/arm-none-eabi-gcc
CXX = $(COMPILERPATH)/arm-none-eabi-g++
OBJCOPY = $(COMPILERPATH)/arm-none-eabi-objcopy
SIZE = $(COMPILERPATH)/arm-none-eabi-size

$(warning see:$(ARDUINOPATH))

# automatically create lists of the sources and objects
# TODO: this does not handle Arduino libraries yet...
C_FILES := $(wildcard *.c)
CPP_FILES := $(wildcard *.cpp)
OBJS := $(C_FILES:.c=.o) $(CPP_FILES:.cpp=.o)


# the actual makefile rules (all .o files built by GNU make's default implicit rules)

all: $(TARGET).hex

$(TARGET).elf: $(OBJS) $(MCU_LD)
	$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)

%.hex: %.elf
	$(SIZE) $<
	$(OBJCOPY) -O ihex -R .eeprom $< $@
ifneq (,$(wildcard $(TOOLSPATH)))
	$(TOOLSPATH)/teensy_post_compile -file=$(basename $@) -path=$(shell pwd) -tools=$(TOOLSPATH)
	-$(TOOLSPATH)/teensy_reboot
endif

# compiler generated dependency info
-include $(OBJS:.o=.d)

clean:
	rm -f *.o *.d $(TARGET).elf $(TARGET).hex

Running at 48MHz:
scope_11.png

Running at 72MHz:
scope_10.png
 
I tested your your code and can not reproduce the effect. It generates a nice 10kHz signal with 25µs HIGH time for F_CPU = 48MHz, 72MHz and 96MHz
 
I think I know what is going on here: Looks like you compiled with -DF_CPU=48000000 which worked. Then you just changed your makefile to -DF_CPU=72000000 and recompiled without a 'make clean'. Thus the core was not recompiled (object files were newer than source files) and has still F_BUS = F_CPU = 48MHz compiled in. However, any code which uses F_BUS after you recompiled main.cpp will use F_BUS=36MHz. E.g. intervalTimer::begin will calculate the the required clock periods using F_BUS=36MHz but the timer still runs at 48MHz. Thus the actual period will be 100µs / 48 x 36 = 75µs which you observe.

I tested this and can produce exactly your observation if I do the following

- compile at 48Mhz,
- thouch main
- recompile with F_CPU = 72Mhz (this recompiles main.cpp only)

-> Always do a 'make clean' if you change compiler flags
 
Last edited:
Bingo! That was it! Thank you very much for your help!

I think I know what is going on here: Looks like you compiled with -DF_CPU=48000000 which worked. Then you just changed your makefile to -DF_CPU=72000000 and recompiled without a 'make clean'. Thus the core was not recompiled (object files were newer than source files) and has still F_BUS = F_CPU = 48MHz compiled in. However, any code which uses F_BUS after you recompiled main.cpp will use F_BUS=36MHz. E.g. intervalTimer::begin will calculate the the required clock periods using F_BUS=36MHz but the timer still runs at 48MHz. Thus the actual period will be 100µs / 48 x 36 = 75µs which you observe.

I tested this and can produce exactly your observation if I do the following

- compile at 48Mhz,
- thouch main
- recompile with F_CPU = 72Mhz (this recompiles main.cpp only)

-> Always do a 'make clean' if you change compiler flags
 
Back
Top