Teensy 4 code won't compile, but fine for 3.2/LC. MIDI Controller

cedd

Member
Hi All
I've been working for ages on a MIDI remote control to talk to a mixing desk. It controls the bus sends on the desk, allowing a musician to control their own mix using a single rotary click encoder. I have the code working and whilst it's pretty untidy and i'm sure it can be massively improved upon, it works! It fetches the channel names from the desk, it has a menu structure that is accessible by a long hold on the encoder (allowing the setting of model type for the connected mixing desk and also which of the desk's mixes you want to control), it controls the desk sends correctly. I'm frankly amazed that i've got this far!

My problem now is that the Teensy 3.2 is out of stock. I own one of them, but last week managed to fry it by splashing 12V on to its' 5V pin! I tried an LC but there's not enough RAM on it - the screen is unstable. Instead I bought a Teensy 4. I'll eventually need 12 of these things, so the LC is more attractive, but I think I just have to accept that it's not going to be able to hack it.
The code compiles and works a-ok on the 3.2, however as soon as I try and compile for 4, it refuses. I get the "Error compiling for board Teensy 4.0

I know I have multiple instances of the same library on my machine, and to be honest i'm not sure how that's happened. I had to completely uninstall Arduino IDE a month ago as I ran in to a problem where an edited version of the Adafruit SSD1306 display library (for a tiny display for another project) was always being used in sketches even though i'd changed the filename of the edited version. Had to uninstall, clear out the registries etc. and reinstall before I could use the library I wanted to again. It's therefore a pretty recent install. I know Teensy comes with its' own set of libraries, which might be the problem, though I don't think i'd installed them where the error messages are telling me they're located. Given that it compiles ok for 3.2, i'm inclined to think that they're a red herring.

I do wonder if the problem might be with my use of the TimerOne library, knowing the faster clock speed of the 4.0, but I can't see it stopping the code from compiling.
I tried going back to an older Arduin IDE as i'd seen somebody else have issues with compiling for a 4.0 that this solved, but it's been no use.
Can someone help me make sense of these error messages please! I can't make much sense of what they mean.

Arduino: 1.8.15 (Windows 7), TD: 1.56, Board: "Teensy 4.0, Serial + MIDI, 600 MHz, Faster, US English"


In file included from C:\arduino-1.8.15\Projects\MidiPersonalMonitor\ModelMixNumMenu\ModelMixNumMenu.ino:8:0:

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h: In member function 'void TimerOne::setPeriod(long unsigned int)':

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:180:32: error: 'F_TIMER' was not declared in this scope

const unsigned long cycles = (F_TIMER / 2000000) * microseconds;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:216:16: error: 'FTM1_SC' was not declared in this scope

uint32_t sc = FTM1_SC;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:218:2: error: 'FTM1_MOD' was not declared in this scope

FTM1_MOD = pwmPeriod;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:219:25: error: 'FTM_SC_CLKS' was not declared in this scope

FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | clockSelectBits | (sc & FTM_SC_TOIE);

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:219:29: error: 'FTM_SC_CPWMS' was not declared in this scope

FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | clockSelectBits | (sc & FTM_SC_TOIE);

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:219:68: error: 'FTM_SC_TOIE' was not declared in this scope

FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | clockSelectBits | (sc & FTM_SC_TOIE);

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h: In member function 'void TimerOne::start()':

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:227:2: error: 'FTM1_CNT' was not declared in this scope

FTM1_CNT = 0;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h: In member function 'void TimerOne::stop()':

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:231:2: error: 'FTM1_SC' was not declared in this scope

FTM1_SC = FTM1_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:231:23: error: 'FTM_SC_TOIE' was not declared in this scope

FTM1_SC = FTM1_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:231:37: error: 'FTM_SC_CPWMS' was not declared in this scope

FTM1_SC = FTM1_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:231:63: error: 'FTM_SC_PS' was not declared in this scope

FTM1_SC = FTM1_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h: In member function 'void TimerOne::resume()':

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:237:2: error: 'FTM1_SC' was not declared in this scope

FTM1_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:237:24: error: 'FTM_SC_TOIE' was not declared in this scope

FTM1_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:237:49: error: 'FTM_SC_PS' was not declared in this scope

FTM1_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:237:55: error: 'FTM_SC_CPWMS' was not declared in this scope

FTM1_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:237:83: error: 'FTM_SC_CLKS' was not declared in this scope

FTM1_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h: In member function 'void TimerOne::setPwmDuty(char, unsigned int)':

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:247:13: error: 'TIMER1_A_PIN' was not declared in this scope

if (pin == TIMER1_A_PIN) {

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:248:3: error: 'FTM1_C0V' was not declared in this scope

FTM1_C0V = dutyCycle;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:249:20: error: 'TIMER1_B_PIN' was not declared in this scope

} else if (pin == TIMER1_B_PIN) {

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:250:3: error: 'FTM1_C1V' was not declared in this scope

FTM1_C1V = dutyCycle;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h: In member function 'void TimerOne::pwm(char, unsigned int)':

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:255:13: error: 'TIMER1_A_PIN' was not declared in this scope

if (pin == TIMER1_A_PIN) {

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:256:53: error: 'PORT_PCR_MUX' was not declared in this scope

*portConfigRegister(TIMER1_A_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:256:57: error: 'PORT_PCR_DSE' was not declared in this scope

*portConfigRegister(TIMER1_A_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:256:72: error: 'PORT_PCR_SRE' was not declared in this scope

*portConfigRegister(TIMER1_A_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:257:20: error: 'TIMER1_B_PIN' was not declared in this scope

} else if (pin == TIMER1_B_PIN) {

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:258:53: error: 'PORT_PCR_MUX' was not declared in this scope

*portConfigRegister(TIMER1_B_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:258:57: error: 'PORT_PCR_DSE' was not declared in this scope

*portConfigRegister(TIMER1_B_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:258:72: error: 'PORT_PCR_SRE' was not declared in this scope

*portConfigRegister(TIMER1_B_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h: In member function 'void TimerOne::disablePwm(char)':

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:266:13: error: 'TIMER1_A_PIN' was not declared in this scope

if (pin == TIMER1_A_PIN) {

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:268:20: error: 'TIMER1_B_PIN' was not declared in this scope

} else if (pin == TIMER1_B_PIN) {

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h: In member function 'void TimerOne::attachInterrupt(void (*)())':

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:278:2: error: 'FTM1_SC' was not declared in this scope

FTM1_SC |= FTM_SC_TOIE;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:278:13: error: 'FTM_SC_TOIE' was not declared in this scope

FTM1_SC |= FTM_SC_TOIE;

^

In file included from C:\arduino-1.8.15\hardware\teensy\avr\cores\teensy4/core_pins.h:32:0,

from C:\arduino-1.8.15\hardware\teensy\avr\cores\teensy4/wiring.h:39,

from C:\arduino-1.8.15\hardware\teensy\avr\cores\teensy4/WProgram.h:45,

from C:\Users\Chris\AppData\Local\Temp\arduino_build_551922\pch\Arduino.h:6:

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:279:18: error: 'IRQ_FTM1' was not declared in this scope

NVIC_ENABLE_IRQ(IRQ_FTM1);

^

C:\arduino-1.8.15\hardware\teensy\avr\cores\teensy4/imxrt.h:9846:52: note: in definition of macro 'NVIC_ENABLE_IRQ'

#define NVIC_ENABLE_IRQ(n) (*(&NVIC_ISER0 + ((n) >> 5)) = (1 << ((n) & 31)))

^

In file included from C:\arduino-1.8.15\Projects\MidiPersonalMonitor\ModelMixNumMenu\ModelMixNumMenu.ino:8:0:

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h: In member function 'void TimerOne::detachInterrupt()':

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:286:2: error: 'FTM1_SC' was not declared in this scope

FTM1_SC &= ~FTM_SC_TOIE;

^

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:286:14: error: 'FTM_SC_TOIE' was not declared in this scope

FTM1_SC &= ~FTM_SC_TOIE;

^

In file included from C:\arduino-1.8.15\hardware\teensy\avr\cores\teensy4/core_pins.h:32:0,

from C:\arduino-1.8.15\hardware\teensy\avr\cores\teensy4/wiring.h:39,

from C:\arduino-1.8.15\hardware\teensy\avr\cores\teensy4/WProgram.h:45,

from C:\Users\Chris\AppData\Local\Temp\arduino_build_551922\pch\Arduino.h:6:

C:\Users\Chris\Documents\Arduino\libraries\TimerOne/TimerOne.h:287:19: error: 'IRQ_FTM1' was not declared in this scope

NVIC_DISABLE_IRQ(IRQ_FTM1);

^

C:\arduino-1.8.15\hardware\teensy\avr\cores\teensy4/imxrt.h:9847:52: note: in definition of macro 'NVIC_DISABLE_IRQ'

#define NVIC_DISABLE_IRQ(n) (*(&NVIC_ICER0 + ((n) >> 5)) = (1 << ((n) & 31)))

^

ModelMixNumMenu: In function 'void setup()':

C:\arduino-1.8.15\Projects\MidiPersonalMonitor\ModelMixNumMenu\ModelMixNumMenu.ino:112:44: warning: invalid conversion from 'void (*)(const byte*, uint16_t, bool) {aka void (*)(const unsigned char*, short unsigned int, bool)}' to 'midi::SystemExclusiveCallback {aka void (*)(unsigned char*, unsigned int)}' [-fpermissive]

MIDI.setHandleSystemExclusive(receivemidi);

^

In file included from C:\arduino-1.8.15\Projects\MidiPersonalMonitor\ModelMixNumMenu\ModelMixNumMenu.ino:6:0:

C:\arduino-1.8.15\hardware\teensy\avr\libraries\MIDI\src/MIDI.h:195:17: note: initializing argument 1 of 'void midi::MidiInterface<Transport, _Settings, _Platform>::setHandleSystemExclusive(midi::SystemExclusiveCallback) [with Transport = midi::SerialMIDI<HardwareSerial>; _Settings = midi::DefaultSettings; _Platform = midi::DefaultPlatform; midi::SystemExclusiveCallback = void (*)(unsigned char*, unsigned int); byte = unsigned char]'

inline void setHandleSystemExclusive(SystemExclusiveCallback fptr) { mSystemExclusiveCallback = fptr; }

^

ModelMixNumMenu: In function 'void loop()':

ModelMixNumMenu:127: warning: enumeration value 'Open' not handled in switch

switch (b) {

^

ModelMixNumMenu:127: warning: enumeration value 'Closed' not handled in switch

ModelMixNumMenu:127: warning: enumeration value 'Pressed' not handled in switch

ModelMixNumMenu:127: warning: enumeration value 'Released' not handled in switch

ModelMixNumMenu: In function 'void sendmidi()':

ModelMixNumMenu:395: warning: right shift count >= width of type

if (checksum >> 127){

^

ModelMixNumMenu: In function 'void getnames()':

ModelMixNumMenu:425: warning: right shift count >= width of type

if (checksum >> 127){

^

Multiple libraries were found for "MIDI.h"

Used: C:\arduino-1.8.15\hardware\teensy\avr\libraries\MIDI

Not used: C:\Users\Chris\Documents\Arduino\libraries\MIDI_Library

Multiple libraries were found for "TimerOne.h"

Used: C:\Users\Chris\Documents\Arduino\libraries\TimerOne

Not used: C:\arduino-1.8.15\hardware\teensy\avr\libraries\TimerOne

Error compiling for board Teensy 4.0.



This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

When I compile for 3.2 I just get the following (but it works);
ModelMixNumMenu: In function 'void setup()':
C:\arduino-1.8.15\Projects\MidiPersonalMonitor\ModelMixNumMenu\ModelMixNumMenu.ino:112:44: warning: invalid conversion from 'void (*)(const byte*, uint16_t, bool) {aka void (*)(const unsigned char*, short unsigned int, bool)}' to 'midi::SystemExclusiveCallback {aka void (*)(unsigned char*, unsigned int)}' [-fpermissive]
MIDI.setHandleSystemExclusive(receivemidi);
^
In file included from C:\arduino-1.8.15\Projects\MidiPersonalMonitor\ModelMixNumMenu\ModelMixNumMenu.ino:6:0:
C:\arduino-1.8.15\hardware\teensy\avr\libraries\MIDI\src/MIDI.h:195:17: note: initializing argument 1 of 'void midi::MidiInterface<Transport, _Settings, _Platform>::setHandleSystemExclusive(midi::SystemExclusiveCallback) [with Transport = midi::SerialMIDI<HardwareSerial>; _Settings = midi::DefaultSettings; _Platform = midi::DefaultPlatform; midi::SystemExclusiveCallback = void (*)(unsigned char*, unsigned int); byte = unsigned char]'
inline void setHandleSystemExclusive(SystemExclusiveCallback fptr) { mSystemExclusiveCallback = fptr; }
^
ModelMixNumMenu: In function 'void loop()':
ModelMixNumMenu:127: warning: enumeration value 'Open' not handled in switch
switch (b) {
^
ModelMixNumMenu:127: warning: enumeration value 'Closed' not handled in switch
ModelMixNumMenu:127: warning: enumeration value 'Pressed' not handled in switch
ModelMixNumMenu:127: warning: enumeration value 'Released' not handled in switch
ModelMixNumMenu: In function 'void sendmidi()':
ModelMixNumMenu:395: warning: right shift count >= width of type
if (checksum >> 127){
^
ModelMixNumMenu: In function 'void getnames()':
ModelMixNumMenu:425: warning: right shift count >= width of type
if (checksum >> 127){
^
In file included from C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.cpp:12:0:
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.h: In constructor 'ClickEncoder::ClickEncoder(uint8_t, uint8_t, uint8_t, uint8_t, bool)':
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.h:112:8: warning: 'ClickEncoder::doubleClickEnabled' will be initialized after [-Wreorder]
bool doubleClickEnabled;
^
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.h:106:8: warning: 'bool ClickEncoder::accelerationEnabled' [-Wreorder]
bool accelerationEnabled;
^
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.cpp:46:1: warning: when initialized here [-Wreorder]
ClickEncoder::ClickEncoder(uint8_t A, uint8_t B, uint8_t BTN, uint8_t stepsPerNotch, bool active)
^
In file included from C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.cpp:12:0:
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.h:106:8: warning: 'ClickEncoder::accelerationEnabled' will be initialized after [-Wreorder]
bool accelerationEnabled;
^
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.h:102:20: warning: 'volatile int16_t ClickEncoder::delta' [-Wreorder]
volatile int16_t delta;
^
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.cpp:46:1: warning: when initialized here [-Wreorder]
ClickEncoder::ClickEncoder(uint8_t A, uint8_t B, uint8_t BTN, uint8_t stepsPerNotch, bool active)
^
In file included from C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.cpp:12:0:
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.h:111:19: warning: 'ClickEncoder::button' will be initialized after [-Wreorder]
volatile Button button;
^
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.h:104:11: warning: 'uint8_t ClickEncoder::steps' [-Wreorder]
uint8_t steps;
^
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.cpp:46:1: warning: when initialized here [-Wreorder]
ClickEncoder::ClickEncoder(uint8_t A, uint8_t B, uint8_t BTN, uint8_t stepsPerNotch, bool active)
^
In file included from C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.cpp:12:0:
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.h:104:11: warning: 'ClickEncoder::steps' will be initialized after [-Wreorder]
uint8_t steps;
^
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.h:98:17: warning: 'const uint8_t ClickEncoder::pinA' [-Wreorder]
const uint8_t pinA;
^
C:\Users\Chris\Documents\Arduino\libraries\encoder-master\ClickEncoder.cpp:46:1: warning: when initialized here [-Wreorder]
ClickEncoder::ClickEncoder(uint8_t A, uint8_t B, uint8_t BTN, uint8_t stepsPerNotch, bool active)
^
Sketch uses 43340 bytes (16%) of program storage space. Maximum is 262144 bytes.
Global variables use 6956 bytes (10%) of dynamic memory, leaving 58580 bytes for local variables. Maximum is 65536 bytes.

And here's my code;
Code:
#include <Adafruit_SSD1306.h>
#include <splash.h>
#include <EEPROM.h>

#include <MIDI.h>
#include <ClickEncoder.h>
#include <TimerOne.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
MIDI_CREATE_INSTANCE(HardwareSerial,Serial2,MIDI);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

byte numchans = 32;
byte maxnumaux = 8;


ClickEncoder *encoder;
int16_t last, value;
byte startchan = 1;
byte selchan = 0;
 
byte activechan = 1;
byte lastchannelval = 0;
byte chselflag = 0;
byte lastchselflag = 0;
byte channelvalmax = 30;
byte chpos = 5;
byte chwidth = 10;
byte upflag = 0;
byte downflag = 0;
int nametimer = 0;
int txtimeout = 5000;
byte sysexarray[15] = {0xF0,0x41,0x7F,0x00,0x00,0x24,0x12,0x04,00,0x12,00,00,00,00,0xF7};
byte namereq[17] =    {0xF0,0x41,0x7F,0x00,0x00,0x24,0x11,0x04,00,00,00,00,00,00,0x06,00,0xF7};
byte high_part;
byte low_part;
int midisendval;
byte auxnumber = 0;
byte auxarray[24] = {0x02,0x0A,0x12,0x1A,0x22,0x2A,0x32,0x3A,0x42,0x4a,0x52,0x5a,0x62,0x6a,0x72,0x7a,0x02,0x0A,0x12,0x1A,0x22,0x2A,0x32,0x3A};
byte checksum; //was int - change back if doesn't work
byte chan;
byte rxflag = 0;
byte namesflag = 0;
byte setupmenuflag = 0;
byte editflag = 0;

byte channelindex = 0;
int namereqdelay = 1000;
byte namecount = 0;
byte namerxflag = 0;
int receivednames[234];
byte nameflag[48] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};


byte channelvals[48];
String menunames[2] = {"Mix","Model"};
byte menu;
byte numbermenu = 1;
String modelnames[2] = {"M300","M480"};
byte modelchannels[2] = {31,47};
byte menuvals[2] = {3,1}; //0 is where the selected aux lives. 1 is where the selected model lives
byte menuvallimits[2] = {23,2}; // maximum limits for the menuvals

byte meterx = 110;
byte metery;
byte meterw;
byte meterh = 15;
byte sendindex = 0;




void timerIsr() {
  encoder->service();
}


void setup() {
  numchans = numchans - 1;
  menuvals[0] = EEPROM.read(0);
  menuvals[1] = EEPROM.read(1);
  if(menuvals[0]>>maxnumaux){
    menuvals[0] = 1;
    EEPROM.write(0,menuvals[0]);
setupmenuflag = 1;
  }

  Serial.begin(9600);
  Serial3.begin(4800);

  MIDI.begin();
  MIDI.turnThruOff();
  encoder = new ClickEncoder(A1, A0, A2, 4);
  Timer1.initialize(1000);
  Timer1.attachInterrupt(timerIsr); 
  last = -1;
 // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.clearDisplay();
  MIDI.setHandleSystemExclusive(receivemidi);

}

void loop() {  
  if (namesflag == 0){
    getnames();
  }

  auxnumber = auxarray[menuvals[0]];
  
  MIDI.read();
  ClickEncoder::Button b = encoder->getButton();            //encoder
  if (b != ClickEncoder::Open) {
    #define VERBOSECASE(label) case label: Serial.println(#label); break;
    switch (b) {
      //VERBOSECASE(ClickEncoder::Pressed);
      //VERBOSECASE(ClickEncoder::Held)
      //VERBOSECASE(ClickEncoder::Released)
      case ClickEncoder::DoubleClicked:
      
      break;
      case ClickEncoder::Held:
      
      if (setupmenuflag == 0){
         setupmenuflag = 1;
         display.clearDisplay();
         display.display();
         delay(500);
      }
      else{
        setupmenuflag = 0;
         display.clearDisplay();
         display.display();
         if (EEPROM.read(0) != menuvals[0]){
          EEPROM.write(0,menuvals[0]);
         }
                  if (EEPROM.read(1) != menuvals[1]){
          EEPROM.write(1,menuvals[1]);
         }
        delay(500);
      }
          break;
      case ClickEncoder::Clicked:

        if(setupmenuflag == 1){
          if (editflag == 0){
            editflag = 1;
          }
          else{editflag = 0;}
          
        }
          if (chselflag == 0){
          activechan = selchan;  
          chselflag = 1;
          }
          else{
            chselflag = 0;    
          }
          break;
    }
  }
  if (setupmenuflag == 1){
  display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(35,0);
    display.print("Setup");


      display.setCursor(3, 28);
      display.print(menunames[menu]);

if (editflag == 0){
      value += encoder->getValue();
      if (value > last){menu++;}
      if (value < last){menu--;}
      if (menu < 0){menu = 0;}
      if (menu > numbermenu){menu = numbermenu;}
      last = value;    
      display.drawRect(0, 26, 80, 18, SSD1306_WHITE);
}
else{
      
      value += encoder->getValue();
      if (value > last){menuvals[menu]++;
                  if (menu == 0){
        if(menuvals[1] == 0){
          if(7<menuvals[0] && menuvals[0]<16){
            menuvals[0] = 16 ;
          }
          if (19<menuvals[0]){
            menuvals[0]=19;
          }
        }
      }   
      }
      if (value < last){menuvals[menu]--; 
            if (menu == 0){
        if(menuvals[1] == 0){
          if(7<menuvals[0] && menuvals[0]<16){
            menuvals[0] = 7 ;
          }
        }
      }    
      }
      if (menuvals[menu] < 0){menuvals[menu] = 0;}
      if (menuvals[menu] > menuvallimits[menu]){menuvals[menu] = menuvallimits[menu];}
      if (menu == 0){
        if(menuvals[1] == 0){
          if(7<menuvals[0] && menuvals[0]<16){
            display.drawLine(0,46, 80, 46, SSD1306_WHITE); ;
          }
        }
      }
      last = value;
      display.drawRect(0, 42, 80, 19, SSD1306_WHITE);
}
      display.setCursor(3, 45);
      if(menu == 0){
        String mixnames[24] = {"Aux 1","Aux 2","Aux 3","Aux 4","Aux 5","Aux 6","Aux 7","Aux 8","Aux 9","Aux 10","Aux 11","Aux 12","Aux 13","Aux 14","Aux 15","Aux 16","Mtx 1","Mtx 2","Mtx 3","Mtx 4","Mtx 5","Mtx 6","Mtx 7","Mtx 8"};
      display.print(mixnames[menuvals[0]]);
      }
      else if (menu == 1){
      display.print(modelnames[menuvals[1]]);  
      }   
      display.display();
      numchans = modelchannels[menuvals[1]];



}
else{




  value += encoder->getValue();
  
  if (chselflag == 0){                                      //channel select menu
    lastchselflag = 0;
    if (value > last){selchan++;}
    if (value < last){selchan--;}
    if (selchan < 1){selchan = numchans;}
    if (selchan > numchans){selchan = startchan;}
    last = value;
  }
  else{                                                     //value set menu
    lastchannelval = channelvals[selchan];
    if (value > last){channelvals[selchan]++;
      }
    if (value < last){channelvals[selchan]--;
    }
    if (channelvals[selchan] < 1){channelvals[selchan] = 0;}
    if (channelvals[selchan] > channelvalmax){channelvals[selchan] = channelvalmax;}
    last = value;
    if((lastchannelval != channelvals[selchan]) && (rxflag == 0)){
      sendmidi();  
    }
    rxflag = 0;
  }


  
    if (chselflag == 0){
    meterw = map(channelvals[selchan], 0, 30, 0, 100);
    }
    else{
    meterw = map(channelvals[selchan], 0, 30, 0, 100);  
    }
    chwidth = 128/numchans;
    chpos = chwidth*(selchan-1);
    disp();

}
}

void disp(){

String namearray[48] = {"chan01","chan02","chan03","chan04","chan05","chan06","chan07","chan08","chan09","chan10","chan11","chan12","chan14","chan15","chan16","chan17","chan18","chan19","chan20","chan21","chan22","chan23","chan24","chan25","chan26","chan27","chan28","chan29","chan30","chan31","chan32","chan33","chan34","chan35","chan36","chan37","chan38","chan39","chan40","chan41","chan42","chan43","chan44","chan45","chan46","chan47","chan48"};
    display.clearDisplay();
    display.setTextSize(3);
    display.setTextColor(WHITE);
    display.setCursor(10,35);
    if(nameflag[selchan-1]==0){
    display.print(namearray[selchan-1]);
    }
    else{
    display.write(receivednames[(selchan-1)*6]);
    display.setCursor(26,35);
    display.write(receivednames[((selchan-1)*6)+1]);
    display.setCursor(42,35);
    display.write(receivednames[((selchan-1)*6)+2]);    
    display.setCursor(58,35);
    display.write(receivednames[((selchan-1)*6)+3]);
    display.setCursor(74,35);
    display.write(receivednames[((selchan-1)*6)+4]);
    display.setCursor(90,35);
    display.write(receivednames[((selchan-1)*6)+5]);
    }
    display.setTextSize(2);
    display.setCursor(103,0);
    display.println(channelvals[selchan]);
    
    if (chselflag == 0){
      display.drawRect(0, 32, 128, 29, SSD1306_WHITE);
    }
    else{
      display.drawRect(00, 00, 128, 15, SSD1306_WHITE);      
    }
    

    display.fillRoundRect(0, 0, meterw, meterh, 2, SSD1306_WHITE);
    display.fillRoundRect(chpos, 20, chwidth, 9, 2, SSD1306_WHITE);
    display.drawLine(0,19, 0, 29, SSD1306_WHITE); 
    display.drawLine(127,19, 127, 29, SSD1306_WHITE); 
    display.drawLine(0,29, 127, 29, SSD1306_WHITE); 
    display.drawLine(70,0, 70,14, SSD1306_WHITE);
    display.drawLine(00,0, 00,14, SSD1306_WHITE);
    display.drawLine(100,0, 100,14, SSD1306_WHITE);
    
    display.display();
}   


void receivemidi(const byte *a, uint16_t sizeofsysex, bool last){
  const byte *received = MIDI.getSysExArray();

  if(received[6] == 0x12){                      //it's a Data set
    if(received[7] == 0x04 && received[9] == 0x12){   //it's aux data
        if (received[10] == auxnumber){               //it's for my aux
        chan = received[8]+1;
        //Serial.print("aux data");
        byte rxhigh_part = received[11];
        byte rxlow_part = received[12];
        int val = ((rxhigh_part&0x7F)<<7)|(rxlow_part&0x7F);
        if((val&0x2000)!=0)val|=0xffffC000;
        val = map(val,-905,100,0,99); 
        channelvals[received[8]+1]=val;
        rxflag = 1;
        }
    }
        
    else if((received[7] == 0x04) && ((received[9] == 0x00)) && (received[10] == 0x00)){   //it's a name
      //Serial.println("name received");
      chan = received[8];

      receivednames[chan*6] = received[11];
      receivednames[(chan*6)+1] = received[12];
      receivednames[(chan*6)+2] = received[13];
      receivednames[(chan*6)+3] = received[14];
      receivednames[(chan*6)+4] = received[15];
      receivednames[(chan*6)+5] = received[16];
      nameflag[chan] = 1;      
      namerxflag = 1;
      delay(200);     
     }
  }


}

    void sendmidi(){

midisendval = log(channelvals[selchan]+1)/log(30)*1000;
midisendval = map(midisendval, 0, 1010, -905, 100); //or 16129
//Serial.println(midisendval);

high_part = (midisendval>>7)&0x7F;
low_part = midisendval&0x7F;
//Serial.print(high_part,HEX);
//Serial.print(" : ");
//Serial.println(low_part,HEX);

sysexarray[8]=(activechan-1);
if (menuvals[0]<= 15){
  sysexarray[9] = 0x12;
}
else{ sysexarray[9] = 0x13;}
sysexarray[10]=auxnumber;
sysexarray[11]=high_part;
sysexarray[12]=low_part;
checksum = sysexarray[7]+sysexarray[8]+sysexarray[9]+sysexarray[10]+sysexarray[11]+sysexarray[12];
if (checksum >> 127){
  checksum=checksum-128;
}
checksum=128-checksum;
checksum=checksum&0x7F;
sysexarray[13]=checksum;
//Serial.println(checksum,HEX);
//usbMIDI.sendSysEx(15,sysexarray,true);
MIDI.sendSysEx(15,sysexarray,true);

    }


  void getnames(){
     display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(00,00);
    display.write("Stand By");
    display.setCursor(00,20);
    display.write("Getting");
    display.setCursor(00,40);
    display.write("Names");
    display.display();
    
  while(namecount <= numchans+1){
    if (nametimer == 0){

    namereq[8]=namecount;
    checksum = namereq[7]+namereq[8]+namereq[9]+namereq[10]+namereq[11]+namereq[12]+namereq[13]+namereq[14];
      if (checksum >> 127){
      checksum=checksum-128;
      }
    checksum=128-checksum;
    checksum=checksum&0x7F;
    namereq[15]=checksum;
    MIDI.sendSysEx(17,namereq,true);
    //usbMIDI.sendSysEx(17,namereq,true);
    }
    nametimer++;
    MIDI.read();

    if(nameflag[namecount] == 1){
      namecount++;
      nametimer = 0;
    }
    if (nametimer == txtimeout){
      namecount++;
      nametimer = 0;
    }
    if (namecount == numchans){
      namesflag = 1;
    }   
  }
  }
 
Are you using Teensy's Encoder library, or some other Arduino library? I don't see a file named ClickEncoder.h anywhere in the TeensyDuino installation. Anyway, that's the first error that I run into when I try to compile your program.
 
ClickEncoder is a third party library. It makes use of TimerOne, so i'm wondering if the problem lies somewhere within those two.
I'll look in to the Teensy encoder library. It's a shame as ClickEncoder handles things like double clicks and held buttons really nicely. Will have to write that myself if I use the Teensy one as it doesn't appear to have those functions. Not the end of the world but needs a bit of a rewrite (it does anyway, I know it's messy). Sure the Teensy one will work well so it's worth doing, and from a little googling it appears that the T4 clock speed might be the issue.
 
ClickEncoder is a third party library. It makes use of TimerOne, so i'm wondering if the problem lies somewhere within those two.
I'll look in to the Teensy encoder library. It's a shame as ClickEncoder handles things like double clicks and held buttons really nicely. Will have to write that myself if I use the Teensy one as it doesn't appear to have those functions. Not the end of the world but needs a bit of a rewrite (it does anyway, I know it's messy). Sure the Teensy one will work well so it's worth doing, and from a little googling it appears that the T4 clock speed might be the issue.

When I search for ClickEncoder library, I find quite a few, and I don't see any that support Teensy. Which one are you using and are you sure it supports Teensy? Also, with Teensy, you may want to move from TimerOne to IntervalTimer if you can.
 
Back
Top