I2C sw driver with support of multiple buses, Slow, Fast, FastPlus, and user-defined speed selection (#2465)
* I2C driver speed-up, i2c.SLOW, i2c.FAST and user-defined speed selection * - Multiple buses (up to 10) with different speeds on each bus - Standard(Slow, 100kHz), Fast(400kHz) and FastPlus(1MHz) modes or an arbitrary clock speed - Sharing SDA line over multiple I²C buses to save available pins - GPIO16 pin can be used as SCL pin, but it does not support clock stretching and selected bus will be limited to FAST speed. * Dynamic memory allocation, error checks, simplification, timing tweaks. * Separated the code of old driver for better compatibility and simplicity * Change of driver interface * Add bus status check in setup(); simplify getDC(); remove unnesessary lines in ACK read/write * Fix for moved doc file and trailing whitespaces
This commit is contained in:
parent
3f5ae99e42
commit
ab61e9c03a
|
@ -1,20 +1,421 @@
|
|||
/******************************************************************************
|
||||
* Copyright 2013-2014 Espressif Systems (Wuxi)
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* FileName: i2c_master.c
|
||||
* Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
||||
*
|
||||
* Description: i2c master API
|
||||
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
|
||||
* it is free of charge, to any person obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* Modification history:
|
||||
* 2014/3/12, v1.0 create this file.
|
||||
*******************************************************************************/
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
* Rework of original driver: Natalia Sorokina <sonaux@gmail.com>, 2018
|
||||
*/
|
||||
|
||||
#include "../libc/c_stdlib.h"
|
||||
#include "ets_sys.h"
|
||||
#include "osapi.h"
|
||||
#include "gpio.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
#include "cpu_esp8266.h"
|
||||
#include "pin_map.h"
|
||||
|
||||
#include "user_config.h"
|
||||
|
||||
#include "driver/i2c_master.h"
|
||||
|
||||
#include "pin_map.h"
|
||||
|
||||
#ifndef I2C_MASTER_OLD_VERSION
|
||||
/******************************************************************************
|
||||
* NEW driver
|
||||
* Enabled if I2C_MASTER_OLD_VERSION is not defined in user_config.h
|
||||
*******************************************************************************/
|
||||
// Supports multiple i2c buses
|
||||
// I2C speed in range 25kHz - 550kHz (25kHz - 1MHz if CPU at 160MHz)
|
||||
// If GPIO16 is used as SCL then speed is limited to 25kHz - 400kHz
|
||||
// Speed is defined for every bus separately
|
||||
|
||||
// enable use GPIO16 (D0) pin as SCL line
|
||||
#ifdef I2C_MASTER_GPIO16_ENABLE
|
||||
#define IS_PIN16(n) ((n)==16)
|
||||
// CPU_CYCLES_BETWEEN_DELAYS describes how much cpu cycles code runs
|
||||
// between i2c_master_setDC() calls if delay is zero and i2c_master_set_DC_delay()
|
||||
// is not being called. This is not exact value, but proportional with length of code.
|
||||
// Increasing the value results in less delay and faster i2c clock speed.
|
||||
#define CPU_CYCLES_BETWEEN_DELAYS 80
|
||||
// CPU_CYCLES_GPIO16 is added to CPU_CYCLES_BETWEEN_DELAYS,
|
||||
// as RTC-related IO takes much more time than standard GPIOs.
|
||||
// Increasing the value results in less delay and faster i2c clock speed for GPIO16.
|
||||
#define CPU_CYCLES_GPIO16 90
|
||||
|
||||
#else
|
||||
// If GPIO16 support is not enabled, remove GPIO16-related code during compile
|
||||
// and change timing constants.
|
||||
#define IS_PIN16(n) (0)
|
||||
#define CPU_CYCLES_BETWEEN_DELAYS 74
|
||||
#endif //I2C_MASTER_GPIO16_ENABLE
|
||||
|
||||
#define MIN_SPEED 25000
|
||||
#define MAX_NUMBER_OF_I2C NUM_I2C
|
||||
|
||||
typedef struct {
|
||||
uint8 last_SDA;
|
||||
uint8 last_SCL;
|
||||
uint8 pin_SDA;
|
||||
uint8 pin_SCL;
|
||||
uint32 pin_SDA_SCL_mask;
|
||||
uint32 pin_SDA_mask;
|
||||
uint32 pin_SCL_mask;
|
||||
uint32 speed;
|
||||
sint16 cycles_delay;
|
||||
} i2c_master_state_t;
|
||||
static i2c_master_state_t *i2c[MAX_NUMBER_OF_I2C];
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_set_DC_delay
|
||||
* Description : Internal used function - calculate delay for i2c_master_setDC
|
||||
* Parameters : bus id
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
LOCAL void ICACHE_FLASH_ATTR
|
||||
i2c_master_set_DC_delay(uint16 id)
|
||||
{
|
||||
// [cpu cycles per half SCL clock period] - [cpu cycles that code takes to run]
|
||||
i2c[id]->cycles_delay = system_get_cpu_freq() * 500000 / i2c[id]->speed - CPU_CYCLES_BETWEEN_DELAYS;
|
||||
#ifdef I2C_MASTER_GPIO16_ENABLE
|
||||
if(IS_PIN16(i2c[id]->pin_SCL)){ //if GPIO16
|
||||
i2c[id]->cycles_delay -= CPU_CYCLES_GPIO16; //decrease delay
|
||||
}
|
||||
#endif //I2C_MASTER_GPIO16_ENABLE
|
||||
if(i2c[id]->cycles_delay < 0){
|
||||
i2c[id]->cycles_delay = 0;
|
||||
}
|
||||
}
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_wait_cpu_cycles
|
||||
* Description : Internal used function - wait for given count of cpu cycles
|
||||
* Parameters : sint16 cycles_delay
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
static inline void i2c_master_wait_cpu_cycles(sint16 cycles_delay)
|
||||
{
|
||||
uint32 cycles_start;
|
||||
uint32 cycles_curr;
|
||||
// uses special 'ccount' register which is increased every CPU cycle
|
||||
// to make precise delay
|
||||
asm volatile("rsr %0, ccount":"=a"(cycles_start));
|
||||
do{
|
||||
asm volatile("rsr %0, ccount":"=a"(cycles_curr));
|
||||
} while (cycles_curr - cycles_start < cycles_delay);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_wait_gpio_SCL_high
|
||||
* Description : Internal used function - wait until SCL line in a high state
|
||||
(slave device may hold SCL line low until it is ready to proceed)
|
||||
* Parameters : bus id
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
static inline void i2c_master_wait_gpio_SCL_high(uint16 id)
|
||||
{
|
||||
// retrieves bitmask of all GPIOs from memory-mapped gpio register and exits if SCL bit is set
|
||||
// equivalent, but slow variant:
|
||||
// while(!(READ_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) & i2c[id]->pin_SCL_mask)) {};
|
||||
// even slower: while (!(gpio_input_get() & i2c[id]->pin_SCL_mask)) {};
|
||||
asm volatile("l_wait:"
|
||||
"l16ui %0, %[gpio_in_addr], 0;" //read gpio state into register %0
|
||||
"memw;" //wait for read completion
|
||||
"bnall %0, %[gpio_SCL_mask], l_wait;" // test if SCL bit not set
|
||||
::[gpio_SCL_mask] "r" (i2c[id]->pin_SCL_mask),
|
||||
[gpio_in_addr] "r" (PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS)
|
||||
);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_setDC
|
||||
* Description : Internal used function -
|
||||
* set i2c SDA and SCL bit value for half clock cycle
|
||||
* Parameters : bus id, uint8 SDA, uint8 SCL
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
LOCAL void ICACHE_FLASH_ATTR
|
||||
i2c_master_setDC(uint16 id, uint8 SDA, uint8 SCL)
|
||||
{
|
||||
uint32 this_SDA_SCL_set_mask;
|
||||
uint32 this_SDA_SCL_clear_mask;
|
||||
i2c[id]->last_SDA = SDA;
|
||||
i2c[id]->last_SCL = SCL;
|
||||
|
||||
if(i2c[id]->cycles_delay > 0){
|
||||
i2c_master_wait_cpu_cycles(i2c[id]->cycles_delay);
|
||||
}
|
||||
if (IS_PIN16(i2c[id]->pin_SCL)){ //GPIO16 wired differently, it has it's own register address
|
||||
WRITE_PERI_REG(RTC_GPIO_OUT, SCL); // write SCL value
|
||||
if(1 == SDA){
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, i2c[id]->pin_SDA_mask); //SDA = 1
|
||||
}else{
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, i2c[id]->pin_SDA_mask); // SDA = 0
|
||||
}
|
||||
if(1 == SCL){ //clock stretching, GPIO16 version
|
||||
while(!(READ_PERI_REG(RTC_GPIO_IN_DATA) & 1)) {}; //read SCL value until SCL goes high
|
||||
}else{
|
||||
// dummy read operation and empty CPU cycles to maintain equal times for low and high state
|
||||
READ_PERI_REG(RTC_GPIO_IN_DATA) & 1; asm volatile("nop;nop;nop;nop;");
|
||||
}
|
||||
}
|
||||
else{
|
||||
this_SDA_SCL_set_mask = (SDA << i2c[id]->pin_SDA) | (SCL << i2c[id]->pin_SCL);
|
||||
this_SDA_SCL_clear_mask = i2c[id]->pin_SDA_SCL_mask ^ this_SDA_SCL_set_mask;
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, this_SDA_SCL_clear_mask);
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, this_SDA_SCL_set_mask);
|
||||
if(1 == SCL) { //clock stretching
|
||||
i2c_master_wait_gpio_SCL_high(id);
|
||||
}else{
|
||||
asm volatile("nop;nop;nop;"); // empty CPU cycles to maintain equal times for low and high state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_getDC
|
||||
* Description : Internal used function -
|
||||
* get i2c SDA bit value
|
||||
* Parameters : bus id
|
||||
* Returns : uint8 - SDA bit value
|
||||
*******************************************************************************/
|
||||
static inline uint8 ICACHE_FLASH_ATTR
|
||||
i2c_master_getDC(uint16 id)
|
||||
{
|
||||
return (READ_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) >> i2c[id]->pin_SDA) & 1;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_configured
|
||||
* Description : checks if i2c bus is configured
|
||||
* Parameters : bus id
|
||||
* Returns : boolean value, true if configured
|
||||
*******************************************************************************/
|
||||
bool ICACHE_FLASH_ATTR
|
||||
i2c_master_configured(uint16 id){
|
||||
return !(NULL == i2c[id]);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_init
|
||||
* Description : initialize I2C bus to enable i2c operations
|
||||
(reset state of all slave devices)
|
||||
* Parameters : bus id
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_init(uint16 id)
|
||||
{
|
||||
uint8 i;
|
||||
|
||||
i2c_master_setDC(id, 1, 0);
|
||||
|
||||
// when SCL = 0, toggle SDA to clear up
|
||||
i2c_master_setDC(id, 0, 0) ;
|
||||
i2c_master_setDC(id, 1, 0) ;
|
||||
|
||||
// set data_cnt to max value
|
||||
for (i = 0; i < 28; i++) {
|
||||
i2c_master_setDC(id, 1, 0);
|
||||
i2c_master_setDC(id, 1, 1);
|
||||
}
|
||||
|
||||
// reset all
|
||||
i2c_master_stop(id);
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_setup
|
||||
* Description : Initializes and configures the driver on given bus ID
|
||||
* Parameters : bus id
|
||||
* Returns : configured speed
|
||||
*******************************************************************************/
|
||||
uint32 ICACHE_FLASH_ATTR
|
||||
i2c_master_setup(uint16 id, uint8 sda, uint8 scl, uint32 speed)
|
||||
{
|
||||
if(NULL == i2c[id]){
|
||||
i2c[id] = (i2c_master_state_t*) c_malloc(sizeof(i2c_master_state_t));
|
||||
}
|
||||
if(NULL == i2c[id]){ // if malloc failed
|
||||
return 0;
|
||||
}
|
||||
i2c[id]->last_SDA = 1; //default idle state
|
||||
i2c[id]->last_SCL = 1;
|
||||
i2c[id]->pin_SDA = pin_num[sda];
|
||||
i2c[id]->pin_SCL = pin_num[scl];
|
||||
i2c[id]->pin_SDA_mask = 1 << i2c[id]->pin_SDA;
|
||||
i2c[id]->pin_SCL_mask = 1 << i2c[id]->pin_SCL;
|
||||
i2c[id]->pin_SDA_SCL_mask = i2c[id]->pin_SDA_mask | i2c[id]->pin_SCL_mask;
|
||||
i2c[id]->speed = speed;
|
||||
i2c[id]->cycles_delay = 0;
|
||||
|
||||
if(i2c[id]->speed < MIN_SPEED){
|
||||
i2c[id]->speed = MIN_SPEED;
|
||||
}
|
||||
i2c_master_set_DC_delay(id); // recalibrate clock
|
||||
|
||||
ETS_GPIO_INTR_DISABLE(); //disable gpio interrupts
|
||||
|
||||
if (IS_PIN16(i2c[id]->pin_SCL)){ //if GPIO16
|
||||
CLEAR_PERI_REG_MASK(PAD_XPD_DCDC_CONF, 0x43); //disable all functions for XPD_DCDC
|
||||
SET_PERI_REG_MASK(PAD_XPD_DCDC_CONF, 0x1); // select function RTC_GPIO0 for pin XPD_DCDC
|
||||
CLEAR_PERI_REG_MASK(RTC_GPIO_CONF, 0x1); //mux configuration for out enable
|
||||
SET_PERI_REG_MASK(RTC_GPIO_ENABLE, 0x1); //out enable
|
||||
SET_PERI_REG_MASK(RTC_GPIO_OUT, 0x1); // set SCL high
|
||||
}
|
||||
else{
|
||||
PIN_FUNC_SELECT(pin_mux[scl], pin_func[scl]);
|
||||
SET_PERI_REG_MASK(PERIPHS_GPIO_BASEADDR + GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id]->pin_SCL)),
|
||||
GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain
|
||||
gpio_output_set(i2c[id]->pin_SCL_mask, 0, i2c[id]->pin_SCL_mask, 0); //enable and set high
|
||||
}
|
||||
PIN_FUNC_SELECT(pin_mux[sda], pin_func[sda]);
|
||||
SET_PERI_REG_MASK(PERIPHS_GPIO_BASEADDR + GPIO_PIN_ADDR(GPIO_ID_PIN(i2c[id]->pin_SDA)),
|
||||
GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain
|
||||
gpio_output_set(i2c[id]->pin_SDA_mask, 0, i2c[id]->pin_SDA_mask, 0); //enable and set high
|
||||
|
||||
ETS_GPIO_INTR_ENABLE(); //enable gpio interrupts
|
||||
|
||||
if (! (gpio_input_get() ^ i2c[id]->pin_SCL_mask)){ //SCL is in low state, bus failure
|
||||
return 0;
|
||||
}
|
||||
i2c_master_init(id);
|
||||
if (! (gpio_input_get() ^ i2c[id]->pin_SDA_mask)){ //SDA is in low state, bus failure
|
||||
return 0;
|
||||
}
|
||||
return i2c[id]->speed;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_start
|
||||
* Description : set i2c to send state
|
||||
* Parameters : bus id
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_start(uint16 id)
|
||||
{
|
||||
i2c_master_set_DC_delay(id); // recalibrate clock
|
||||
i2c_master_setDC(id, 1, i2c[id]->last_SCL);
|
||||
i2c_master_setDC(id, 1, 1);
|
||||
i2c_master_setDC(id, 0, 1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_stop
|
||||
* Description : set i2c to stop sending state
|
||||
* Parameters : bus id
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_stop(uint16 id)
|
||||
{
|
||||
i2c_master_setDC(id, 0, i2c[id]->last_SCL);
|
||||
i2c_master_setDC(id, 0, 1);
|
||||
i2c_master_setDC(id, 1, 1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_readByte
|
||||
* Description : read Byte from i2c bus
|
||||
* Parameters : bus id
|
||||
* Returns : uint8 - readed value
|
||||
*******************************************************************************/
|
||||
uint8 ICACHE_FLASH_ATTR
|
||||
i2c_master_readByte(uint16 id, sint16 ack)
|
||||
{
|
||||
uint8 retVal = 0;
|
||||
uint8 k;
|
||||
sint8 i;
|
||||
//invert and clamp ACK to 0/1, because ACK == 1 for i2c means SDA in low state
|
||||
uint8 ackLevel = (ack ? 0 : 1);
|
||||
|
||||
i2c_master_setDC(id, i2c[id]->last_SDA, 0);
|
||||
i2c_master_setDC(id, 1, 0);
|
||||
for (i = 7; i >= 0; i--) {
|
||||
i2c_master_setDC(id, 1, 1);
|
||||
k = i2c_master_getDC(id);
|
||||
i2c_master_setDC(id, 1, 0); // unnecessary in last iteration
|
||||
k <<= i;
|
||||
retVal |= k;
|
||||
}
|
||||
// set ACK
|
||||
i2c_master_setDC(id, ackLevel, 0);
|
||||
i2c_master_setDC(id, ackLevel, 1);
|
||||
i2c_master_setDC(id, 1, 0);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_writeByte
|
||||
* Description : write wrdata value(one byte) into i2c
|
||||
* Parameters : bus id, uint8 wrdata - write value
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
uint8 ICACHE_FLASH_ATTR
|
||||
i2c_master_writeByte(uint16 id, uint8 wrdata)
|
||||
{
|
||||
uint8 dat;
|
||||
sint8 i;
|
||||
uint8 retVal;
|
||||
|
||||
i2c_master_setDC(id, i2c[id]->last_SDA, 0);
|
||||
for (i = 7; i >= 0; i--) {
|
||||
dat = (wrdata >> i) & 1;
|
||||
i2c_master_setDC(id, dat, 0);
|
||||
i2c_master_setDC(id, dat, 1);
|
||||
}
|
||||
//get ACK
|
||||
i2c_master_setDC(id, 1, 0);
|
||||
i2c_master_setDC(id, 1, 1);
|
||||
retVal = i2c_master_getDC(id);
|
||||
i2c_master_setDC(id, 1, 0);
|
||||
return ! retVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else // if defined I2C_MASTER_OLD_VERSION
|
||||
/******************************************************************************
|
||||
* OLD driver
|
||||
* Enabled when I2C_MASTER_OLD_VERSION is defined in user_config.h
|
||||
*******************************************************************************/
|
||||
|
||||
#define I2C_MASTER_SDA_MUX (pin_mux[sda])
|
||||
#define I2C_MASTER_SCL_MUX (pin_mux[scl])
|
||||
#define I2C_MASTER_SDA_GPIO (pinSDA)
|
||||
#define I2C_MASTER_SCL_GPIO (pinSCL)
|
||||
#define I2C_MASTER_SDA_FUNC (pin_func[sda])
|
||||
#define I2C_MASTER_SCL_FUNC (pin_func[scl])
|
||||
#define I2C_MASTER_SDA_HIGH_SCL_HIGH() \
|
||||
gpio_output_set(1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
|
||||
#define I2C_MASTER_SDA_HIGH_SCL_LOW() \
|
||||
gpio_output_set(1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
|
||||
#define I2C_MASTER_SDA_LOW_SCL_HIGH() \
|
||||
gpio_output_set(1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
|
||||
#define I2C_MASTER_SDA_LOW_SCL_LOW() \
|
||||
gpio_output_set(0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
|
||||
#define i2c_master_wait os_delay_us
|
||||
#define I2C_MASTER_SPEED 100000
|
||||
#define I2C_MASTER_BUS_ID 0
|
||||
|
||||
LOCAL uint8 m_nLastSDA;
|
||||
LOCAL uint8 m_nLastSCL;
|
||||
|
@ -26,8 +427,7 @@ LOCAL uint8 pinSCL = 15;
|
|||
* FunctionName : i2c_master_setDC
|
||||
* Description : Internal used function -
|
||||
* set i2c SDA and SCL bit value for half clk cycle
|
||||
* Parameters : uint8 SDA
|
||||
* uint8 SCL
|
||||
* Parameters : uint8 SDA, uint8 SCL
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
LOCAL void ICACHE_FLASH_ATTR
|
||||
|
@ -49,11 +449,13 @@ i2c_master_setDC(uint8 SDA, uint8 SCL)
|
|||
} else {
|
||||
I2C_MASTER_SDA_HIGH_SCL_HIGH();
|
||||
}
|
||||
|
||||
if(1 == SCL) {
|
||||
do {
|
||||
sclLevel = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO));
|
||||
} while(sclLevel == 0);
|
||||
}
|
||||
i2c_master_wait(5);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -64,7 +466,7 @@ i2c_master_setDC(uint8 SDA, uint8 SCL)
|
|||
* Returns : uint8 - SDA bit value
|
||||
*******************************************************************************/
|
||||
LOCAL uint8 ICACHE_FLASH_ATTR
|
||||
i2c_master_getDC(void)
|
||||
i2c_master_getDC()
|
||||
{
|
||||
uint8 sda_out;
|
||||
sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
|
||||
|
@ -74,53 +476,52 @@ i2c_master_getDC(void)
|
|||
/******************************************************************************
|
||||
* FunctionName : i2c_master_init
|
||||
* Description : initilize I2C bus to enable i2c operations
|
||||
* Parameters : NONE
|
||||
* Parameters : bus id
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_init(void)
|
||||
i2c_master_init(uint16 id)
|
||||
{
|
||||
uint8 i;
|
||||
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
|
||||
// when SCL = 0, toggle SDA to clear up
|
||||
i2c_master_setDC(0, 0) ;
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0) ;
|
||||
i2c_master_wait(5);
|
||||
|
||||
// set data_cnt to max value
|
||||
for (i = 0; i < 28; i++) {
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
}
|
||||
|
||||
// reset all
|
||||
i2c_master_stop();
|
||||
i2c_master_stop(I2C_MASTER_BUS_ID);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 i2c_master_get_pinSDA(){
|
||||
return pinSDA;
|
||||
}
|
||||
|
||||
uint8 i2c_master_get_pinSCL(){
|
||||
return pinSCL;
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_configured
|
||||
* Description : checks if i2c bus is configured
|
||||
* Parameters : bus id
|
||||
* Returns : boolean value, true if configured
|
||||
*******************************************************************************/
|
||||
bool ICACHE_FLASH_ATTR
|
||||
i2c_master_configured(uint16 id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_gpio_init
|
||||
* FunctionName : i2c_master_setup
|
||||
* Description : config SDA and SCL gpio to open-drain output mode,
|
||||
* mux and gpio num defined in i2c_master.h
|
||||
* Parameters : NONE
|
||||
* Returns : NONE
|
||||
* Parameters : bus id, uint8 sda, uint8 scl, uint32 speed
|
||||
* Returns : configured speed
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_gpio_init(uint8 sda, uint8 scl)
|
||||
uint32 ICACHE_FLASH_ATTR
|
||||
i2c_master_setup(uint16 id, uint8 sda, uint8 scl, uint32 speed)
|
||||
{
|
||||
pinSDA = pin_num[sda];
|
||||
pinSCL = pin_num[scl];
|
||||
|
@ -141,152 +542,61 @@ i2c_master_gpio_init(uint8 sda, uint8 scl)
|
|||
ETS_GPIO_INTR_ENABLE() ;
|
||||
// ETS_INTR_UNLOCK();
|
||||
|
||||
i2c_master_init();
|
||||
i2c_master_init(I2C_MASTER_BUS_ID);
|
||||
|
||||
return I2C_MASTER_SPEED;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_start
|
||||
* Description : set i2c to send state
|
||||
* Parameters : NONE
|
||||
* Parameters : bus id
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_start(void)
|
||||
i2c_master_start(uint16 id)
|
||||
{
|
||||
i2c_master_setDC(1, m_nLastSCL);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
i2c_master_setDC(0, 1);
|
||||
i2c_master_wait(5); // sda 0, scl 1
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_stop
|
||||
* Description : set i2c to stop sending state
|
||||
* Parameters : NONE
|
||||
* Parameters : bus id
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_stop(void)
|
||||
i2c_master_stop(uint16 id)
|
||||
{
|
||||
i2c_master_wait(5);
|
||||
|
||||
i2c_master_setDC(0, m_nLastSCL);
|
||||
i2c_master_wait(5); // sda 0
|
||||
i2c_master_setDC(0, 1);
|
||||
i2c_master_wait(5); // sda 0, scl 1
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_setAck
|
||||
* Description : set ack to i2c bus as level value
|
||||
* Parameters : uint8 level - 0 or 1
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_setAck(uint8 level)
|
||||
{
|
||||
i2c_master_setDC(m_nLastSDA, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(level, 0);
|
||||
i2c_master_wait(5); // sda level, scl 0
|
||||
i2c_master_setDC(level, 1);
|
||||
i2c_master_wait(8); // sda level, scl 1
|
||||
i2c_master_setDC(level, 0);
|
||||
i2c_master_wait(5); // sda level, scl 0
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_getAck
|
||||
* Description : confirm if peer send ack
|
||||
* Parameters : NONE
|
||||
* Returns : uint8 - ack value, 0 or 1
|
||||
*******************************************************************************/
|
||||
uint8 ICACHE_FLASH_ATTR
|
||||
i2c_master_getAck(void)
|
||||
{
|
||||
uint8 retVal;
|
||||
i2c_master_setDC(m_nLastSDA, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5);
|
||||
|
||||
retVal = i2c_master_getDC();
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_checkAck
|
||||
* Description : get dev response
|
||||
* Parameters : NONE
|
||||
* Returns : true : get ack ; false : get nack
|
||||
*******************************************************************************/
|
||||
bool ICACHE_FLASH_ATTR
|
||||
i2c_master_checkAck(void)
|
||||
{
|
||||
if(i2c_master_getAck()){
|
||||
return FALSE;
|
||||
}else{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_send_ack
|
||||
* Description : response ack
|
||||
* Parameters : NONE
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_send_ack(void)
|
||||
{
|
||||
i2c_master_setAck(0x0);
|
||||
}
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_send_nack
|
||||
* Description : response nack
|
||||
* Parameters : NONE
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_send_nack(void)
|
||||
{
|
||||
i2c_master_setAck(0x1);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_readByte
|
||||
* Description : read Byte from i2c bus
|
||||
* Parameters : NONE
|
||||
* Parameters : bus id
|
||||
* Returns : uint8 - readed value
|
||||
*******************************************************************************/
|
||||
uint8 ICACHE_FLASH_ATTR
|
||||
i2c_master_readByte(void)
|
||||
i2c_master_readByte(uint16 id, sint16 ack)
|
||||
{
|
||||
uint8 retVal = 0;
|
||||
uint8 k, i;
|
||||
uint8 ackLevel = (ack ? 0 : 1);
|
||||
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(m_nLastSDA, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
i2c_master_setDC(1, 1);
|
||||
i2c_master_wait(5); // sda 1, scl 1
|
||||
|
||||
k = i2c_master_getDC();
|
||||
i2c_master_wait(5);
|
||||
|
@ -300,40 +610,51 @@ i2c_master_readByte(void)
|
|||
}
|
||||
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_wait(5); // sda 1, scl 0
|
||||
|
||||
// set ACK
|
||||
i2c_master_setDC(m_nLastSDA, 0);
|
||||
i2c_master_setDC(ackLevel, 0);
|
||||
i2c_master_setDC(ackLevel, 1);
|
||||
i2c_master_wait(3);
|
||||
i2c_master_setDC(ackLevel, 0);
|
||||
i2c_master_setDC(1, 0);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : i2c_master_writeByte
|
||||
* Description : write wrdata value(one byte) into i2c
|
||||
* Parameters : uint8 wrdata - write value
|
||||
* Parameters : bus id, uint8 wrdata - write value
|
||||
* Returns : NONE
|
||||
*******************************************************************************/
|
||||
void ICACHE_FLASH_ATTR
|
||||
i2c_master_writeByte(uint8 wrdata)
|
||||
uint8 ICACHE_FLASH_ATTR
|
||||
i2c_master_writeByte(uint16 id, uint8 wrdata)
|
||||
{
|
||||
uint8 dat;
|
||||
sint8 i;
|
||||
uint8 retVal;
|
||||
|
||||
i2c_master_wait(5);
|
||||
|
||||
i2c_master_setDC(m_nLastSDA, 0);
|
||||
i2c_master_wait(5);
|
||||
|
||||
for (i = 7; i >= 0; i--) {
|
||||
dat = wrdata >> i;
|
||||
i2c_master_setDC(dat, 0);
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(dat, 1);
|
||||
i2c_master_wait(5);
|
||||
|
||||
if (i == 0) {
|
||||
i2c_master_wait(3); ////
|
||||
}
|
||||
|
||||
i2c_master_setDC(dat, 0);
|
||||
i2c_master_wait(5);
|
||||
}
|
||||
// get ACK
|
||||
i2c_master_setDC(m_nLastSDA, 0);
|
||||
i2c_master_setDC(1, 0);
|
||||
i2c_master_setDC(1, 1);
|
||||
retVal = i2c_master_getDC();
|
||||
i2c_master_wait(5);
|
||||
i2c_master_setDC(1, 0);
|
||||
return ! retVal;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,74 +1,12 @@
|
|||
#ifndef __I2C_MASTER_H__
|
||||
#define __I2C_MASTER_H__
|
||||
|
||||
#define I2C_MASTER_SDA_MUX (pin_mux[sda])
|
||||
#define I2C_MASTER_SCL_MUX (pin_mux[scl])
|
||||
#define I2C_MASTER_SDA_GPIO (pinSDA)
|
||||
#define I2C_MASTER_SCL_GPIO (pinSCL)
|
||||
#define I2C_MASTER_SDA_FUNC (pin_func[sda])
|
||||
#define I2C_MASTER_SCL_FUNC (pin_func[scl])
|
||||
uint32 i2c_master_setup(uint16 id, uint8 sda, uint8 scl, uint32 speed);
|
||||
void i2c_master_init(uint16 id);
|
||||
bool i2c_master_configured(uint16 id);
|
||||
void i2c_master_stop(uint16 id);
|
||||
void i2c_master_start(uint16 id);
|
||||
uint8 i2c_master_readByte(uint16 id, sint16 ack);
|
||||
uint8 i2c_master_writeByte(uint16 id, uint8 wrdata);
|
||||
|
||||
// #define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
|
||||
// #define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTDO_U
|
||||
// #define I2C_MASTER_SDA_GPIO 2
|
||||
// #define I2C_MASTER_SCL_GPIO 15
|
||||
// #define I2C_MASTER_SDA_FUNC FUNC_GPIO2
|
||||
// #define I2C_MASTER_SCL_FUNC FUNC_GPIO15
|
||||
|
||||
// #define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
|
||||
// #define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTMS_U
|
||||
// #define I2C_MASTER_SDA_GPIO 2
|
||||
// #define I2C_MASTER_SCL_GPIO 14
|
||||
// #define I2C_MASTER_SDA_FUNC FUNC_GPIO2
|
||||
// #define I2C_MASTER_SCL_FUNC FUNC_GPIO14
|
||||
|
||||
//#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
|
||||
//#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_GPIO0_U
|
||||
//#define I2C_MASTER_SDA_GPIO 2
|
||||
//#define I2C_MASTER_SCL_GPIO 0
|
||||
//#define I2C_MASTER_SDA_FUNC FUNC_GPIO2
|
||||
//#define I2C_MASTER_SCL_FUNC FUNC_GPIO0
|
||||
|
||||
#if 0
|
||||
#define I2C_MASTER_GPIO_SET(pin) \
|
||||
gpio_output_set(1<<pin,0,1<<pin,0)
|
||||
|
||||
#define I2C_MASTER_GPIO_CLR(pin) \
|
||||
gpio_output_set(0,1<<pin,1<<pin,0)
|
||||
|
||||
#define I2C_MASTER_GPIO_OUT(pin,val) \
|
||||
if(val) I2C_MASTER_GPIO_SET(pin);\
|
||||
else I2C_MASTER_GPIO_CLR(pin)
|
||||
#endif
|
||||
|
||||
#define I2C_MASTER_SDA_HIGH_SCL_HIGH() \
|
||||
gpio_output_set(1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
|
||||
|
||||
#define I2C_MASTER_SDA_HIGH_SCL_LOW() \
|
||||
gpio_output_set(1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
|
||||
|
||||
#define I2C_MASTER_SDA_LOW_SCL_HIGH() \
|
||||
gpio_output_set(1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
|
||||
|
||||
#define I2C_MASTER_SDA_LOW_SCL_LOW() \
|
||||
gpio_output_set(0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
|
||||
|
||||
void i2c_master_gpio_init(uint8 sda, uint8 scl);
|
||||
void i2c_master_init(void);
|
||||
|
||||
#define i2c_master_wait os_delay_us
|
||||
void i2c_master_stop(void);
|
||||
void i2c_master_start(void);
|
||||
void i2c_master_setAck(uint8 level);
|
||||
uint8 i2c_master_getAck(void);
|
||||
uint8 i2c_master_readByte(void);
|
||||
void i2c_master_writeByte(uint8 wrdata);
|
||||
|
||||
bool i2c_master_checkAck(void);
|
||||
void i2c_master_send_ack(void);
|
||||
void i2c_master_send_nack(void);
|
||||
|
||||
uint8 i2c_master_get_pinSDA();
|
||||
uint8 i2c_master_get_pinSCL();
|
||||
|
||||
#endif
|
||||
#endif //__I2C_MASTER_H__
|
||||
|
|
|
@ -156,6 +156,22 @@
|
|||
#define ENDUSER_SETUP_AP_SSID "SetupGadget"
|
||||
|
||||
|
||||
// I2C software driver partially supports use of GPIO16 (D0) pin for SCL line.
|
||||
// GPIO16 does not support open-drain mode and works in push-pull mode,
|
||||
// so clock stretching will not be possible, because circuit in slave device that
|
||||
// supposed to drive SCL low during stretching will not be capable to hold SCL low.
|
||||
// Also I2C speed will be limited to no more than 400000 Hz (FAST mode).
|
||||
// This define is does not have an effect on an old driver (see I2C_MASTER_OLD_VERSION).
|
||||
|
||||
//#define I2C_MASTER_GPIO16_ENABLE
|
||||
|
||||
// For compatibility reasons you can switch to old version of I2C software driver.
|
||||
// It does not support changing speed, have only one bus id = 0, does not support GPIO16
|
||||
// and works only in Standard(slow) mode with clock speed around 50kHz.
|
||||
|
||||
#define I2C_MASTER_OLD_VERSION
|
||||
|
||||
|
||||
// The following sections are only relevent for those developers who are
|
||||
// developing modules or core Lua changes and configure how extra diagnostics
|
||||
// are enabled in the firmware. These should only be configured if you are
|
||||
|
|
|
@ -15,13 +15,16 @@ static int i2c_setup( lua_State *L )
|
|||
MOD_CHECK_ID( gpio, sda );
|
||||
MOD_CHECK_ID( gpio, scl );
|
||||
|
||||
if(scl==0 || sda==0)
|
||||
return luaL_error( L, "no i2c for D0" );
|
||||
if ( sda == 0 )
|
||||
return luaL_error( L, "i2c SDA on D0 is not supported" );
|
||||
|
||||
s32 speed = ( s32 )luaL_checkinteger( L, 4 );
|
||||
if (speed <= 0)
|
||||
if ( speed <= 0 )
|
||||
return luaL_error( L, "wrong arg range" );
|
||||
lua_pushinteger( L, platform_i2c_setup( id, sda, scl, (u32)speed ) );
|
||||
speed = platform_i2c_setup( id, sda, scl, (u32)speed );
|
||||
if ( speed == 0 )
|
||||
return luaL_error( L, "failed to initialize i2c %d", id );
|
||||
lua_pushinteger( L, speed );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -31,7 +34,10 @@ static int i2c_start( lua_State *L )
|
|||
unsigned id = luaL_checkinteger( L, 1 );
|
||||
|
||||
MOD_CHECK_ID( i2c, id );
|
||||
platform_i2c_send_start( id );
|
||||
if (platform_i2c_configured( id ) )
|
||||
platform_i2c_send_start( id );
|
||||
else
|
||||
luaL_error( L, "i2c %d is not configured", id );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -147,7 +153,8 @@ static const LUA_REG_TYPE i2c_map[] = {
|
|||
{ LSTRKEY( "address" ), LFUNCVAL( i2c_address ) },
|
||||
{ LSTRKEY( "write" ), LFUNCVAL( i2c_write ) },
|
||||
{ LSTRKEY( "read" ), LFUNCVAL( i2c_read ) },
|
||||
//{ LSTRKEY( "FAST" ), LNUMVAL( PLATFORM_I2C_SPEED_FAST ) },
|
||||
{ LSTRKEY( "FASTPLUS" ), LNUMVAL( PLATFORM_I2C_SPEED_FASTPLUS ) },
|
||||
{ LSTRKEY( "FAST" ), LNUMVAL( PLATFORM_I2C_SPEED_FAST ) },
|
||||
{ LSTRKEY( "SLOW" ), LNUMVAL( PLATFORM_I2C_SPEED_SLOW ) },
|
||||
{ LSTRKEY( "TRANSMITTER" ), LNUMVAL( PLATFORM_I2C_DIRECTION_TRANSMITTER ) },
|
||||
{ LSTRKEY( "RECEIVER" ), LNUMVAL( PLATFORM_I2C_DIRECTION_RECEIVER ) },
|
||||
|
|
|
@ -15,7 +15,13 @@
|
|||
#define NUM_PWM GPIO_PIN_NUM
|
||||
#define NUM_ADC 1
|
||||
#define NUM_CAN 0
|
||||
|
||||
#ifndef I2C_MASTER_OLD_VERSION
|
||||
#define NUM_I2C 10
|
||||
#else
|
||||
#define NUM_I2C 1
|
||||
#endif //I2C_MASTER_OLD_VERSION
|
||||
|
||||
#define NUM_OW GPIO_PIN_NUM
|
||||
#define NUM_TMR 7
|
||||
|
||||
|
|
|
@ -735,16 +735,19 @@ uint32_t platform_i2c_setup( unsigned id, uint8_t sda, uint8_t scl, uint32_t spe
|
|||
platform_gpio_mode(sda, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); // inside this func call platform_pwm_close
|
||||
platform_gpio_mode(scl, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP); // disable gpio interrupt first
|
||||
|
||||
i2c_master_gpio_init(sda, scl);
|
||||
return PLATFORM_I2C_SPEED_SLOW;
|
||||
return i2c_master_setup(id, sda, scl, speed);
|
||||
}
|
||||
|
||||
bool platform_i2c_configured( unsigned id ){
|
||||
return i2c_master_configured(id);
|
||||
}
|
||||
|
||||
void platform_i2c_send_start( unsigned id ){
|
||||
i2c_master_start();
|
||||
i2c_master_start(id);
|
||||
}
|
||||
|
||||
void platform_i2c_send_stop( unsigned id ){
|
||||
i2c_master_stop();
|
||||
i2c_master_stop(id);
|
||||
}
|
||||
|
||||
int platform_i2c_send_address( unsigned id, uint16_t address, int direction ){
|
||||
|
@ -754,22 +757,17 @@ int platform_i2c_send_address( unsigned id, uint16_t address, int direction ){
|
|||
PLATFORM_I2C_DIRECTION_RECEIVER == 1 ) ) {
|
||||
direction = ( direction == PLATFORM_I2C_DIRECTION_TRANSMITTER ) ? 0 : 1;
|
||||
}
|
||||
|
||||
i2c_master_writeByte( (uint8_t) ((address << 1) | direction ));
|
||||
// Low-level returns nack (0=acked); we return ack (1=acked).
|
||||
return ! i2c_master_getAck();
|
||||
return i2c_master_writeByte(id,
|
||||
(uint8_t) ((address << 1) + (direction == PLATFORM_I2C_DIRECTION_TRANSMITTER ? 0 : 1))
|
||||
);
|
||||
}
|
||||
|
||||
int platform_i2c_send_byte( unsigned id, uint8_t data ){
|
||||
i2c_master_writeByte(data);
|
||||
// Low-level returns nack (0=acked); we return ack (1=acked).
|
||||
return ! i2c_master_getAck();
|
||||
int platform_i2c_send_byte(unsigned id, uint8_t data ){
|
||||
return i2c_master_writeByte(id, data);
|
||||
}
|
||||
|
||||
int platform_i2c_recv_byte( unsigned id, int ack ){
|
||||
uint8_t r = i2c_master_readByte();
|
||||
i2c_master_setAck( !ack );
|
||||
return r;
|
||||
return i2c_master_readByte(id, ack);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
|
|
@ -235,7 +235,8 @@ void platform_sigma_delta_set_target( uint8_t target );
|
|||
enum
|
||||
{
|
||||
PLATFORM_I2C_SPEED_SLOW = 100000,
|
||||
PLATFORM_I2C_SPEED_FAST = 400000
|
||||
PLATFORM_I2C_SPEED_FAST = 400000,
|
||||
PLATFORM_I2C_SPEED_FASTPLUS = 1000000
|
||||
};
|
||||
|
||||
// I2C direction
|
||||
|
@ -251,6 +252,7 @@ static inline int platform_i2c_exists( unsigned id ) { return id < NUM_I2C; }
|
|||
static inline int platform_i2c_exists( unsigned id ) { return 0; }
|
||||
#endif
|
||||
uint32_t platform_i2c_setup( unsigned id, uint8_t sda, uint8_t scl, uint32_t speed );
|
||||
bool platform_i2c_configured( unsigned id );
|
||||
void platform_i2c_send_start( unsigned id );
|
||||
void platform_i2c_send_stop( unsigned id );
|
||||
int platform_i2c_send_address( unsigned id, uint16_t address, int direction );
|
||||
|
|
|
@ -2,16 +2,56 @@
|
|||
| Since | Origin / Contributor | Maintainer | Source |
|
||||
| :----- | :-------------------- | :---------- | :------ |
|
||||
| 2014-12-22 | [Zeroday](https://github.com/funshine) | [Zeroday](https://github.com/funshine) | [i2c.c](../../app/modules/i2c.c)|
|
||||
| 2018-08-30 | [Natalia Sorokina](https://github.com/sonaux) | | [i2c_master.c](../../app/driver/i2c_master.c)|
|
||||
|
||||
I²C (I2C, IIC) is a serial 2-wire bus for communicating with various devices. Also known as SMBus or TWI, though SMBus have some additions to the I2C protocol.
|
||||
ESP8266 chip does not have hardware I²C, so module uses software I²C driver.
|
||||
It can be set up on any GPIO pins including GPIO16 (see below).
|
||||
|
||||
This module supports:
|
||||
- Master mode
|
||||
- Multiple buses (up to 10) with different speeds on each bus
|
||||
- Standard(Slow, 100kHz), Fast(400kHz) and FastPlus(1MHz) modes or an arbitrary clock speed
|
||||
- Clock stretching (slow slave device can tell the master to wait)
|
||||
- Sharing SDA line over multiple I²C buses to save available pins
|
||||
- GPIO16 pin can be used as SCL pin, but selected bus will be limited to not more than FAST speed.
|
||||
|
||||
HIGH-speed mode (3.5MHz clock) and 10-bit addressing scheme is not supported.
|
||||
|
||||
You have to call `i2c.setup` on a given I²C bus at least once before communicating to any device connected to that bus, otherwise you will get an error.
|
||||
|
||||
I²C bus designed to work in open-drain mode, so it needs pull-up resistors 1k - 10k on SDA and SCL lines. Though many peripheral modules have pull-up resistors onboard and will work without additional external resistors.
|
||||
|
||||
Hint for using many identical devices with same address:
|
||||
Many devices allow to choose between 2 I²C addresses via pin or soldered 0 Ohm resistor.
|
||||
If address change is not an option or you need to use more than 2 similar devices, you can use different I²C buses.
|
||||
Initialize them once by calling `i2c.setup` with different bus numbers and pins, then refer to each device by bus id and device address.
|
||||
SCL pins should be different, SDA can be shared on one pin.
|
||||
|
||||
Note that historically many NodeMCU drivers and modules assumed that only a single I²C bus with id 0 is available, so it is always safer to start with id 0 as first bus in your code.
|
||||
If your device driver functions do not have I²C bus id as an input parameter and/or not built with Lua OOP principles then most probably device will be accessible through bus id 0 only and must be connected to its pins.
|
||||
|
||||
To enable new driver comment line `#define I2C_MASTER_OLD_VERSION` in `user_config.h`
|
||||
|
||||
To enable support for GPIO16 (D0) uncomment line `#define I2C_MASTER_GPIO16_ENABLED` in `user_config.h`
|
||||
|
||||
GPIO16 does not support open-drain mode and works in push-pull mode. That may lead to communication errors when slave device tries to stretch SCL clock but unable to hold SCL line low. If that happens, try setting lower I²C speed.
|
||||
|
||||
!!! caution
|
||||
|
||||
If your module reboots when trying to use GPIO16 pin, then it is wired to RESET pin to support deep sleep mode and you cannot use GPIO16 for I²C bus or other purposes.
|
||||
|
||||
|
||||
## i2c.address()
|
||||
Setup I²C address and read/write mode for the next transfer.
|
||||
On I²C bus every device is addressed by 7-bit number. Address for the particular device can be found in its datasheet.
|
||||
|
||||
#### Syntax
|
||||
`i2c.address(id, device_addr, direction)`
|
||||
|
||||
#### Parameters
|
||||
- `id` always 0
|
||||
- `device_addr` 7-bit device address, remember that [in I²C `device_addr` represents the upper 7 bits](http://www.nxp.com/documents/user_manual/UM10204.pdf#page=13) followed by a single `direction` bit
|
||||
- `id` bus number
|
||||
- `device_addr` 7-bit device address. Remember that [in I²C `device_addr` represents the upper 7 bits](http://www.nxp.com/documents/user_manual/UM10204.pdf#page=13) followed by a single `direction` bit. Sometimes device address is advertised as 8-bit value, then you should divide it by 2 to get 7-bit value.
|
||||
- `direction` `i2c.TRANSMITTER` for writing mode , `i2c. RECEIVER` for reading mode
|
||||
|
||||
#### Returns
|
||||
|
@ -27,7 +67,7 @@ Read data for variable number of bytes.
|
|||
`i2c.read(id, len)`
|
||||
|
||||
#### Parameters
|
||||
- `id` always 0
|
||||
- `id` bus number
|
||||
- `len` number of data bytes
|
||||
|
||||
#### Returns
|
||||
|
@ -39,11 +79,11 @@ id = 0
|
|||
sda = 1
|
||||
scl = 2
|
||||
|
||||
-- initialize i2c, set pin1 as sda, set pin2 as scl
|
||||
i2c.setup(id, sda, scl, i2c.SLOW)
|
||||
-- initialize i2c, set pin 1 as sda, set pin 2 as scl
|
||||
i2c.setup(id, sda, scl, i2c.FAST)
|
||||
|
||||
-- user defined function: read from reg_addr content of dev_addr
|
||||
function read_reg(dev_addr, reg_addr)
|
||||
-- user defined function: read 1 byte of data from device
|
||||
function read_reg(id, dev_addr, reg_addr)
|
||||
i2c.start(id)
|
||||
i2c.address(id, dev_addr, i2c.TRANSMITTER)
|
||||
i2c.write(id, reg_addr)
|
||||
|
@ -56,29 +96,51 @@ function read_reg(dev_addr, reg_addr)
|
|||
end
|
||||
|
||||
-- get content of register 0xAA of device 0x77
|
||||
reg = read_reg(0x77, 0xAA)
|
||||
reg = read_reg(id, 0x77, 0xAA)
|
||||
print(string.byte(reg))
|
||||
```
|
||||
|
||||
####See also
|
||||
#### See also
|
||||
[i2c.write()](#i2cwrite)
|
||||
|
||||
## i2c.setup()
|
||||
Initialize the I²C module.
|
||||
Initialize the I²C bus with the selected bus number, pins and speed.
|
||||
|
||||
#### Syntax
|
||||
`i2c.setup(id, pinSDA, pinSCL, speed)`
|
||||
|
||||
####Parameters
|
||||
- `id` always 0
|
||||
#### Parameters
|
||||
- `id` 0~9, bus number
|
||||
- `pinSDA` 1~12, IO index
|
||||
- `pinSCL` 1~12, IO index
|
||||
- `speed` only `i2c.SLOW` supported
|
||||
- `pinSCL` 0~12, IO index
|
||||
- `speed` `i2c.SLOW` (100kHz), `i2c.FAST` (400kHz), `i2c.FASTPLUS` (1MHz) or any clock frequency in range of 25000-1000000 Hz.
|
||||
FASTPLUS mode results in 600kHz I2C clock speed at default 80MHz CPU frequency. To get 1MHz I2C clock speed change CPU frequency to 160MHz with function `node.setcpufreq(node.CPU160MHZ)`.
|
||||
|
||||
#### Returns
|
||||
`speed` the selected speed
|
||||
`speed` the selected speed, `0` if bus initialization error.
|
||||
|
||||
####See also
|
||||
#### Example
|
||||
```lua
|
||||
i2c0 = {
|
||||
id = 0,
|
||||
sda = 1,
|
||||
scl = 0,
|
||||
speed = i2c.FAST
|
||||
}
|
||||
i2c1 = {
|
||||
id = 1,
|
||||
sda = 1,
|
||||
scl = 2,
|
||||
speed = i2c.FASTPLUS
|
||||
}
|
||||
-- initialize i2c bus 0
|
||||
i2c0.speed = i2c.setup(i2c0.id, i2c0.sda, i2c0.scl, i2c0.speed)
|
||||
-- initialize i2c bus 1 with shared SDA on pin 1
|
||||
node.setcpufreq(node.CPU160MHZ) -- to support FASTPLUS speed
|
||||
i2c1.speed = i2c.setup(i2c1.id, i2c1.sda, i2c1.scl, i2c1.speed)
|
||||
print("i2c bus 0 speed: ", i2c0.speed, "i2c bus 1 speed: ", i2c1.speed)
|
||||
```
|
||||
#### See also
|
||||
[i2c.read()](#i2cread)
|
||||
|
||||
## i2c.start()
|
||||
|
@ -88,12 +150,12 @@ Send an I²C start condition.
|
|||
`i2c.start(id)`
|
||||
|
||||
#### Parameters
|
||||
`id` always 0
|
||||
`id` bus number
|
||||
|
||||
#### Returns
|
||||
`nil`
|
||||
|
||||
####See also
|
||||
#### See also
|
||||
[i2c.read()](#i2cread)
|
||||
|
||||
## i2c.stop()
|
||||
|
@ -102,23 +164,23 @@ Send an I²C stop condition.
|
|||
#### Syntax
|
||||
`i2c.stop(id)`
|
||||
|
||||
####Parameters
|
||||
`id` always 0
|
||||
#### Parameters
|
||||
`id` bus number
|
||||
|
||||
#### Returns
|
||||
`nil`
|
||||
|
||||
####See also
|
||||
#### See also
|
||||
[i2c.read()](#i2cread)
|
||||
|
||||
## i2c.write()
|
||||
Write data to I²C bus. Data items can be multiple numbers, strings or Lua tables.
|
||||
|
||||
####Syntax
|
||||
#### Syntax
|
||||
`i2c.write(id, data1[, data2[, ..., datan]])`
|
||||
|
||||
####Parameters
|
||||
- `id` always 0
|
||||
#### Parameters
|
||||
- `id` bus number
|
||||
- `data` data can be numbers, string or Lua table.
|
||||
|
||||
#### Returns
|
||||
|
@ -126,7 +188,30 @@ Write data to I²C bus. Data items can be multiple numbers, strings or Lua table
|
|||
|
||||
#### Example
|
||||
```lua
|
||||
i2c.write(0, "hello", "world")
|
||||
id = 0
|
||||
sda = 1
|
||||
scl = 2
|
||||
|
||||
-- initialize i2c, set pin 1 as sda, set pin 2 as scl
|
||||
i2c.setup(id, sda, scl, i2c.FAST)
|
||||
|
||||
-- user defined function: write some data to device
|
||||
-- with address dev_addr starting from reg_addr
|
||||
function write_reg(id, dev_addr, reg_addr, data)
|
||||
i2c.start(id)
|
||||
i2c.address(id, dev_addr, i2c.TRANSMITTER)
|
||||
i2c.write(id, reg_addr)
|
||||
c = i2c.write(id, data)
|
||||
i2c.stop(id)
|
||||
return c
|
||||
end
|
||||
-- set register with address 0x45 of device 0x77 with value 1
|
||||
count = write_reg(id, 0x77, 0x45, 1)
|
||||
print(count, " bytes written")
|
||||
|
||||
-- write text into i2c EEPROM starting with memory address 0
|
||||
count = write_reg(id, 0x50, 0, "Sample")
|
||||
print(count, " bytes written")
|
||||
```
|
||||
|
||||
#### See also
|
||||
|
|
Loading…
Reference in New Issue