F_CPU_ACTUAL error in Teensy 4 but not Teensy 3

Status
Not open for further replies.

chipaudette

Well-known member
I've got a library that compiles fine under Teensy 3.6 but won't compile until Teensy 4.0. It's giving errors about not knowing F_CPU_ACTUAL. I suspect that this is a symptom of a larger problem, but I don't know how to chase it down. Why would I get compile errors for Teensy 4 but not for Teensy 3?

More Info...

My library is a float32 extension of the teensy audio library (https://github.com/Tympan/Tympan_Library), which means that most of its classes inherit (after a couple steps) from AudioStream from the Teensy Audio library.

The simplest way to expose this problem is to simply open the PassThroughStereo example from the Teensy Audio library. It compiles fine as either Teensy 3.6 or Teensy 4.0.

Now, to cause the error, I add the #include referencing my own library...not any actual code, just the #include:

Code:
//This is the beginning of PassThroughStereo.ino
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Tympan_Library.h> //I added this.  I don't instantiate any classes.  I just added this #include.

This complies fine under Teensy 3.6. But, under Teensy 4, I get the error below for (seemingly) every class that inherits from AudioStream...it claims that it does't know about F_CPU_ACTUAL:

Code:
In file included from C:\Users\wea\Documents\Arduino\libraries\Tympan_Library\src\AudioStream_F32.h:18:0,

                 from C:\Users\wea\Documents\Arduino\libraries\Tympan_Library\src\AudioMixer_F32.h:21,

                 from C:\Users\wea\Documents\Arduino\libraries\Tympan_Library\src\AudioMixer_F32.cpp:1:

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h: In member function 'int AudioStream::processorUsage()':

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:108:50: error: 'F_CPU_ACTUAL' was not declared in this scope

 #define CYCLE_COUNTER_APPROX_PERCENT(n) (((n) + (F_CPU_ACTUAL / 32 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100)) / (F_CPU_ACTUAL / 16 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100))

Similarly, I also get the error below for many (all?) of the files that inherit from AudioStream...it claims that it doesn't know IRQ_SOFTWARE:

Code:
In file included from C:\Users\wea\Documents\Arduino\libraries\Tympan_Library\src\AudioStream_F32.h:18:0,

                 from C:\Users\wea\Documents\Arduino\libraries\Tympan_Library\src\AudioMixer_F32.h:21,

                 from C:\Users\wea\Documents\Arduino\libraries\Tympan_Library\src\AudioMixer_F32.cpp:1:

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h: In static member function 'static void AudioStream::update_all()':

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:162:50: error: 'IRQ_SOFTWARE' was not declared in this scope

  static void update_all(void) { NVIC_SET_PENDING(IRQ_SOFTWARE); }

                                                  ^

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:162:62: error: 'NVIC_SET_PENDING' was not declared in this scope

  static void update_all(void) { NVIC_SET_PENDING(IRQ_SOFTWARE); }

Why would this compile fine under Teensy 3.6 but break under Teensy 4.0?

Thanks,

Chip
 
Often times it is hard to know without actually seeing the sources and the like. It is probably simply that these defines are needed for T4 are not included in the header files that your class is using...

That is for example the define: extern volatile uint32_t F_CPU_ACTUAL;
Is in the file core_pins.h in the Cores\teensy4 directory. So your code is not including this file directly or indirectly.

So you might simply add this include to your library and see if it helps...
 
Hi KurtE,

Thanks for the suggestion. I'll give it a try.

As a point of education for myself...and stepping away from my own code to just focus on the stock Teensy code...how does AudioStream.h know these quantities? Neither the Teensy3 version and the Teensy4 version have much of a #include list...

Teensy3 AudioStream.h: https://github.com/PaulStoffregen/c...cae8e2bac64be109fbfe35e/teensy3/AudioStream.h
Teensy4 AudioStream.h: https://github.com/PaulStoffregen/c...399d10bd59bd12017bd2e07/teensy4/AudioStream.h

When these are computing CYCLE_COUNTER_APPROX_PERCENT, how do they know what F_CPU_ACTUAL is?

Curiously, I see that Teensy3 uses F_CPU whereas Teensy4 uses F_CPU_ACTUAL. Why the difference?

(Again, this is me trying to learn more of the guts so that I can contribute more usefully...)

Chip
 
CPU freq stuff is almost always specified as a compiler option, which is then visible from within code.

Another example would be the chip. For teensy 4, a compiler option like "-D__IMXRT1062__" will be added, that's how "#ifdef __IMXRT1062__" works throughout the teensy 4 core code.

The way I pick code apart to figure out how it works is use either an IDE with a "search in files" capability, or if you're on linux/mac, use grep to find whatever it is you're interested in.
 
So many questions. I'll briefly comment on this one.

Curiously, I see that Teensy3 uses F_CPU whereas Teensy4 uses F_CPU_ACTUAL. Why the difference?

We're trying to better support dynamic CPU frequency changes on Teensy 4.0.

This wasn't really feasible on Teensy 3.x, because nearly everything's clock is integer division from the CPU clock. Change the CPU clock and suddenly audio is at the wrong speed, baud rates are messed up, and so on. So F_CPU is a preprocessor constant on Teensy 3.x, just like it is on pretty much all Arduino compatible boards. All the software is designed around the assumption that F_CPU never changes.

Teensy 4.0 has 7 PLLs, where 1 PLL is used for the CPU and 6 more plus a ton of dividers and muxes create the frequencies for all the speed sensitive peripherals. See the "CCM Clock Tree" in the reference manual to get a visual idea. While there are some small caveats, this hardware allows the CPU to change speed while pretty much all the timing sensitive peripherals keep running as their intended speeds.

F_CPU_ACTUAL tries allow the software to adapt, so stuff like millis(), elapsedMicros, etc still work properly as the CPU speed changes. F_CPU_ACTUAL is a uint32_t that gives the current CPU speed in Hz. Initially I tried making F_CPU a variable. But the Arduino ecosystem is filled with code assuming it's a preprocessor macro, so we have a somewhat confusing situation where we have a meaningless F_CPU for the sake of compatibility. F_CPU_ACTUAL is what really matters on Teensy 4.0. It's not a constant. It tells you the current speed. You can expect the speed to change dynamically. In most cases you'd use it (read only) just like you would F_CPU, at least in equations. But don't use F_CPU_ACTUAL in #if checks for conditional compilation, because it's not a constant and not a preprocessor macro like F_CPU.

Hopefully this explanation helps you understand the rationale, and the reason why I had to use 2 different names.
 
Last edited:
I got the same error last night when attempting my first port:

Code:
In file included from C:\Users\Derek\AppData\Local\Temp\arduino_build_495648\sketch\AudioSDR.h:31:0,
                 from C:\Users\Derek\AppData\Local\Temp\arduino_build_495648\sketch\AudioSDR.cpp:33:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h: In member function 'int AudioStream::processorUsage()':
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:108:50: error: 'F_CPU_ACTUAL' was not declared in this scope
 #define CYCLE_COUNTER_APPROX_PERCENT(n) (((n) + (F_CPU_ACTUAL / 32 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100)) / (F_CPU_ACTUAL / 16 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100))

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:142:36: note: in expansion of macro 'CYCLE_COUNTER_APPROX_PERCENT'
  int processorUsage(void) { return CYCLE_COUNTER_APPROX_PERCENT(cpu_cycles); }
                                    ^

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h: In member function 'int AudioStream::processorUsageMax()':
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:108:50: error: 'F_CPU_ACTUAL' was not declared in this scope
 #define CYCLE_COUNTER_APPROX_PERCENT(n) (((n) + (F_CPU_ACTUAL / 32 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100)) / (F_CPU_ACTUAL / 16 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100))
                                                  ^

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:143:39: note: in expansion of macro 'CYCLE_COUNTER_APPROX_PERCENT'
  int processorUsageMax(void) { return CYCLE_COUNTER_APPROX_PERCENT(cpu_cycles_max); }
                                       ^
It was late so I left it there!

I've made attempt to modify audiostream, or anything else in the Audio library, but the audio object AudioSDR is my own creation (it has worked fine for 15 months on T3.6). I haven't had time to look at it today: just wanted to let Chip know that he is not alone...
 
Seems like it might be a problem for all "home-brew" audio objects! I've tried several, here is the simplest example I can think of - a do-nothing pass-through object:

Code:
//----------------------------------------------------
// Test for Teensy 4 "home brew" Audio object 
// compilation.
// Derek Rowell     8/15/2019
//====================================================
#include <Audio.h>
#include "AudioPassthru.h"
#include <Wire.h>
#include <SPI.h>
#include <SerialFlash.h>
//
AudioInputI2S     input;
AudioOutputI2S    output;
AudioPassthru     passthru;

AudioConnection c1(input,0,    passthru,0);
AudioConnection c2(input,1,    passthru,1);
AudioConnection c3(passthru,0, output,0);
AudioConnection c4(passthru,1, output,1);
AudioControlSGTL5000 codec;
//----------
void setup() {
  Serial.begin(57600);
  delay(2000);
  codec.enable();
  AudioMemory(20);
  codec.volume(1.0);
}
//---------------
void loop() {}
//---------------
with the home-grown code::
Code:
//----------------------------------------
//        *** AudioPassthru.h ***
//---------------------------------------
#ifndef audio_passthru_h_
  #define audio_passthru_h_
  #include "AudioStream.h"
  #include "Arduino.h"
  //
  //--- 
  class AudioPassthru : public AudioStream {
    public:
      AudioPassthru() : AudioStream(2, inputQueueArray){}
      virtual void update(void);
    // ----
    private:
      audio_block_t *inputQueueArray[2];
  };
#endif
and
Code:
//----------------------------------------
//           *** AudioPassthru.cpp ***
//---------------------------------------
#include "AudioPassthru.h"
void AudioPassthru::update(void) { 
  audio_block_t *blockI, *blockQ;
  blockI = receiveWritable(0);
  blockQ = receiveWritable(1);
  //
  if (!blockI && !blockQ) return;
  if ( blockQ && !blockI) {release(blockQ); return;}
  if ( blockI && !blockQ) {release(blockI); return;}
  //-- Do absolutely nothing!!!
  transmit(blockI, 0);
  transmit(blockQ, 1);
  //
  release(blockI);
  release(blockQ);
  return;}

It compiles and runs just fine on the T3.6, but gives the same errors as above when compiling for the T4:

Code:
 In file included from C:\Users\Derek\AppData\Local\Temp\arduino_build_103058\sketch\AudioPassthru.h:7:0,
                 from C:\Users\Derek\AppData\Local\Temp\arduino_build_103058\sketch\AudioPassthru.cpp:4:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h: In member function 'int AudioStream::processorUsage()':
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:108:50: error: 'F_CPU_ACTUAL' was not declared in this scope
 #define CYCLE_COUNTER_APPROX_PERCENT(n) (((n) + (F_CPU_ACTUAL / 32 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100)) / (F_CPU_ACTUAL / 16 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100))
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:142:36: note: in expansion of macro 'CYCLE_COUNTER_APPROX_PERCENT'

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:108:50: error: 'F_CPU_ACTUAL' was not declared in this scope
 #define CYCLE_COUNTER_APPROX_PERCENT(n) (((n) + (F_CPU_ACTUAL / 32 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100)) / (F_CPU_ACTUAL / 16 / AUDIO_SAMPLE_RATE * AUDIO_BLOCK_SAMPLES / 100))

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:143:39: note: in expansion of macro 'CYCLE_COUNTER_APPROX_PERCENT'
  int processorUsageMax(void) { return CYCLE_COUNTER_APPROX_PERCENT(cpu_cycles_max); }

In file included from C:\Users\Derek\AppData\Local\Temp\arduino_build_103058\sketch\AudioPassthru.h:7:0,
                 from C:\Users\Derek\AppData\Local\Temp\arduino_build_103058\sketch\AudioPassthru.cpp:4:

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h: In static member function 'static void AudioStream::update_all()':

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:162:50: error: 'IRQ_SOFTWARE' was not declared in this scope
  static void update_all(void) { NVIC_SET_PENDING(IRQ_SOFTWARE); }

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/AudioStream.h:162:62: error: 'NVIC_SET_PENDING' was not declared in this scope
  static void update_all(void) { NVIC_SET_PENDING(IRQ_SOFTWARE); }

:(
 
A couple of more data points:
1. The audio passthrough example in the IDE Teeny4-->Audio-->HardwareTesting--> PassThroughStereo compiles without problem (it's almost the same as mine above!!!)
2. It's NOT just the use of home grown Audio objects, the completely vanilla code below also fails to compile:
Code:
//---------------------------------------------
// Test for Teensy 4 Audio compilation problem
//       *** THIS FAILS TO COMPILE! ***
//=============================================
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SerialFlash.h>
//
AudioSynthWaveformSine sine;
AudioOutputI2S         output;
// -----
AudioConnection c1(sine,0, output,0);
AudioControlSGTL5000 codec;

//----
void setup() {
  Serial.begin(57600);
  delay(2000);
  AudioMemory(20);
  codec.enable();
  codec.volume(1.0);
  sine.amplitude(0.5);
  sine.frequency(1000.0);
}

//----
void loop() {}
Any help would be welcome...
 
Status
Not open for further replies.
Back
Top