/* si2c.c - Software I2C library for ESP31B Copyright (c) 2015 Hristo Gochkov. All rights reserved. This file is part of the ESP31B core for Arduino environment. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "twi.h" #include "soc/gpio_reg.h" #include "soc/gpio_struct.h" #include "soc/io_mux_reg.h" #include "driver/rtc_io.h" #include #define LOW 0x0 #define HIGH 0x1 //GPIO FUNCTIONS #define INPUT 0x01 #define OUTPUT 0x02 #define PULLUP 0x04 #define INPUT_PULLUP 0x05 #define PULLDOWN 0x08 #define INPUT_PULLDOWN 0x09 #define OPEN_DRAIN 0x10 #define OUTPUT_OPEN_DRAIN 0x12 #define SPECIAL 0xF0 #define FUNCTION_1 0x00 #define FUNCTION_2 0x20 #define FUNCTION_3 0x40 #define FUNCTION_4 0x60 #define FUNCTION_5 0x80 #define FUNCTION_6 0xA0 #define ESP_REG(addr) *((volatile uint32_t *)(addr)) const uint8_t pin_to_mux[40] = { 0x44, 0x88, 0x40, 0x84, 0x48, 0x6c, 0x60, 0x64, 0x68, 0x54, 0x58, 0x5c, 0x34, 0x38, 0x30, 0x3c, 0x4c, 0x50, 0x70, 0x74, 0x78, 0x7c, 0x80, 0x8c, 0, 0x24, 0x28, 0x2c, 0, 0, 0, 0, 0x1c, 0x20, 0x14, 0x18, 0x04, 0x08, 0x0c, 0x10}; static void pinMode(uint8_t pin, uint8_t mode) { if(pin >= 40) { return; } uint32_t rtc_reg = rtc_gpio_desc[pin].reg; //RTC pins PULL settings if(rtc_reg) { //lock rtc ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux); if(mode & PULLUP) { ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pullup) & ~(rtc_gpio_desc[pin].pulldown); } else if(mode & PULLDOWN) { ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pulldown) & ~(rtc_gpio_desc[pin].pullup); } else { ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown); } //unlock rtc } uint32_t pinFunction = 0, pinControl = 0; //lock gpio if(mode & INPUT) { if(pin < 32) { GPIO.enable_w1tc = BIT(pin); } else { GPIO.enable1_w1tc.val = BIT(pin - 32); } } else if(mode & OUTPUT) { if(pin > 33) { //unlock gpio return;//pins above 33 can be only inputs } else if(pin < 32) { GPIO.enable_w1ts = BIT(pin); } else { GPIO.enable1_w1ts.val = BIT(pin - 32); } } if(mode & PULLUP) { pinFunction |= FUN_PU; } else if(mode & PULLDOWN) { pinFunction |= FUN_PD; } pinFunction |= ((uint32_t)2 << FUN_DRV_S);//what are the drivers? pinFunction |= FUN_IE;//input enable but required for output as well? if(mode & (INPUT | OUTPUT)) { pinFunction |= ((uint32_t)2 << MCU_SEL_S); } else if(mode == SPECIAL) { pinFunction |= ((uint32_t)(((pin)==1||(pin)==3)?0:1) << MCU_SEL_S); } else { pinFunction |= ((uint32_t)(mode >> 5) << MCU_SEL_S); } ESP_REG(DR_REG_IO_MUX_BASE + pin_to_mux[pin]) = pinFunction; if(mode & OPEN_DRAIN) { pinControl = (1 << GPIO_PIN0_PAD_DRIVER_S); } GPIO.pin[pin].val = pinControl; //unlock gpio } static void digitalWrite(uint8_t pin, uint8_t val) { if(val) { if(pin < 32) { GPIO.out_w1ts = BIT(pin); } else if(pin < 34) { GPIO.out1_w1ts.val = BIT(pin - 32); } } else { if(pin < 32) { GPIO.out_w1tc = BIT(pin); } else if(pin < 34) { GPIO.out1_w1tc.val = BIT(pin - 32); } } } unsigned char twi_dcount = 18; static unsigned char twi_sda, twi_scl; static inline void SDA_LOW() { //Enable SDA (becomes output and since GPO is 0 for the pin, // it will pull the line low) if (twi_sda < 32) { GPIO.enable_w1ts = BIT(twi_sda); } else { GPIO.enable1_w1ts.val = BIT(twi_sda - 32); } } static inline void SDA_HIGH() { //Disable SDA (becomes input and since it has pullup it will go high) if (twi_sda < 32) { GPIO.enable_w1tc = BIT(twi_sda); } else { GPIO.enable1_w1tc.val = BIT(twi_sda - 32); } } static inline uint32_t SDA_READ() { if (twi_sda < 32) { return (GPIO.in & BIT(twi_sda)) != 0; } else { return (GPIO.in1.val & BIT(twi_sda - 32)) != 0; } } static void SCL_LOW() { if (twi_scl < 32) { GPIO.enable_w1ts = BIT(twi_scl); } else { GPIO.enable1_w1ts.val = BIT(twi_scl - 32); } } static void SCL_HIGH() { if (twi_scl < 32) { GPIO.enable_w1tc = BIT(twi_scl); } else { GPIO.enable1_w1tc.val = BIT(twi_scl - 32); } } static uint32_t SCL_READ() { if (twi_scl < 32) { return (GPIO.in & BIT(twi_scl)) != 0; } else { return (GPIO.in1.val & BIT(twi_scl - 32)) != 0; } } #ifndef FCPU80 #define FCPU80 80000000L #endif #if F_CPU == FCPU80 #define TWI_CLOCK_STRETCH 800 #else #define TWI_CLOCK_STRETCH 1600 #endif void twi_setClock(unsigned int freq) { #if F_CPU == FCPU80 if(freq <= 100000) { twi_dcount = 19; //about 100KHz } else if(freq <= 200000) { twi_dcount = 8; //about 200KHz } else if(freq <= 300000) { twi_dcount = 3; //about 300KHz } else if(freq <= 400000) { twi_dcount = 1; //about 400KHz } else { twi_dcount = 1; //about 400KHz } #else if(freq <= 100000) { twi_dcount = 32; //about 100KHz } else if(freq <= 200000) { twi_dcount = 14; //about 200KHz } else if(freq <= 300000) { twi_dcount = 8; //about 300KHz } else if(freq <= 400000) { twi_dcount = 5; //about 400KHz } else if(freq <= 500000) { twi_dcount = 3; //about 500KHz } else if(freq <= 600000) { twi_dcount = 2; //about 600KHz } else { twi_dcount = 1; //about 700KHz } #endif } void twi_init(unsigned char sda, unsigned char scl) { twi_sda = sda; twi_scl = scl; pinMode(twi_sda, OUTPUT); pinMode(twi_scl, OUTPUT); digitalWrite(twi_sda, 0); digitalWrite(twi_scl, 0); pinMode(twi_sda, INPUT_PULLUP); pinMode(twi_scl, INPUT_PULLUP); twi_setClock(100000); } void twi_stop(void) { pinMode(twi_sda, INPUT); pinMode(twi_scl, INPUT); } static void twi_delay(unsigned char v) { unsigned int i; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-variable" unsigned int reg; for(i=0; i