Porting arduino code to M5Stack



  • Hi all, I found this useful arduino code to generate ppm for RC, but it use interrupt and I don't know how to port for M5Stack...
    can You help me??

    
    //https://forum.arduino.cc/index.php/topic,163199.msg1220724.html#msg1220724
    
    // Started 18 Apr 2013 - the loco chassis is more or less ready for testing.
    //
    // This is a test program to drive a loco on R/C channel 1 based on the position of a potentiometer.
    //
    // The centre connection of the pot is connected to pin A2
    // The control signal from the Arduino to the transmitter is on Pin D7.
    //
    // I intend that parts of this program will be used in the computer controlled version.
    //
    // The R/C receiver is programmed to treat the centre value (128?) as off with 0 and 255 representing
    //    full forward and full reverse. Some experimentation will probably be necessary to determine the
    //    correct 0 point.
    // The transmitter can receive a sequence of pulses for 2 to 7 channels. For this program pulses will be
    //    prepared for 7 channels with channels 2 to 7 being values that correspond to centre off.
    //    The receiver would not work with only 3 channels - it needs at least 4..
    //
    // The Transmitter expects a sequence of pulses each of whose width (duration) conveys the
    //   speed setting. The pulse lengths must vary between 1.0 and 2.0 millisecs with 1.5ms representing
    //   centre off. Each pulse must be separated by a short pulse of 0.3ms and there must be a long pulse
    //   to separate the groups of pulses. Ideally the group of pulses should repeat every 22ms
    //   So, 2.0 + 0.3ms for 7 pulses takes 16.1ms thus requiring a separating pulse of 5.9ms.
    //
    // The pulses are generated by timer1 (16 bit) interrupts and to simpify matters when the computer is
    //    controlling things the numbers needed to produce the sequence of pulse lengths will be stored
    //    in an array. At each interrupt the next value in the array is used to set the duration for the
    //    following interrupt. For this program the values in the array position corresponding to channel 3
    //    will be derived from the potentiometer position. (The Rx seems to be programmed to drive the motor
    //      on ch3).
    //
    // Timer1 is used because the longer periods afforded by the 16bits are needed. The prescaler is set
    //    to divide the CPU clock by 64 giving a timer clock of 250khz or 4 microsecs (4us).
    //    On that basis 0.3ms requires a delay of 75 clock steps
    //                  1.0                      250
    //                  1.5                      375
    //                  2.0                      500
    //                  5.9                     1475
    //                 15.1                     3775
    //
    // This program only communicates with the PC for program testing.
    
    // Data variables
    unsigned int ppm[16]; // the array of values for the timer1 interrupt timings
    unsigned int potVal; // value read from potemtiometer
    int curPpm = 0; // the position in the array of timings
    byte curPpmMax; // the actual number of timer steps
    
    char pulsePin = 7; // the digital pin for sending pulses to the transmitter
    char debugPin = 13; // something to watch to check things are working
    char potPin = 2; // the analog pin for the potentiometer
    
    byte loopCount = 0; // a crude substitute for delay()
    int analogIn; // for reading potentiometer position
    
    
    boolean testing = true;
    
    void setup() {
    
      if (testing) {
        Serial.begin(9600);
        Serial.println("Starting TrainRadioPot");
      }
    
      // set the pin directions
      pinMode(pulsePin, OUTPUT);
      //  pinMode(debugPin, OUTPUT);
    
      // set the timing values
      ppm[0] = 1475; //3775; // long pulse - see notes above
      ppm[1] = 75; // short dividing pulse
      ppm[2] = 305; // loco1 ch1
      ppm[3] = 75; // short
      ppm[4] = 305; // loco2 ch2
      ppm[5] = 75; // short
      ppm[6] = 305; // loco3 ch3
      ppm[7] = 75; // short
      ppm[8] = 305; // loco4 ch4
      ppm[9] = 75; // short
      ppm[10] = 305; // loco5 ch5
      ppm[11] = 75; // short
      ppm[12] = 305; // loco6 ch6
      ppm[13] = 75; // short
      ppm[14] = 305; // loco7 ch7
      ppm[15] = 75; // short
    
      curPpmMax = 16; // the number of timer values
      curPpm = 0; // the starting position in the array of timings
    
      // setup and start timer interrupts
      // ppm is achieved by sending different delays to the timer interrupt
      noInterrupts();
      TCCR1A = 0;     // set entire TCCR1A register to 0
      TCCR1B = 0;     // same for TCCR1B
      // set compare match register to desired timer count:
      OCR1A = 1000; // It works by causing an interrupt when TCNT2 counts up to this number
      // This number will be set from the ppm array when the program is running
      digitalWrite(pulsePin, 0); // start with pin low
      // turn on CTC mode: Clear Timer on Compare
      bitSet(TCCR1B, WGM12);
      // Set CS10 and CS11 bits for 64 prescaler: 10, 12 = 1024
      bitSet(TCCR1B, CS10);
      bitSet(TCCR1B, CS11);
      bitClear(TCCR1B, CS12);
      // enable timer compare A interrupt:
      bitSet(TIMSK1, OCIE1A);
      interrupts();
    
    }
    
    void loop() {
    
      if (loopCount == 1) {
        analogIn = analogRead(potPin);
        // the reading must be converted from the range 0 - 1023 to the range 250 - 500
        //   which means dividing by 4 and adding 180 to give 305 at the centre
        potVal = (analogIn >> 2) + 180;
        //		if (potVal > 302 && potVal < 308) {
        if (potVal > 280 && potVal < 320) {
          potVal = 305; // to create an off space without jitter
        }
        //	ppm[2] = potVal;
        //  ppm[8] = potVal;// } CH4 ROL STABE
        // ppm[4] = potVal; //   CH2 PAN STABE YAW
        ppm[6] = potVal; //       CH3 TILT STABE PICH
    
      }
    
    
      //	loopCount = 0; // for testing - so analog read is ignored
      loopCount = loopCount + 1; // it will roll over to zero automatically
      // the purpose of loopCount is so that the pot isn't read every loop
    }
    
    
    // interrupt routine that is triggered when the timer counts up to the preset value
    ISR(TIMER1_COMPA_vect) {
      noInterrupts();
      digitalWrite(pulsePin, !digitalRead(pulsePin)); // change the state of the pin
      OCR1A = ppm[curPpm]; // set the value for the next time interval
      curPpm = ((curPpm + 1) % curPpmMax); // move the index on
      // the modulus operator makes the index roll over to the start
      interrupts();
    }
    

    this is the error I get trying to upload the sketch on m5:

    
    Arduino: 1.8.7 (Mac OS X), Board: "M5Stack-Core-ESP32, QIO, 80MHz, Default, 921600, None"
    
    TrainRadioPot:138:5: error: expected constructor, destructor, or type conversion before '(' token
     ISR(TIMER1_COMPA_vect) {
         ^
    /Users/Desktop/StabeOneWheels/TrainRadioPot/TrainRadioPot.ino: In function 'void setup()':
    TrainRadioPot:94:3: error: 'TCCR1A' was not declared in this scope
       TCCR1A = 0;     // set entire TCCR1A register to 0
       ^
    TrainRadioPot:95:3: error: 'TCCR1B' was not declared in this scope
       TCCR1B = 0;     // same for TCCR1B
       ^
    TrainRadioPot:97:3: error: 'OCR1A' was not declared in this scope
       OCR1A = 1000; // It works by causing an interrupt when TCNT2 counts up to this number
       ^
    In file included from sketch/TrainRadioPot.ino.cpp:1:0:
    TrainRadioPot:101:18: error: 'WGM12' was not declared in this scope
       bitSet(TCCR1B, WGM12);
                      ^
    /Users/Documents/Arduino/hardware/espressif/esp32/cores/esp32/Arduino.h:95:49: note: in definition of macro 'bitSet'
     #define bitSet(value, bit) ((value) |= (1UL << (bit)))
                                                     ^
    TrainRadioPot:103:18: error: 'CS10' was not declared in this scope
       bitSet(TCCR1B, CS10);
                      ^
    /Users/Documents/Arduino/hardware/espressif/esp32/cores/esp32/Arduino.h:95:49: note: in definition of macro 'bitSet'
     #define bitSet(value, bit) ((value) |= (1UL << (bit)))
                                                     ^
    TrainRadioPot:104:18: error: 'CS11' was not declared in this scope
       bitSet(TCCR1B, CS11);
                      ^
    /Users/Documents/Arduino/hardware/espressif/esp32/cores/esp32/Arduino.h:95:49: note: in definition of macro 'bitSet'
     #define bitSet(value, bit) ((value) |= (1UL << (bit)))
                                                     ^
    TrainRadioPot:105:20: error: 'CS12' was not declared in this scope
       bitClear(TCCR1B, CS12);
                        ^
    /Users/Documents/Arduino/hardware/espressif/esp32/cores/esp32/Arduino.h:96:52: note: in definition of macro 'bitClear'
     #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
                                                        ^
    TrainRadioPot:107:10: error: 'TIMSK1' was not declared in this scope
       bitSet(TIMSK1, OCIE1A);
              ^
    /Users/Documents/Arduino/hardware/espressif/esp32/cores/esp32/Arduino.h:95:30: note: in definition of macro 'bitSet'
     #define bitSet(value, bit) ((value) |= (1UL << (bit)))
                                  ^
    TrainRadioPot:107:18: error: 'OCIE1A' was not declared in this scope
       bitSet(TIMSK1, OCIE1A);
                      ^
    /Users/Documents/Arduino/hardware/espressif/esp32/cores/esp32/Arduino.h:95:49: note: in definition of macro 'bitSet'
     #define bitSet(value, bit) ((value) |= (1UL << (bit)))
                                                     ^
    /Users/Desktop/StabeOneWheels/TrainRadioPot/TrainRadioPot.ino: At global scope:
    TrainRadioPot:138:4: error: expected constructor, destructor, or type conversion before '(' token
     ISR(TIMER1_COMPA_vect) {
        ^
    exit status 1
    expected constructor, destructor, or type conversion before '(' token
    
    This report would have more information with
    "Show verbose output during compilation"
    option enabled in File -> Preferences.
    
    
    

    tnks a lot



  • nobody?!



  • If I recall correctly, those command are register calls to the arduino. You need to dig into the espressiv docs to find the register calls for the esp32.

    Check out this doc from espressiv



  • looking in the espressive doc for register calls gave me something really out of my knowledge:

    Interrupts
    Registration of the interrupt handler for a specific timer or a timer group can be done by calling timer_isr_register().
    
    To enable interrupts for a timer group, call timer_group_intr_enable(), for a specific timer call timer_enable_intr(). To disable interrupts for a timer group, call timer_group_intr_disable(), for a specified timer, call timer_disable_intr().
    
    When handling an interrupt within an interrupt serivce routine (ISR), the interrupt status bit needs to be explicitly cleared. To do that, set the TIMERGN.int_clr_timers.tM structure, defined in soc/esp32/include/soc/timer_group_struct.h. In this structure, N is the timer group number [0, 1], M is the timer number [0, 1]. For example, to clear an interrupt status bit for the timer 1 in the timer group 0, call the following:
    
    TIMERG0.int_clr_timers.t1 = 1
    For more information on how to use interrupts, please see the application example below.
    
    Application Example
    The 64-bit hardware timer example: peripherals/timer_group.
    
    API Reference
    Header File
    driver/include/driver/timer.h
    
    esp_err_ttimer_isr_register(timer_group_tgroup_num, timer_idx_t timer_num, void (*fn)(void *), void *arg, int intr_alloc_flags, timer_isr_handle_t*handle, )
    Register Timer interrupt handler, the handler is an ISR. The handler will be attached to the same CPU core that this function is running on.
    
    Note
    If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set, the handler function must be declared with IRAM_ATTR attribute and can only call functions in IRAM or ROM. It cannot call other timer APIs. Use direct register access to configure timers from inside the ISR in this case.
    Return
    ESP_OK Success
    ESP_ERR_INVALID_ARG Parameter error
    Parameters
    group_num: Timer group number
    timer_num: Timer index of timer group
    fn: Interrupt handler function.
    arg: Parameter for handler function
    intr_alloc_flags: Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
    handle: Pointer to return handle. If non-NULL, a handle for the interrupt will be returned here.
    esp_err_ttimer_init(timer_group_tgroup_num, timer_idx_t timer_num, consttimer_config_t*config)
    Initializes and configure the timer.
    
    Return
    ESP_OK Success
    ESP_ERR_INVALID_ARG Parameter error
    Parameters
    group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
    timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
    config: Pointer to timer initialization parameters.
    esp_err_ttimer_get_config(timer_group_tgroup_num, timer_idx_t timer_num, timer_config_t*config)
    Get timer configure value.
    
    Return
    ESP_OK Success
    ESP_ERR_INVALID_ARG Parameter error
    Parameters
    group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
    timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
    config: Pointer of struct to accept timer parameters.
    esp_err_ttimer_group_intr_enable(timer_group_tgroup_num, timer_intr_t intr_mask)
    Enable timer group interrupt, by enable mask.
    
    Return
    ESP_OK Success
    ESP_ERR_INVALID_ARG Parameter error
    Parameters
    group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
    intr_mask: Timer interrupt enable mask.
    TIMER_INTR_T0: t0 interrupt
    TIMER_INTR_T1: t1 interrupt
    TIMER_INTR_WDT: watchdog interrupt
    esp_err_ttimer_group_intr_disable(timer_group_tgroup_num, timer_intr_t intr_mask)
    Disable timer group interrupt, by disable mask.
    
    Return
    ESP_OK Success
    ESP_ERR_INVALID_ARG Parameter error
    Parameters
    group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
    intr_mask: Timer interrupt disable mask.
    TIMER_INTR_T0: t0 interrupt
    TIMER_INTR_T1: t1 interrupt
    TIMER_INTR_WDT: watchdog interrupt
    esp_err_ttimer_enable_intr(timer_group_tgroup_num, timer_idx_t timer_num)
    Enable timer interrupt.
    
    Return
    ESP_OK Success
    ESP_ERR_INVALID_ARG Parameter error
    Parameters
    group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
    timer_num: Timer index.
    esp_err_ttimer_disable_intr(timer_group_tgroup_num, timer_idx_t timer_num)
    Disable timer interrupt.
    
    Return
    ESP_OK Success
    ESP_ERR_INVALID_ARG Parameter error
    Parameters
    group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
    timer_num: Timer index.
    


  • I cant really help you beyond pointing you in a rough direction as I dont understand the registers.

    I only recognised that they were reg calls from an arduino tutorial that came up once on youtubes feed,