🤖Have you ever tried Chat.M5Stack.com before asking??😎
    M5Stack Community
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Register
    • Login

    Porting arduino code to M5Stack

    Arduino
    2
    5
    6.0k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C
      cepics
      last edited by

      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

      1 Reply Last reply Reply Quote 0
      • C
        cepics
        last edited by

        nobody?!

        1 Reply Last reply Reply Quote 0
        • ajb2k3A
          ajb2k3
          last edited by ajb2k3

          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

          UIFlow, so easy an adult can learn it!
          If I don't know it, be patient!
          I've ether not learned it or am too drunk to remember it!
          Author of the WIP UIFlow Handbook!
          M5Black, Go, Stick, Core2, and so much more it cant be fit in here!

          1 Reply Last reply Reply Quote 0
          • C
            cepics
            last edited by

            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.
            
            1 Reply Last reply Reply Quote 0
            • ajb2k3A
              ajb2k3
              last edited by

              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,

              UIFlow, so easy an adult can learn it!
              If I don't know it, be patient!
              I've ether not learned it or am too drunk to remember it!
              Author of the WIP UIFlow Handbook!
              M5Black, Go, Stick, Core2, and so much more it cant be fit in here!

              1 Reply Last reply Reply Quote 0
              • First post
                Last post