c++arduinoencoderteensy

When I try to build the teeny 4.1 encoder>speedTest.ino example I get a type conversion error, from volatile uint32_t* to volatile unsigned char*


When I try to build the teeny 4.1 encoder>speedTest.ino example I get the following error:

error: cannot convert 'volatile uint32_t {aka volatile long unsigned int}' to 'volatile unsigned char*' in initialization #define portOutputRegister(pin) ((digital_pin_to_info_PGM[(pin)].reg + 0))**

More detail on the error below.

Hardware & Software Board Teensy 4.1

Arduino IDE version 1.8.19

Teensyduino Version 1.56 for windows 7 and up (downloaded from teensyduino website today 3/22/2022)

The board is a Teensy 4.1

My operating system is Windows 10 pro

Arduino Sketch

Using the included encoder>speedtest.ino latest version, downloaded from https://github.com/PaulStoffregen/Encoder. The same error occurs with the version included with Teensyduino 1.56.

    /* Encoder Library - SpeedTest - for measuring maximum Encoder speed
     * http://www.pjrc.com/teensy/td_libs_Encoder.html
     *
     * This example code is in the public domain.
     */
    
    
    // This SpeedTest example provides a simple way to verify how much
    // CPU time Encoder is consuming.  Connect a DC voltmeter to the
    // output pin and measure the voltage while the encoder is stopped
    // or running at a very slow speed.  Even though the pin is rapidly
    // pulsing, a DC voltmeter will show the average voltage.  Due to
    // software timing, it will read a number much less than a steady
    // logic high, but this number will give you a baseline reading
    // for output with minimal interrupt overhead.  Then increase the
    // encoder speed.  The voltage will decrease as the processor spends
    // more time in Encoder's interrupt routines counting the pulses
    // and less time pulsing the output pin.  When the voltage is
    // close to zero and will not decrease any farther, you have reached
    // the absolute speed limit.  Or, if using a mechanical system where
    // you reach a speed limit imposed by your motors or other hardware,
    // the amount this voltage has decreased, compared to the baseline,
    // should give you a good approximation of the portion of available
    // CPU time Encoder is consuming at your maximum speed.
    
    // Encoder requires low latency interrupt response.  Available CPU
    // time does NOT necessarily prove or guarantee correct performance.
    // If another library, like NewSoftSerial, is disabling interrupts
    // for lengthy periods of time, Encoder can be prevented from
    // properly counting the intput signals while interrupt are disabled.
    
    
    // This optional setting causes Encoder to use more optimized code,
    // but the downside is a conflict if any other part of your sketch
    // or any other library you're using requires attachInterrupt().
    // It must be defined before Encoder.h is included.
    //#define ENCODER_OPTIMIZE_INTERRUPTS
    
    #include <Encoder.h>
    #include "pins_arduino.h"
    
    // Change these two numbers to the pins connected to your encoder
    // or shift register circuit which emulates a quadrature encoder
    //  case 1: both pins are interrupts
    //  case 2: only first pin used as interrupt
    Encoder myEnc(5, 6);
    
    // Connect a DC voltmeter to this pin.
    const int outputPin = 12;
    
    /* This simple circuit, using a Dual Flip-Flop chip, can emulate
       quadrature encoder signals.  The clock can come from a fancy
       function generator or a cheap 555 timer chip.  The clock
       frequency can be measured with another board running FreqCount
       http://www.pjrc.com/teensy/td_libs_FreqCount.html
    
                            +5V
                             |        Quadrature Encoder Signal Emulator
     Clock                   |
     Input o----*--------------------------      ---------------------------o Output1
                |            |14           |    |
                |     _______|_______      |    |     _______________ 
                |    |    CD4013     |     |    |    |    CD4013     |
                |  5 |               | 1   |    |  9 |               | 13
            ---------|  D         Q  |-----|----*----|  D         Q  |------o Output2
           |    |    |               |     |         |               |
           |    |  3 |               |     |      11 |               |
           |     ----|> Clk          |      ---------|> Clk          |
           |         |               |               |               |
           |       6 |               |             8 |               |
           |     ----|  S            |           ----|  S            |
           |    |    |               |          |    |               |
           |    |  4 |            _  | 2        | 10 |            _  | 12
           |    *----|  R         Q  |---       *----|  R         Q  |----
           |    |    |               |          |    |               |    |
           |    |    |_______________|          |    |_______________|    |
           |    |            |                  |                         |
           |    |            | 7                |                         |
           |    |            |                  |                         |
            --------------------------------------------------------------
                |            |                  |
                |            |                  |
              -----        -----              -----
               ---          ---                ---
                -            -                  -
    */
    
    
    void setup() {
      pinMode(outputPin, OUTPUT);
    }
    
    #if defined(__AVR__) || defined(TEENSYDUINO)
    #define REGTYPE unsigned char
    #else
    #define REGTYPE unsigned long
    #endif
    
    void loop() {
      volatile int count = 0;
      volatile REGTYPE *reg = portOutputRegister(digitalPinToPort(outputPin));
      REGTYPE mask = digitalPinToBitMask(outputPin);
    
      while (1) {
        myEnc.read();   // Read the encoder while interrupts are enabled.
        noInterrupts();
        *reg |= mask;   // Pulse the pin high, while interrupts are disabled.
        count = count + 1;
        *reg &= ~mask;
        interrupts();
      }
    }

Full Error Readout

Arduino: 1.8.19 Hourly Build 2019/02/04 10:33 (Windows 10), TD: 1.56, Board: "Teensy 4.1, Serial, 600 MHz, Faster, US English"

In file included from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/core_pins.h:33:0,

                 from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/wiring.h:39,

                 from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/WProgram.h:45,

                 from C:\Users\name\AppData\Local\Temp\arduino_build_426018\pch\Arduino.h:6:

SpeedTest: In function 'void loop()':

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/pins_arduino.h:149:75: error: cannot convert 'volatile uint32_t* {aka volatile long unsigned int*}' to 'volatile unsigned char*' in initialization

 #define portOutputRegister(pin)  ((digital_pin_to_info_PGM[(pin)].reg + 0))

                                                                           ^

C:\Users\name~1\AppData\Local\Temp\arduino_modified_sketch_275677\SpeedTest.ino:101:27: note: in expansion of macro 'portOutputRegister'

   volatile REGTYPE *reg = portOutputRegister(digitalPinToPort(outputPin));

                           ^

C:\Users\name~1\AppData\Local\Temp\arduino_modified_sketch_275677\SpeedTest.pde: At global scope:

SpeedTest:46: error: redefinition of 'Encoder myEnc'

 Encoder myEnc(5, 6);

              ^

C:\Users\name~1\AppData\Local\Temp\arduino_modified_sketch_275677\SpeedTest.ino:46:9: note: 'Encoder myEnc' previously declared here

 Encoder myEnc(5, 6);

         ^

SpeedTest:49: error: redefinition of 'const int outputPin'

 const int outputPin = 12;

           ^

C:\Users\name~1\AppData\Local\Temp\arduino_modified_sketch_275677\SpeedTest.ino:49:11: note: 'const int outputPin' previously defined here

 const int outputPin = 12;

           ^

SpeedTest: In function 'void setup()':

SpeedTest:89: error: redefinition of 'void setup()'

 void setup() {

      ^

C:\Users\name~1\AppData\Local\Temp\arduino_modified_sketch_275677\SpeedTest.ino:89:6: note: 'void setup()' previously defined here

 void setup() {

      ^

SpeedTest: In function 'void loop()':

SpeedTest:99: error: redefinition of 'void loop()'

 void loop() {

      ^

C:\Users\name~1\AppData\Local\Temp\arduino_modified_sketch_275677\SpeedTest.ino:99:6: note: 'void loop()' previously defined here

 void loop() {

      ^

In file included from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/core_pins.h:33:0,

                 from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/wiring.h:39,

                 from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/WProgram.h:45,

                 from C:\Users\name~1\AppData\Local\Temp\arduino_build_426018\pch\Arduino.h:6:

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/pins_arduino.h:149:75: error: cannot convert 'volatile uint32_t* {aka volatile long unsigned int*}' to 'volatile unsigned char*' in initialization

 #define portOutputRegister(pin)  ((digital_pin_to_info_PGM[(pin)].reg + 0))

                                                                           ^

C:\Users\name~1\AppData\Local\Temp\arduino_modified_sketch_275677\SpeedTest.pde:101:27: note: in expansion of macro 'portOutputRegister'

   volatile REGTYPE *reg = portOutputRegister(digitalPinToPort(outputPin));

                           ^

redefinition of 'Encoder myEnc'



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

I searched and wasn't able to find an answer anywhere. I found a similar sounding issue on the Github here, but with a different version:

https://github.com/PaulStoffregen/Encoder/issues/44

however there is no "direct_pin_red.h" which is what the answer there says to add the code to.

He says to add the following code to that file

#if defined(__IMXRT1062__)
#define IO_REG_TYPE             uint32_t
#define PIN_TO_BASEREG(pin)             (portInputRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin)             (digitalPinToBitMask(pin))
#define DIRECT_PIN_READ(base, mask)     (((*(base)) & (mask)) ? 1 : 0)

I found a file with similar code in Arduino\hardware\teensy\avr\libraries\Encoder\utility\direct_pin_read.h

#define IO_REG_TYPE         uint32_t
#define PIN_TO_BASEREG(pin)             (portOutputRegister(pin))
#define PIN_TO_BITMASK(pin)             (digitalPinToBitMask(pin))
#define DIRECT_PIN_READ(base, mask)     (((*(base)) & (mask)) ? 1 : 0)

The only difference being the PIN_TO_BASEREG definition in the answer on git is

#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))

vs

#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))

So I tried changing it to match the given solution, but I get the same errors.

I'm not sure why it is calling this a conversion error between volatile uint32_t* to volatile unsigned char*, or where I need to change the definition.


Solution

  • The macro definition is clearly wrong. It looks like it was done for the old AVR Teensies and was not adjusted to the 32bit ARM boards. For a T4.x you can simply replace it by

    // #if defined(__AVR__) || defined(TEENSYDUINO)
    // #define REGTYPE unsigned char
    // #else
    // #define REGTYPE unsigned long
    // #endif
    
    using REGTYPE = uint32_t;
    

    which compiles. You can also replace the complete register stuff and simply use

    #include <Encoder.h>
    #include "pins_arduino.h"
    
    // Change these two numbers to the pins connected to your encoder
    // or shift register circuit which emulates a quadrature encoder
    //  case 1: both pins are interrupts
    //  case 2: only first pin used as interrupt
    Encoder myEnc(5, 6);
    
    // Connect a DC voltmeter to this pin.
    const int outputPin = 12;
    
    
    void setup() {
      pinMode(outputPin, OUTPUT);
    }
    
    
    void loop() {
      volatile int count = 0;
    
      while (1) {
        myEnc.read();   // Read the encoder while interrupts are enabled.
    
        noInterrupts();
        digitalWriteFast(outputPin, HIGH);
        count = count + 1;
        digitalWriteFast(outputPin, LOW);
        interrupts();
      }
    }
    

    But, I'm not sure if the measurement makes sense for a 600MHz T4. The outputPin will be high for a few nanoseconds only...