// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "esp32-hal-gpio.h" #include "hal/gpio_hal.h" #include "soc/soc_caps.h" // It fixes lack of pin definition for S3 and for any future SoC // this function works for ESP32, ESP32-S2 and ESP32-S3 - including the C3, it will return -1 for any pin #if SOC_TOUCH_SENSOR_NUM > 0 #include "soc/touch_sensor_periph.h" int8_t digitalPinToTouchChannel(uint8_t pin) { int8_t ret = -1; if (pin < SOC_GPIO_PIN_COUNT) { for (uint8_t i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) { if (touch_sensor_channel_io_map[i] == pin) { ret = i; break; } } } return ret; } #else // No Touch Sensor available int8_t digitalPinToTouchChannel(uint8_t pin) { return -1; } #endif #ifdef SOC_ADC_SUPPORTED #include "soc/adc_periph.h" int8_t digitalPinToAnalogChannel(uint8_t pin) { uint8_t channel = 0; if (pin < SOC_GPIO_PIN_COUNT) { for (uint8_t i = 0; i < SOC_ADC_PERIPH_NUM; i++) { for (uint8_t j = 0; j < SOC_ADC_MAX_CHANNEL_NUM; j++) { if (adc_channel_io_map[i][j] == pin) { return channel; } channel++; } } } return -1; } int8_t analogChannelToDigitalPin(uint8_t channel) { if (channel >= (SOC_ADC_PERIPH_NUM * SOC_ADC_MAX_CHANNEL_NUM)) { return -1; } uint8_t adc_unit = (channel / SOC_ADC_MAX_CHANNEL_NUM); uint8_t adc_chan = (channel % SOC_ADC_MAX_CHANNEL_NUM); return adc_channel_io_map[adc_unit][adc_chan]; } #else // No Analog channels availible int8_t analogChannelToDigitalPin(uint8_t channel) { return -1; } #endif typedef void (*voidFuncPtr)(void); typedef void (*voidFuncPtrArg)(void*); typedef struct { voidFuncPtr fn; void* arg; bool functional; } InterruptHandle_t; static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = {0,}; #include "driver/rtc_io.h" extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode) { #ifdef RGB_BUILTIN if (pin == RGB_BUILTIN){ __pinMode(RGB_BUILTIN-SOC_GPIO_PIN_COUNT, mode); return; } #endif if (!GPIO_IS_VALID_GPIO(pin)) { log_e("Invalid pin selected"); return; } gpio_hal_context_t gpiohal; gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); gpio_config_t conf = { .pin_bit_mask = (1ULL<pin[pin].int_type /*!< GPIO interrupt type - previously set */ }; if (mode < 0x20) {//io conf.mode = mode & (INPUT | OUTPUT); if (mode & OPEN_DRAIN) { conf.mode |= GPIO_MODE_DEF_OD; } if (mode & PULLUP) { conf.pull_up_en = GPIO_PULLUP_ENABLE; } if (mode & PULLDOWN) { conf.pull_down_en = GPIO_PULLDOWN_ENABLE; } } if(gpio_config(&conf) != ESP_OK) { log_e("GPIO config failed"); return; } } extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val) { #ifdef RGB_BUILTIN if(pin == RGB_BUILTIN){ //use RMT to set all channels on/off const uint8_t comm_val = val != 0 ? RGB_BRIGHTNESS : 0; neopixelWrite(RGB_BUILTIN, comm_val, comm_val, comm_val); return; } #endif gpio_set_level((gpio_num_t)pin, val); } extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin) { return gpio_get_level((gpio_num_t)pin); } static void ARDUINO_ISR_ATTR __onPinInterrupt(void * arg) { InterruptHandle_t * isr = (InterruptHandle_t*)arg; if(isr->fn) { if(isr->arg){ ((voidFuncPtrArg)isr->fn)(isr->arg); } else { isr->fn(); } } } extern void cleanupFunctional(void* arg); extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional) { static bool interrupt_initialized = false; if(!interrupt_initialized) { esp_err_t err = gpio_install_isr_service((int)ARDUINO_ISR_FLAG); interrupt_initialized = (err == ESP_OK) || (err == ESP_ERR_INVALID_STATE); } if(!interrupt_initialized) { log_e("GPIO ISR Service Failed To Start"); return; } // if new attach without detach remove old info if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) { cleanupFunctional(__pinInterruptHandlers[pin].arg); } __pinInterruptHandlers[pin].fn = (voidFuncPtr)userFunc; __pinInterruptHandlers[pin].arg = arg; __pinInterruptHandlers[pin].functional = functional; gpio_set_intr_type((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); if(intr_type & 0x8){ gpio_wakeup_enable((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); } gpio_isr_handler_add((gpio_num_t)pin, __onPinInterrupt, &__pinInterruptHandlers[pin]); //FIX interrupts on peripherals outputs (eg. LEDC,...) //Enable input in GPIO register gpio_hal_context_t gpiohal; gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); gpio_hal_input_enable(&gpiohal, pin); } extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type) { __attachInterruptFunctionalArg(pin, userFunc, arg, intr_type, false); } extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type) { __attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, NULL, intr_type, false); } extern void __detachInterrupt(uint8_t pin) { gpio_isr_handler_remove((gpio_num_t)pin); //remove handle and disable isr for pin gpio_wakeup_disable((gpio_num_t)pin); if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) { cleanupFunctional(__pinInterruptHandlers[pin].arg); } __pinInterruptHandlers[pin].fn = NULL; __pinInterruptHandlers[pin].arg = NULL; __pinInterruptHandlers[pin].functional = false; gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_DISABLE); } extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode"))); extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite"))); extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead"))); extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt"))); extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void * arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg"))); extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));