Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

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

  1. #1
    Junior Member
    Join Date
    Feb 2020
    Posts
    4

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

    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\ModelMixNumMen u\ModelMixNumMenu.ino:8:0:

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

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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\TimerOn e/TimerOne.h:216:16: error: 'FTM1_SC' was not declared in this scope

    uint32_t sc = FTM1_SC;

    ^

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

    FTM1_MOD = pwmPeriod;

    ^

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/TimerOne.h: In member function 'void TimerOne::start()':

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

    FTM1_CNT = 0;

    ^

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

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/TimerOne.h: In member function 'void TimerOne::resume()':

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/TimerOne.h: In member function 'void TimerOne::setPwmDuty(char, unsigned int)':

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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\TimerOn e/TimerOne.h:248:3: error: 'FTM1_C0V' was not declared in this scope

    FTM1_C0V = dutyCycle;

    ^

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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\TimerOn e/TimerOne.h:250:3: error: 'FTM1_C1V' was not declared in this scope

    FTM1_C1V = dutyCycle;

    ^

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

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/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\TimerOn e/TimerOne.h: In member function 'void TimerOne::disablePwm(char)':

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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\TimerOn e/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\TimerOn e/TimerOne.h: In member function 'void TimerOne::attachInterrupt(void (*)())':

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

    FTM1_SC |= FTM_SC_TOIE;

    ^

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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_55 1922\pch\Arduino.h:6:

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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\ModelMixNumMen u\ModelMixNumMenu.ino:8:0:

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

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

    FTM1_SC &= ~FTM_SC_TOIE;

    ^

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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_55 1922\pch\Arduino.h:6:

    C:\Users\Chris\Documents\Arduino\libraries\TimerOn e/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\ModelMixNumMen u\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\ModelMixNumMen u\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::SystemE xclusiveCallback) [with Transport = midi::SerialMIDI<HardwareSerial>; _Settings = midi:efaultSettings; _Platform = midi:efaultPlatform; 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_Li brary

    Multiple libraries were found for "TimerOne.h"

    Used: C:\Users\Chris\Documents\Arduino\libraries\TimerOn e

    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\ModelMixNumMen u\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\ModelMixNumMen u\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::SystemE xclusiveCallback) [with Transport = midi::SerialMIDI<HardwareSerial>; _Settings = midi:efaultSettings; _Platform = midi:efaultPlatform; 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:inA' [-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;
        }   
      }
      }

  2. #2
    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.

  3. #3
    Junior Member
    Join Date
    Feb 2020
    Posts
    4
    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.

  4. #4
    Quote Originally Posted by cedd View Post
    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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •