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.
-
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,