Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
arduino-esp32
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
xpstem
arduino-esp32
Commits
ed53b6c8
Unverified
Commit
ed53b6c8
authored
Oct 14, 2021
by
Me No Dev
Committed by
GitHub
Oct 14, 2021
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #5746 from espressif/i2c-slave
I2C Slave Implementation
parents
2e53300d
b145e659
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1160 additions
and
40 deletions
+1160
-40
CMakeLists.txt
CMakeLists.txt
+1
-0
cores/esp32/esp32-hal-i2c-slave.c
cores/esp32/esp32-hal-i2c-slave.c
+848
-0
cores/esp32/esp32-hal-i2c-slave.h
cores/esp32/esp32-hal-i2c-slave.h
+35
-0
libraries/Wire/examples/WireMaster/WireMaster.ino
libraries/Wire/examples/WireMaster/WireMaster.ino
+30
-0
libraries/Wire/examples/WireScan/WireScan.ino
libraries/Wire/examples/WireScan/WireScan.ino
+28
-0
libraries/Wire/examples/WireSlave/WireSlave.ino
libraries/Wire/examples/WireSlave/WireSlave.ino
+37
-0
libraries/Wire/src/Wire.cpp
libraries/Wire/src/Wire.cpp
+172
-40
libraries/Wire/src/Wire.h
libraries/Wire/src/Wire.h
+9
-0
No files found.
CMakeLists.txt
View file @
ed53b6c8
...
@@ -7,6 +7,7 @@ set(CORE_SRCS
...
@@ -7,6 +7,7 @@ set(CORE_SRCS
cores/esp32/esp32-hal-dac.c
cores/esp32/esp32-hal-dac.c
cores/esp32/esp32-hal-gpio.c
cores/esp32/esp32-hal-gpio.c
cores/esp32/esp32-hal-i2c.c
cores/esp32/esp32-hal-i2c.c
cores/esp32/esp32-hal-i2c-slave.c
cores/esp32/esp32-hal-ledc.c
cores/esp32/esp32-hal-ledc.c
cores/esp32/esp32-hal-matrix.c
cores/esp32/esp32-hal-matrix.c
cores/esp32/esp32-hal-misc.c
cores/esp32/esp32-hal-misc.c
...
...
cores/esp32/esp32-hal-i2c-slave.c
0 → 100755
View file @
ed53b6c8
// Copyright 2015-2021 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 <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <inttypes.h>
#include <string.h>
#include <math.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "rom/gpio.h"
#include "soc/gpio_sig_map.h"
#include "hal/gpio_types.h"
#include "driver/gpio.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/ringbuf.h"
#include "esp_intr_alloc.h"
#include "driver/periph_ctrl.h"
#include "soc/i2c_reg.h"
#include "soc/i2c_struct.h"
#include "hal/i2c_ll.h"
#include "esp32-hal-log.h"
#include "esp32-hal-i2c-slave.h"
#define I2C_SLAVE_USE_RX_QUEUE 0 // 1: Queue, 0: RingBuffer
#if SOC_I2C_NUM > 1
#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
#define I2C_SDA_IDX(p) ((p==0)?I2CEXT0_SDA_OUT_IDX:((p==1)?I2CEXT1_SDA_OUT_IDX:0))
#else
#define I2C_SCL_IDX(p) I2CEXT0_SCL_OUT_IDX
#define I2C_SDA_IDX(p) I2CEXT0_SDA_OUT_IDX
#endif
#if CONFIG_IDF_TARGET_ESP32
#define I2C_TXFIFO_WM_INT_ENA I2C_TXFIFO_EMPTY_INT_ENA
#define I2C_RXFIFO_WM_INT_ENA I2C_RXFIFO_FULL_INT_ENA
#endif
enum
{
I2C_SLAVE_EVT_RX
,
I2C_SLAVE_EVT_TX
};
typedef
struct
i2c_slave_struct_t
{
i2c_dev_t
*
dev
;
uint8_t
num
;
int8_t
sda
;
int8_t
scl
;
i2c_slave_request_cb_t
request_callback
;
i2c_slave_receive_cb_t
receive_callback
;
void
*
arg
;
intr_handle_t
intr_handle
;
TaskHandle_t
task_handle
;
xQueueHandle
event_queue
;
#if I2C_SLAVE_USE_RX_QUEUE
xQueueHandle
rx_queue
;
#else
RingbufHandle_t
rx_ring_buf
;
#endif
xQueueHandle
tx_queue
;
uint32_t
rx_data_count
;
#if !CONFIG_DISABLE_HAL_LOCKS
xSemaphoreHandle
lock
;
#endif
}
i2c_slave_struct_t
;
typedef
union
{
struct
{
uint32_t
event
:
2
;
uint32_t
stop
:
1
;
uint32_t
param
:
29
;
};
uint32_t
val
;
}
i2c_slave_queue_event_t
;
static
i2c_slave_struct_t
_i2c_bus_array
[
SOC_I2C_NUM
]
=
{
{
&
I2C0
,
0
,
-
1
,
-
1
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
0
#if !CONFIG_DISABLE_HAL_LOCKS
,
NULL
#endif
},
#if SOC_I2C_NUM > 1
{
&
I2C1
,
1
,
-
1
,
-
1
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
0
#if !CONFIG_DISABLE_HAL_LOCKS
,
NULL
#endif
}
#endif
};
#if CONFIG_DISABLE_HAL_LOCKS
#define I2C_SLAVE_MUTEX_LOCK()
#define I2C_SLAVE_MUTEX_UNLOCK()
#else
#define I2C_SLAVE_MUTEX_LOCK() if(i2c->lock){xSemaphoreTake(i2c->lock, portMAX_DELAY);}
#define I2C_SLAVE_MUTEX_UNLOCK() if(i2c->lock){xSemaphoreGive(i2c->lock);}
#endif
//-------------------------------------- HAL_LL (Missing Functions) ------------------------------------------------
typedef
enum
{
I2C_STRETCH_CAUSE_MASTER_READ
,
I2C_STRETCH_CAUSE_TX_FIFO_EMPTY
,
I2C_STRETCH_CAUSE_RX_FIFO_FULL
,
I2C_STRETCH_CAUSE_MAX
}
i2c_stretch_cause_t
;
static
inline
i2c_stretch_cause_t
i2c_ll_stretch_cause
(
i2c_dev_t
*
hw
)
{
#if CONFIG_IDF_TARGET_ESP32C3
return
hw
->
sr
.
stretch_cause
;
#elif CONFIG_IDF_TARGET_ESP32S2
return
hw
->
status_reg
.
stretch_cause
;
#else
return
I2C_STRETCH_CAUSE_MAX
;
#endif
}
static
inline
void
i2c_ll_set_stretch
(
i2c_dev_t
*
hw
,
uint16_t
time
)
{
#ifndef CONFIG_IDF_TARGET_ESP32
typeof
(
hw
->
scl_stretch_conf
)
scl_stretch_conf
;
scl_stretch_conf
.
val
=
0
;
scl_stretch_conf
.
slave_scl_stretch_en
=
(
time
>
0
);
scl_stretch_conf
.
stretch_protect_num
=
time
;
scl_stretch_conf
.
slave_scl_stretch_clr
=
1
;
hw
->
scl_stretch_conf
.
val
=
scl_stretch_conf
.
val
;
if
(
time
>
0
){
//enable interrupt
hw
->
int_ena
.
val
|=
I2C_SLAVE_STRETCH_INT_ENA
;
}
else
{
//disable interrupt
hw
->
int_ena
.
val
&=
(
~
I2C_SLAVE_STRETCH_INT_ENA
);
}
#endif
}
static
inline
void
i2c_ll_stretch_clr
(
i2c_dev_t
*
hw
)
{
#ifndef CONFIG_IDF_TARGET_ESP32
hw
->
scl_stretch_conf
.
slave_scl_stretch_clr
=
1
;
#endif
}
static
inline
bool
i2c_ll_slave_addressed
(
i2c_dev_t
*
hw
)
{
#if CONFIG_IDF_TARGET_ESP32C3
return
hw
->
sr
.
slave_addressed
;
#else
return
hw
->
status_reg
.
slave_addressed
;
#endif
}
static
inline
bool
i2c_ll_slave_rw
(
i2c_dev_t
*
hw
)
//not exposed by hal_ll
{
#if CONFIG_IDF_TARGET_ESP32C3
return
hw
->
sr
.
slave_rw
;
#else
return
hw
->
status_reg
.
slave_rw
;
#endif
}
//-------------------------------------- PRIVATE (Function Prototypes) ------------------------------------------------
static
void
i2c_slave_free_resources
(
i2c_slave_struct_t
*
i2c
);
static
void
i2c_slave_delay_us
(
uint64_t
us
);
static
void
i2c_slave_gpio_mode
(
int8_t
pin
,
gpio_mode_t
mode
);
static
bool
i2c_slave_check_line_state
(
int8_t
sda
,
int8_t
scl
);
static
bool
i2c_slave_attach_gpio
(
i2c_slave_struct_t
*
i2c
,
int8_t
sda
,
int8_t
scl
);
static
bool
i2c_slave_detach_gpio
(
i2c_slave_struct_t
*
i2c
);
static
bool
i2c_slave_set_frequency
(
i2c_slave_struct_t
*
i2c
,
uint32_t
clk_speed
);
static
bool
i2c_slave_send_event
(
i2c_slave_struct_t
*
i2c
,
i2c_slave_queue_event_t
*
event
);
static
bool
i2c_slave_handle_tx_fifo_empty
(
i2c_slave_struct_t
*
i2c
);
static
bool
i2c_slave_handle_rx_fifo_full
(
i2c_slave_struct_t
*
i2c
,
uint32_t
len
);
static
size_t
i2c_slave_read_rx
(
i2c_slave_struct_t
*
i2c
,
uint8_t
*
data
,
size_t
len
);
static
void
i2c_slave_isr_handler
(
void
*
arg
);
static
void
i2c_slave_task
(
void
*
pv_args
);
//=====================================================================================================================
//-------------------------------------- Public Functions -------------------------------------------------------------
//=====================================================================================================================
esp_err_t
i2cSlaveAttachCallbacks
(
uint8_t
num
,
i2c_slave_request_cb_t
request_callback
,
i2c_slave_receive_cb_t
receive_callback
,
void
*
arg
){
if
(
num
>=
SOC_I2C_NUM
){
log_e
(
"Invalid port num: %u"
,
num
);
return
ESP_ERR_INVALID_ARG
;
}
i2c_slave_struct_t
*
i2c
=
&
_i2c_bus_array
[
num
];
I2C_SLAVE_MUTEX_LOCK
();
i2c
->
request_callback
=
request_callback
;
i2c
->
receive_callback
=
receive_callback
;
i2c
->
arg
=
arg
;
I2C_SLAVE_MUTEX_UNLOCK
();
return
ESP_OK
;
}
esp_err_t
i2cSlaveInit
(
uint8_t
num
,
int
sda
,
int
scl
,
uint16_t
slaveID
,
uint32_t
frequency
,
size_t
rx_len
,
size_t
tx_len
)
{
if
(
num
>=
SOC_I2C_NUM
){
log_e
(
"Invalid port num: %u"
,
num
);
return
ESP_ERR_INVALID_ARG
;
}
if
(
sda
<
0
||
scl
<
0
)
{
log_e
(
"invalid pins sda=%d, scl=%d"
,
sda
,
scl
);
return
ESP_ERR_INVALID_ARG
;
}
if
(
!
frequency
){
frequency
=
100000
;
}
else
if
(
frequency
>
1000000
){
frequency
=
1000000
;
}
log_i
(
"Initialising I2C Slave: sda=%d scl=%d freq=%d, addr=0x%x"
,
sda
,
scl
,
frequency
,
slaveID
);
i2c_slave_struct_t
*
i2c
=
&
_i2c_bus_array
[
num
];
esp_err_t
ret
=
ESP_OK
;
#if !CONFIG_DISABLE_HAL_LOCKS
if
(
!
i2c
->
lock
){
i2c
->
lock
=
xSemaphoreCreateMutex
();
if
(
i2c
->
lock
==
NULL
)
{
log_e
(
"RX queue create failed"
);
return
ESP_ERR_NO_MEM
;
}
}
#endif
I2C_SLAVE_MUTEX_LOCK
();
i2c_slave_free_resources
(
i2c
);
#if I2C_SLAVE_USE_RX_QUEUE
i2c
->
rx_queue
=
xQueueCreate
(
rx_len
,
sizeof
(
uint8_t
));
if
(
i2c
->
rx_queue
==
NULL
)
{
log_e
(
"RX queue create failed"
);
ret
=
ESP_ERR_NO_MEM
;
goto
fail
;
}
#else
i2c
->
rx_ring_buf
=
xRingbufferCreate
(
rx_len
,
RINGBUF_TYPE_BYTEBUF
);
if
(
i2c
->
rx_ring_buf
==
NULL
)
{
log_e
(
"RX RingBuf create failed"
);
ret
=
ESP_ERR_NO_MEM
;
goto
fail
;
}
#endif
i2c
->
tx_queue
=
xQueueCreate
(
tx_len
,
sizeof
(
uint8_t
));
if
(
i2c
->
tx_queue
==
NULL
)
{
log_e
(
"TX queue create failed"
);
ret
=
ESP_ERR_NO_MEM
;
goto
fail
;
}
i2c
->
event_queue
=
xQueueCreate
(
16
,
sizeof
(
i2c_slave_queue_event_t
));
if
(
i2c
->
event_queue
==
NULL
)
{
log_e
(
"Event queue create failed"
);
ret
=
ESP_ERR_NO_MEM
;
goto
fail
;
}
xTaskCreate
(
i2c_slave_task
,
"i2c_slave_task"
,
4096
,
i2c
,
20
,
&
i2c
->
task_handle
);
if
(
i2c
->
task_handle
==
NULL
){
log_e
(
"Event thread create failed"
);
ret
=
ESP_ERR_NO_MEM
;
goto
fail
;
}
if
(
frequency
==
0
)
{
frequency
=
100000L
;
}
frequency
=
(
frequency
*
5
)
/
4
;
if
(
i2c
->
num
==
0
)
{
periph_module_enable
(
PERIPH_I2C0_MODULE
);
#if SOC_I2C_NUM > 1
}
else
{
periph_module_enable
(
PERIPH_I2C1_MODULE
);
#endif
}
i2c_ll_slave_init
(
i2c
->
dev
);
i2c_ll_set_fifo_mode
(
i2c
->
dev
,
true
);
i2c_ll_set_slave_addr
(
i2c
->
dev
,
slaveID
,
false
);
i2c_ll_set_tout
(
i2c
->
dev
,
32000
);
i2c_slave_set_frequency
(
i2c
,
frequency
);
if
(
!
i2c_slave_check_line_state
(
sda
,
scl
))
{
log_e
(
"bad pin state"
);
ret
=
ESP_FAIL
;
goto
fail
;
}
i2c_slave_attach_gpio
(
i2c
,
sda
,
scl
);
if
(
i2c_ll_is_bus_busy
(
i2c
->
dev
))
{
log_w
(
"Bus busy, reinit"
);
ret
=
ESP_FAIL
;
goto
fail
;
}
i2c_ll_disable_intr_mask
(
i2c
->
dev
,
I2C_LL_INTR_MASK
);
i2c_ll_clr_intsts_mask
(
i2c
->
dev
,
I2C_LL_INTR_MASK
);
i2c_ll_set_fifo_mode
(
i2c
->
dev
,
true
);
if
(
!
i2c
->
intr_handle
)
{
uint32_t
flags
=
ESP_INTR_FLAG_LOWMED
|
ESP_INTR_FLAG_SHARED
;
if
(
i2c
->
num
==
0
)
{
ret
=
esp_intr_alloc
(
ETS_I2C_EXT0_INTR_SOURCE
,
flags
,
&
i2c_slave_isr_handler
,
i2c
,
&
i2c
->
intr_handle
);
#if SOC_I2C_NUM > 1
}
else
{
ret
=
esp_intr_alloc
(
ETS_I2C_EXT1_INTR_SOURCE
,
flags
,
&
i2c_slave_isr_handler
,
i2c
,
&
i2c
->
intr_handle
);
#endif
}
if
(
ret
!=
ESP_OK
)
{
log_e
(
"install interrupt handler Failed=%d"
,
ret
);
goto
fail
;
}
}
i2c_ll_txfifo_rst
(
i2c
->
dev
);
i2c_ll_rxfifo_rst
(
i2c
->
dev
);
i2c_ll_slave_enable_rx_it
(
i2c
->
dev
);
i2c_ll_set_stretch
(
i2c
->
dev
,
0x3FF
);
i2c_ll_update
(
i2c
->
dev
);
I2C_SLAVE_MUTEX_UNLOCK
();
return
ret
;
fail:
i2c_slave_free_resources
(
i2c
);
I2C_SLAVE_MUTEX_UNLOCK
();
return
ret
;
}
esp_err_t
i2cSlaveDeinit
(
uint8_t
num
){
if
(
num
>=
SOC_I2C_NUM
){
log_e
(
"Invalid port num: %u"
,
num
);
return
ESP_ERR_INVALID_ARG
;
}
i2c_slave_struct_t
*
i2c
=
&
_i2c_bus_array
[
num
];
if
(
!
i2c
->
lock
){
log_e
(
"Lock is not initialized! Did you call i2c_slave_init()?"
);
return
ESP_ERR_NO_MEM
;
}
I2C_SLAVE_MUTEX_LOCK
();
i2c_slave_free_resources
(
i2c
);
I2C_SLAVE_MUTEX_UNLOCK
();
return
ESP_OK
;
}
size_t
i2cSlaveWrite
(
uint8_t
num
,
const
uint8_t
*
buf
,
uint32_t
len
,
uint32_t
timeout_ms
)
{
if
(
num
>=
SOC_I2C_NUM
){
log_e
(
"Invalid port num: %u"
,
num
);
return
0
;
}
size_t
to_queue
=
0
,
to_fifo
=
0
;
i2c_slave_struct_t
*
i2c
=
&
_i2c_bus_array
[
num
];
if
(
!
i2c
->
lock
){
log_e
(
"Lock is not initialized! Did you call i2c_slave_init()?"
);
return
ESP_ERR_NO_MEM
;
}
if
(
!
i2c
->
tx_queue
){
return
0
;
}
I2C_SLAVE_MUTEX_LOCK
();
#if CONFIG_IDF_TARGET_ESP32
//make sure that tx is idle
uint64_t
tout_at
=
esp_timer_get_time
()
+
(
timeout_ms
*
1000
);
while
(
i2c_ll_slave_addressed
(
i2c
->
dev
)
&&
i2c_ll_slave_rw
(
i2c
->
dev
))
{
// ongoing MASTER READ
//wait up to timeout_ms for current transaction to finish
vTaskDelay
(
2
);
if
((
uint64_t
)
esp_timer_get_time
()
>=
tout_at
){
log_e
(
"TX IDLE WAIT TIMEOUT!"
);
I2C_SLAVE_MUTEX_UNLOCK
();
return
0
;
}
}
i2c_ll_slave_disable_tx_it
(
i2c
->
dev
);
if
(
i2c_ll_get_txfifo_len
(
i2c
->
dev
)
<
SOC_I2C_FIFO_LEN
)
{
i2c_ll_txfifo_rst
(
i2c
->
dev
);
}
#endif
to_fifo
=
i2c_ll_get_txfifo_len
(
i2c
->
dev
);
if
(
len
<
to_fifo
){
to_fifo
=
len
;
}
i2c_ll_write_txfifo
(
i2c
->
dev
,
(
uint8_t
*
)
buf
,
to_fifo
);
buf
+=
to_fifo
;
len
-=
to_fifo
;
//reset tx_queue
xQueueReset
(
i2c
->
tx_queue
);
//write the rest of the bytes to the queue
if
(
len
){
to_queue
=
uxQueueSpacesAvailable
(
i2c
->
tx_queue
);
if
(
len
<
to_queue
){
to_queue
=
len
;
}
for
(
size_t
i
=
0
;
i
<
to_queue
;
i
++
)
{
if
(
xQueueSend
(
i2c
->
tx_queue
,
&
buf
[
i
],
timeout_ms
/
portTICK_RATE_MS
)
!=
pdTRUE
)
{
xQueueReset
(
i2c
->
tx_queue
);
to_queue
=
0
;
break
;
}
}
//no need to enable TX_EMPTY if tx_queue is empty
if
(
to_queue
){
i2c_ll_slave_enable_tx_it
(
i2c
->
dev
);
}
}
I2C_SLAVE_MUTEX_UNLOCK
();
return
to_queue
+
to_fifo
;
}
//=====================================================================================================================
//-------------------------------------- Private Functions ------------------------------------------------------------
//=====================================================================================================================
static
void
i2c_slave_free_resources
(
i2c_slave_struct_t
*
i2c
){
i2c_slave_detach_gpio
(
i2c
);
i2c_ll_set_slave_addr
(
i2c
->
dev
,
0
,
false
);
i2c_ll_disable_intr_mask
(
i2c
->
dev
,
I2C_LL_INTR_MASK
);
i2c_ll_clr_intsts_mask
(
i2c
->
dev
,
I2C_LL_INTR_MASK
);
if
(
i2c
->
intr_handle
)
{
esp_intr_free
(
i2c
->
intr_handle
);
i2c
->
intr_handle
=
NULL
;
}
if
(
i2c
->
task_handle
){
vTaskDelete
(
i2c
->
task_handle
);
i2c
->
task_handle
=
NULL
;
}
#if I2C_SLAVE_USE_RX_QUEUE
if
(
i2c
->
rx_queue
)
{
vQueueDelete
(
i2c
->
rx_queue
);
i2c
->
rx_queue
=
NULL
;
}
#else
if
(
i2c
->
rx_ring_buf
)
{
vRingbufferDelete
(
i2c
->
rx_ring_buf
);
i2c
->
rx_ring_buf
=
NULL
;
}
#endif
if
(
i2c
->
tx_queue
)
{
vQueueDelete
(
i2c
->
tx_queue
);
i2c
->
tx_queue
=
NULL
;
}
if
(
i2c
->
event_queue
)
{
vQueueDelete
(
i2c
->
event_queue
);
i2c
->
event_queue
=
NULL
;
}
i2c
->
rx_data_count
=
0
;
}
static
bool
i2c_slave_set_frequency
(
i2c_slave_struct_t
*
i2c
,
uint32_t
clk_speed
)
{
if
(
i2c
==
NULL
)
{
log_e
(
"no control buffer"
);
return
false
;
}
if
(
clk_speed
>
1100000UL
){
clk_speed
=
1100000UL
;
}
// Adjust Fifo thresholds based on frequency
uint32_t
a
=
(
clk_speed
/
50000L
)
+
2
;
log_d
(
"Fifo thresholds: rx_fifo_full = %d, tx_fifo_empty = %d"
,
SOC_I2C_FIFO_LEN
-
a
,
a
);
i2c_clk_cal_t
clk_cal
;
#if SOC_I2C_SUPPORT_APB
i2c_ll_cal_bus_clk
(
APB_CLK_FREQ
,
clk_speed
,
&
clk_cal
);
i2c_ll_set_source_clk
(
i2c
->
dev
,
I2C_SCLK_APB
);
/*!< I2C source clock from APB, 80M*/
#elif SOC_I2C_SUPPORT_XTAL
i2c_ll_cal_bus_clk
(
XTAL_CLK_FREQ
,
clk_speed
,
&
clk_cal
);
i2c_ll_set_source_clk
(
i2c
->
dev
,
I2C_SCLK_XTAL
);
/*!< I2C source clock from XTAL, 40M */
#endif
i2c_ll_set_txfifo_empty_thr
(
i2c
->
dev
,
a
);
i2c_ll_set_rxfifo_full_thr
(
i2c
->
dev
,
SOC_I2C_FIFO_LEN
-
a
);
i2c_ll_set_bus_timing
(
i2c
->
dev
,
&
clk_cal
);
i2c_ll_set_filter
(
i2c
->
dev
,
3
);
return
true
;
}
static
void
i2c_slave_delay_us
(
uint64_t
us
)
{
uint64_t
m
=
esp_timer_get_time
();
if
(
us
)
{
uint64_t
e
=
(
m
+
us
);
if
(
m
>
e
)
{
//overflow
while
((
uint64_t
)
esp_timer_get_time
()
>
e
);
}
while
((
uint64_t
)
esp_timer_get_time
()
<
e
);
}
}
static
void
i2c_slave_gpio_mode
(
int8_t
pin
,
gpio_mode_t
mode
)
{
gpio_config_t
conf
=
{
.
pin_bit_mask
=
1LL
<<
pin
,
.
mode
=
mode
,
.
pull_up_en
=
GPIO_PULLUP_ENABLE
,
.
pull_down_en
=
GPIO_PULLDOWN_DISABLE
,
.
intr_type
=
GPIO_INTR_DISABLE
};
gpio_config
(
&
conf
);
}
static
bool
i2c_slave_check_line_state
(
int8_t
sda
,
int8_t
scl
)
{
if
(
sda
<
0
||
scl
<
0
)
{
return
false
;
//return false since there is nothing to do
}
// if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles
gpio_set_level
(
sda
,
1
);
gpio_set_level
(
scl
,
1
);
i2c_slave_gpio_mode
(
sda
,
GPIO_MODE_INPUT
|
GPIO_MODE_DEF_OD
);
i2c_slave_gpio_mode
(
scl
,
GPIO_MODE_INPUT
|
GPIO_MODE_DEF_OD
);
gpio_set_level
(
scl
,
1
);
if
(
!
gpio_get_level
(
sda
)
||
!
gpio_get_level
(
scl
))
{
// bus in busy state
log_w
(
"invalid state sda(%d)=%d, scl(%d)=%d"
,
sda
,
gpio_get_level
(
sda
),
scl
,
gpio_get_level
(
scl
));
for
(
uint8_t
a
=
0
;
a
<
9
;
a
++
)
{
i2c_slave_delay_us
(
5
);
if
(
gpio_get_level
(
sda
)
&&
gpio_get_level
(
scl
))
{
// bus recovered
log_w
(
"Recovered after %d Cycles"
,
a
);
gpio_set_level
(
sda
,
0
);
// start
i2c_slave_delay_us
(
5
);
for
(
uint8_t
a
=
0
;
a
<
9
;
a
++
)
{
gpio_set_level
(
scl
,
1
);
i2c_slave_delay_us
(
5
);
gpio_set_level
(
scl
,
0
);
i2c_slave_delay_us
(
5
);
}
gpio_set_level
(
scl
,
1
);
i2c_slave_delay_us
(
5
);
gpio_set_level
(
sda
,
1
);
// stop
break
;
}
gpio_set_level
(
scl
,
0
);
i2c_slave_delay_us
(
5
);
gpio_set_level
(
scl
,
1
);
}
}
if
(
!
gpio_get_level
(
sda
)
||
!
gpio_get_level
(
scl
))
{
// bus in busy state
log_e
(
"Bus Invalid State, Can't init sda=%d, scl=%d"
,
gpio_get_level
(
sda
),
gpio_get_level
(
scl
));
return
false
;
// bus is busy
}
return
true
;
}
static
bool
i2c_slave_attach_gpio
(
i2c_slave_struct_t
*
i2c
,
int8_t
sda
,
int8_t
scl
)
{
if
(
i2c
==
NULL
)
{
log_e
(
"no control block"
);
return
false
;
}
if
((
sda
<
0
)
||
(
scl
<
0
))
{
log_e
(
"bad pins sda=%d, scl=%d"
,
sda
,
scl
);
return
false
;
}
i2c
->
scl
=
scl
;
gpio_set_level
(
scl
,
1
);
i2c_slave_gpio_mode
(
scl
,
GPIO_MODE_INPUT_OUTPUT_OD
);
gpio_matrix_out
(
scl
,
I2C_SCL_IDX
(
i2c
->
num
),
false
,
false
);
gpio_matrix_in
(
scl
,
I2C_SCL_IDX
(
i2c
->
num
),
false
);
i2c
->
sda
=
sda
;
gpio_set_level
(
sda
,
1
);
i2c_slave_gpio_mode
(
sda
,
GPIO_MODE_INPUT_OUTPUT_OD
);
gpio_matrix_out
(
sda
,
I2C_SDA_IDX
(
i2c
->
num
),
false
,
false
);
gpio_matrix_in
(
sda
,
I2C_SDA_IDX
(
i2c
->
num
),
false
);
return
true
;
}
static
bool
i2c_slave_detach_gpio
(
i2c_slave_struct_t
*
i2c
)
{
if
(
i2c
==
NULL
)
{
log_e
(
"no control Block"
);
return
false
;
}
if
(
i2c
->
scl
>=
0
)
{
gpio_matrix_out
(
i2c
->
scl
,
0x100
,
false
,
false
);
gpio_matrix_in
(
0x30
,
I2C_SCL_IDX
(
i2c
->
num
),
false
);
i2c_slave_gpio_mode
(
i2c
->
scl
,
GPIO_MODE_INPUT
);
i2c
->
scl
=
-
1
;
// un attached
}
if
(
i2c
->
sda
>=
0
)
{
gpio_matrix_out
(
i2c
->
sda
,
0x100
,
false
,
false
);
gpio_matrix_in
(
0x30
,
I2C_SDA_IDX
(
i2c
->
num
),
false
);
i2c_slave_gpio_mode
(
i2c
->
sda
,
GPIO_MODE_INPUT
);
i2c
->
sda
=
-
1
;
// un attached
}
return
true
;
}
static
bool
i2c_slave_send_event
(
i2c_slave_struct_t
*
i2c
,
i2c_slave_queue_event_t
*
event
)
{
bool
pxHigherPriorityTaskWoken
=
false
;
if
(
i2c
->
event_queue
)
{
if
(
xQueueSendFromISR
(
i2c
->
event_queue
,
event
,
(
BaseType_t
*
const
)
&
pxHigherPriorityTaskWoken
)
!=
pdTRUE
){
//log_e("event_queue_full");
}
}
return
pxHigherPriorityTaskWoken
;
}
static
bool
i2c_slave_handle_tx_fifo_empty
(
i2c_slave_struct_t
*
i2c
)
{
bool
pxHigherPriorityTaskWoken
=
false
;
uint32_t
d
=
0
,
moveCnt
=
i2c_ll_get_txfifo_len
(
i2c
->
dev
);
while
(
moveCnt
>
0
)
{
// read tx queue until Fifo is full or queue is empty
if
(
xQueueReceiveFromISR
(
i2c
->
tx_queue
,
&
d
,
(
BaseType_t
*
const
)
&
pxHigherPriorityTaskWoken
)
==
pdTRUE
){
i2c_ll_write_txfifo
(
i2c
->
dev
,
(
uint8_t
*
)
&
d
,
1
);
moveCnt
--
;
}
else
{
i2c_ll_slave_disable_tx_it
(
i2c
->
dev
);
break
;
}
}
return
pxHigherPriorityTaskWoken
;
}
static
bool
i2c_slave_handle_rx_fifo_full
(
i2c_slave_struct_t
*
i2c
,
uint32_t
len
)
{
#if I2C_SLAVE_USE_RX_QUEUE
uint32_t
d
=
0
;
#else
uint8_t
data
[
SOC_I2C_FIFO_LEN
];
#endif
bool
pxHigherPriorityTaskWoken
=
false
;
#if I2C_SLAVE_USE_RX_QUEUE
while
(
len
>
0
)
{
i2c_ll_read_rxfifo
(
i2c
->
dev
,
(
uint8_t
*
)
&
d
,
1
);
if
(
xQueueSendFromISR
(
i2c
->
rx_queue
,
&
d
,
(
BaseType_t
*
const
)
&
pxHigherPriorityTaskWoken
)
!=
pdTRUE
){
log_e
(
"rx_queue_full"
);
}
else
{
i2c
->
rx_data_count
++
;
}
if
(
--
len
==
0
)
{
len
=
i2c_ll_get_rxfifo_cnt
(
i2c
->
dev
);
}
#else
if
(
len
){
i2c_ll_read_rxfifo
(
i2c
->
dev
,
data
,
len
);
if
(
xRingbufferSendFromISR
(
i2c
->
rx_ring_buf
,
(
void
*
)
data
,
len
,
(
BaseType_t
*
const
)
&
pxHigherPriorityTaskWoken
)
!=
pdTRUE
){
log_e
(
"rx_ring_buf_full"
);
}
else
{
i2c
->
rx_data_count
+=
len
;
}
#endif
}
return
pxHigherPriorityTaskWoken
;
}
static
void
i2c_slave_isr_handler
(
void
*
arg
)
{
bool
pxHigherPriorityTaskWoken
=
false
;
i2c_slave_struct_t
*
i2c
=
(
i2c_slave_struct_t
*
)
arg
;
// recover data
uint32_t
activeInt
=
i2c_ll_get_intsts_mask
(
i2c
->
dev
);
i2c_ll_clr_intsts_mask
(
i2c
->
dev
,
activeInt
);
uint8_t
rx_fifo_len
=
i2c_ll_get_rxfifo_cnt
(
i2c
->
dev
);
uint8_t
tx_fifo_len
=
SOC_I2C_FIFO_LEN
-
i2c_ll_get_txfifo_len
(
i2c
->
dev
);
bool
slave_rw
=
i2c_ll_slave_rw
(
i2c
->
dev
);
if
(
activeInt
&
I2C_RXFIFO_WM_INT_ENA
){
// RX FiFo Full
pxHigherPriorityTaskWoken
|=
i2c_slave_handle_rx_fifo_full
(
i2c
,
rx_fifo_len
);
i2c_ll_slave_enable_rx_it
(
i2c
->
dev
);
//is this necessary?
}
if
(
activeInt
&
I2C_TRANS_COMPLETE_INT_ENA
){
// STOP
if
(
rx_fifo_len
){
//READ RX FIFO
pxHigherPriorityTaskWoken
|=
i2c_slave_handle_rx_fifo_full
(
i2c
,
rx_fifo_len
);
}
if
(
i2c
->
rx_data_count
){
//WRITE or RepeatedStart
//SEND RX Event
i2c_slave_queue_event_t
event
;
event
.
event
=
I2C_SLAVE_EVT_RX
;
event
.
stop
=
!
slave_rw
;
event
.
param
=
i2c
->
rx_data_count
;
pxHigherPriorityTaskWoken
|=
i2c_slave_send_event
(
i2c
,
&
event
);
//Zero RX count
i2c
->
rx_data_count
=
0
;
}
if
(
slave_rw
){
// READ
#if CONFIG_IDF_TARGET_ESP32
//SEND TX Event
i2c_slave_queue_event_t
event
;
event
.
event
=
I2C_SLAVE_EVT_TX
;
pxHigherPriorityTaskWoken
|=
i2c_slave_send_event
(
i2c
,
&
event
);
#else
//reset TX data
i2c_ll_txfifo_rst
(
i2c
->
dev
);
uint8_t
d
;
while
(
xQueueReceiveFromISR
(
i2c
->
tx_queue
,
&
d
,
(
BaseType_t
*
const
)
&
pxHigherPriorityTaskWoken
)
==
pdTRUE
)
;
//flush partial write
#endif
}
}
#ifndef CONFIG_IDF_TARGET_ESP32
if
(
activeInt
&
I2C_SLAVE_STRETCH_INT_ENA
){
// STRETCH
i2c_stretch_cause_t
cause
=
i2c_ll_stretch_cause
(
i2c
->
dev
);
if
(
cause
==
I2C_STRETCH_CAUSE_MASTER_READ
){
//on C3 RX data dissapears with repeated start, so we need to get it here
if
(
rx_fifo_len
){
pxHigherPriorityTaskWoken
|=
i2c_slave_handle_rx_fifo_full
(
i2c
,
rx_fifo_len
);
}
//SEND TX Event
i2c_slave_queue_event_t
event
;
event
.
event
=
I2C_SLAVE_EVT_TX
;
pxHigherPriorityTaskWoken
|=
i2c_slave_send_event
(
i2c
,
&
event
);
//will clear after execution
}
else
if
(
cause
==
I2C_STRETCH_CAUSE_TX_FIFO_EMPTY
){
pxHigherPriorityTaskWoken
|=
i2c_slave_handle_tx_fifo_empty
(
i2c
);
i2c_ll_stretch_clr
(
i2c
->
dev
);
}
else
if
(
cause
==
I2C_STRETCH_CAUSE_RX_FIFO_FULL
){
pxHigherPriorityTaskWoken
|=
i2c_slave_handle_rx_fifo_full
(
i2c
,
rx_fifo_len
);
i2c_ll_stretch_clr
(
i2c
->
dev
);
}
}
#endif
if
(
activeInt
&
I2C_TXFIFO_WM_INT_ENA
){
// TX FiFo Empty
pxHigherPriorityTaskWoken
|=
i2c_slave_handle_tx_fifo_empty
(
i2c
);
}
if
(
pxHigherPriorityTaskWoken
){
portYIELD_FROM_ISR
();
}
}
static
size_t
i2c_slave_read_rx
(
i2c_slave_struct_t
*
i2c
,
uint8_t
*
data
,
size_t
len
){
if
(
!
len
){
return
0
;
}
#if I2C_SLAVE_USE_RX_QUEUE
uint8_t
d
=
0
;
BaseType_t
res
=
pdTRUE
;
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
if
(
data
){
res
=
xQueueReceive
(
i2c
->
rx_queue
,
&
data
[
i
],
0
);
}
else
{
res
=
xQueueReceive
(
i2c
->
rx_queue
,
&
d
,
0
);
}
if
(
res
!=
pdTRUE
)
{
log_e
(
"Read Queue(%u) Failed"
,
i
);
len
=
i
;
break
;
}
}
return
(
data
)
?
len
:
0
;
#else
size_t
dlen
=
0
,
to_read
=
len
,
so_far
=
0
,
available
=
0
;
uint8_t
*
rx_data
=
NULL
;
vRingbufferGetInfo
(
i2c
->
rx_ring_buf
,
NULL
,
NULL
,
NULL
,
NULL
,
&
available
);
if
(
available
<
to_read
){
log_e
(
"Less available than requested. %u < %u"
,
available
,
len
);
to_read
=
available
;
}
while
(
to_read
){
dlen
=
0
;
rx_data
=
(
uint8_t
*
)
xRingbufferReceiveUpTo
(
i2c
->
rx_ring_buf
,
&
dlen
,
0
,
to_read
);
if
(
!
rx_data
){
log_e
(
"Receive %u Failed"
,
to_read
);
return
so_far
;
}
if
(
data
){
memcpy
(
data
+
so_far
,
rx_data
,
dlen
);
}
vRingbufferReturnItem
(
i2c
->
rx_ring_buf
,
rx_data
);
so_far
+=
dlen
;
to_read
-=
dlen
;
}
return
(
data
)
?
so_far
:
0
;
#endif
}
static
void
i2c_slave_task
(
void
*
pv_args
)
{
i2c_slave_struct_t
*
i2c
=
(
i2c_slave_struct_t
*
)
pv_args
;
i2c_slave_queue_event_t
event
;
size_t
len
=
0
;
bool
stop
=
false
;
uint8_t
*
data
=
NULL
;
for
(;;){
if
(
xQueueReceive
(
i2c
->
event_queue
,
&
event
,
portMAX_DELAY
)
==
pdTRUE
){
// Write
if
(
event
.
event
==
I2C_SLAVE_EVT_RX
){
len
=
event
.
param
;
stop
=
event
.
stop
;
data
=
(
len
>
0
)
?
(
uint8_t
*
)
malloc
(
len
)
:
NULL
;
if
(
len
&&
data
==
NULL
){
log_e
(
"Malloc (%u) Failed"
,
len
);
}
len
=
i2c_slave_read_rx
(
i2c
,
data
,
len
);
if
(
i2c
->
receive_callback
){
i2c
->
receive_callback
(
i2c
->
num
,
data
,
len
,
stop
,
i2c
->
arg
);
}
free
(
data
);
// Read
}
else
if
(
event
.
event
==
I2C_SLAVE_EVT_TX
){
if
(
i2c
->
request_callback
){
i2c
->
request_callback
(
i2c
->
num
,
i2c
->
arg
);
}
i2c_ll_stretch_clr
(
i2c
->
dev
);
}
}
}
vTaskDelete
(
NULL
);
}
cores/esp32/esp32-hal-i2c-slave.h
0 → 100755
View file @
ed53b6c8
// Copyright 2015-2021 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.
#pragma once
#ifdef __cplusplus
extern
"C"
{
#endif
#include "stdint.h"
#include "stddef.h"
#include "esp_err.h"
typedef
void
(
*
i2c_slave_request_cb_t
)
(
uint8_t
num
,
void
*
arg
);
typedef
void
(
*
i2c_slave_receive_cb_t
)
(
uint8_t
num
,
uint8_t
*
data
,
size_t
len
,
bool
stop
,
void
*
arg
);
esp_err_t
i2cSlaveAttachCallbacks
(
uint8_t
num
,
i2c_slave_request_cb_t
request_callback
,
i2c_slave_receive_cb_t
receive_callback
,
void
*
arg
);
esp_err_t
i2cSlaveInit
(
uint8_t
num
,
int
sda
,
int
scl
,
uint16_t
slaveID
,
uint32_t
frequency
,
size_t
rx_len
,
size_t
tx_len
);
esp_err_t
i2cSlaveDeinit
(
uint8_t
num
);
size_t
i2cSlaveWrite
(
uint8_t
num
,
const
uint8_t
*
buf
,
uint32_t
len
,
uint32_t
timeout_ms
);
#ifdef __cplusplus
}
#endif
libraries/Wire/examples/WireMaster/WireMaster.ino
0 → 100644
View file @
ed53b6c8
#include "Wire.h"
#define I2C_DEV_ADDR 0x55
uint32_t
i
=
0
;
void
setup
()
{
Serial
.
begin
(
115200
);
Serial
.
setDebugOutput
(
true
);
Wire
.
begin
();
}
void
loop
()
{
delay
(
5000
);
//Write message to the slave
Wire
.
beginTransmission
(
I2C_DEV_ADDR
);
Wire
.
printf
(
"Hello World! %u"
,
i
++
);
uint8_t
error
=
Wire
.
endTransmission
(
true
);
Serial
.
printf
(
"endTransmission: %u
\n
"
,
error
);
//Read 16 bytes from the slave
error
=
Wire
.
requestFrom
(
I2C_DEV_ADDR
,
16
);
Serial
.
printf
(
"requestFrom: %u
\n
"
,
error
);
if
(
error
){
uint8_t
temp
[
error
];
Wire
.
readBytes
(
temp
,
error
);
log_print_buf
(
temp
,
error
);
}
}
libraries/Wire/examples/WireScan/WireScan.ino
0 → 100644
View file @
ed53b6c8
#include "Wire.h"
void
setup
()
{
Serial
.
begin
(
115200
);
Wire
.
begin
();
}
void
loop
()
{
byte
error
,
address
;
int
nDevices
=
0
;
delay
(
5000
);
Serial
.
println
(
"Scanning for I2C devices ..."
);
for
(
address
=
0x01
;
address
<
0x7f
;
address
++
){
Wire
.
beginTransmission
(
address
);
error
=
Wire
.
endTransmission
();
if
(
error
==
0
){
Serial
.
printf
(
"I2C device found at address 0x%02X
\n
"
,
address
);
nDevices
++
;
}
else
if
(
error
!=
2
){
Serial
.
printf
(
"Error %d at address 0x%02X
\n
"
,
error
,
address
);
}
}
if
(
nDevices
==
0
){
Serial
.
println
(
"No I2C devices found"
);
}
}
libraries/Wire/examples/WireSlave/WireSlave.ino
0 → 100644
View file @
ed53b6c8
#include "Wire.h"
#define I2C_DEV_ADDR 0x55
uint32_t
i
=
0
;
void
onRequest
(){
Wire
.
print
(
i
++
);
Wire
.
print
(
" Packets."
);
Serial
.
println
(
"onRequest"
);
}
void
onReceive
(
int
len
){
Serial
.
printf
(
"onReceive[%d]: "
,
len
);
while
(
Wire
.
available
()){
Serial
.
write
(
Wire
.
read
());
}
Serial
.
println
();
}
void
setup
()
{
Serial
.
begin
(
115200
);
Serial
.
setDebugOutput
(
true
);
Wire
.
onReceive
(
onReceive
);
Wire
.
onRequest
(
onRequest
);
Wire
.
begin
((
uint8_t
)
I2C_DEV_ADDR
);
#if CONFIG_IDF_TARGET_ESP32
char
message
[
64
];
snprintf
(
message
,
64
,
"%u Packets."
,
i
++
);
Wire
.
slaveWrite
((
uint8_t
*
)
message
,
strlen
(
message
));
#endif
}
void
loop
()
{
}
libraries/Wire/src/Wire.cpp
View file @
ed53b6c8
...
@@ -30,6 +30,7 @@ extern "C" {
...
@@ -30,6 +30,7 @@ extern "C" {
}
}
#include "esp32-hal-i2c.h"
#include "esp32-hal-i2c.h"
#include "esp32-hal-i2c-slave.h"
#include "Wire.h"
#include "Wire.h"
#include "Arduino.h"
#include "Arduino.h"
...
@@ -47,6 +48,9 @@ TwoWire::TwoWire(uint8_t bus_num)
...
@@ -47,6 +48,9 @@ TwoWire::TwoWire(uint8_t bus_num)
,
nonStopTask
(
NULL
)
,
nonStopTask
(
NULL
)
,
lock
(
NULL
)
,
lock
(
NULL
)
#endif
#endif
,
is_slave
(
false
)
,
user_onRequest
(
NULL
)
,
user_onReceive
(
NULL
)
{}
{}
TwoWire
::~
TwoWire
()
TwoWire
::~
TwoWire
()
...
@@ -59,6 +63,47 @@ TwoWire::~TwoWire()
...
@@ -59,6 +63,47 @@ TwoWire::~TwoWire()
#endif
#endif
}
}
bool
TwoWire
::
initPins
(
int
sdaPin
,
int
sclPin
)
{
if
(
sdaPin
<
0
)
{
// default param passed
if
(
num
==
0
)
{
if
(
sda
==-
1
)
{
sdaPin
=
SDA
;
//use Default Pin
}
else
{
sdaPin
=
sda
;
// reuse prior pin
}
}
else
{
if
(
sda
==-
1
)
{
log_e
(
"no Default SDA Pin for Second Peripheral"
);
return
false
;
//no Default pin for Second Peripheral
}
else
{
sdaPin
=
sda
;
// reuse prior pin
}
}
}
if
(
sclPin
<
0
)
{
// default param passed
if
(
num
==
0
)
{
if
(
scl
==
-
1
)
{
sclPin
=
SCL
;
// use Default pin
}
else
{
sclPin
=
scl
;
// reuse prior pin
}
}
else
{
if
(
scl
==
-
1
)
{
log_e
(
"no Default SCL Pin for Second Peripheral"
);
return
false
;
//no Default pin for Second Peripheral
}
else
{
sclPin
=
scl
;
// reuse prior pin
}
}
}
sda
=
sdaPin
;
scl
=
sclPin
;
return
true
;
}
bool
TwoWire
::
setPins
(
int
sdaPin
,
int
sclPin
)
bool
TwoWire
::
setPins
(
int
sdaPin
,
int
sclPin
)
{
{
#if !CONFIG_DISABLE_HAL_LOCKS
#if !CONFIG_DISABLE_HAL_LOCKS
...
@@ -76,8 +121,7 @@ bool TwoWire::setPins(int sdaPin, int sclPin)
...
@@ -76,8 +121,7 @@ bool TwoWire::setPins(int sdaPin, int sclPin)
}
}
#endif
#endif
if
(
!
i2cIsInit
(
num
)){
if
(
!
i2cIsInit
(
num
)){
sda
=
sdaPin
;
initPins
(
sdaPin
,
sclPin
);
scl
=
sclPin
;
}
else
{
}
else
{
log_e
(
"bus already initialized. change pins only when not."
);
log_e
(
"bus already initialized. change pins only when not."
);
}
}
...
@@ -88,10 +132,10 @@ bool TwoWire::setPins(int sdaPin, int sclPin)
...
@@ -88,10 +132,10 @@ bool TwoWire::setPins(int sdaPin, int sclPin)
return
!
i2cIsInit
(
num
);
return
!
i2cIsInit
(
num
);
}
}
bool
TwoWire
::
begin
(
int
sdaPin
,
int
sclPin
,
uint32_t
frequency
)
// Slave Begin
bool
TwoWire
::
begin
(
uint8_t
addr
,
int
sdaPin
,
int
sclPin
,
uint32_t
frequency
)
{
{
bool
started
=
false
;
bool
started
=
false
;
esp_err_t
err
=
ESP_OK
;
#if !CONFIG_DISABLE_HAL_LOCKS
#if !CONFIG_DISABLE_HAL_LOCKS
if
(
lock
==
NULL
){
if
(
lock
==
NULL
){
lock
=
xSemaphoreCreateMutex
();
lock
=
xSemaphoreCreateMutex
();
...
@@ -106,46 +150,64 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
...
@@ -106,46 +150,64 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
return
false
;
return
false
;
}
}
#endif
#endif
if
(
i2cIsInit
(
num
)){
if
(
is_slave
){
log_w
(
"Bus already started in Slave Mode."
);
started
=
true
;
started
=
true
;
goto
end
;
goto
end
;
}
}
if
(
sdaPin
<
0
)
{
// default param passed
if
(
i2cIsInit
(
num
)){
if
(
num
==
0
)
{
log_e
(
"Bus already started in Master Mode."
);
if
(
sda
==-
1
)
{
goto
end
;
sdaPin
=
SDA
;
//use Default Pin
}
else
{
sdaPin
=
sda
;
// reuse prior pin
}
}
else
{
if
(
sda
==-
1
)
{
log_e
(
"no Default SDA Pin for Second Peripheral"
);
goto
end
;
//no Default pin for Second Peripheral
}
else
{
sdaPin
=
sda
;
// reuse prior pin
}
}
if
(
!
initPins
(
sdaPin
,
sclPin
)){
goto
end
;
}
}
i2cSlaveAttachCallbacks
(
num
,
onRequestService
,
onReceiveService
,
this
);
if
(
i2cSlaveInit
(
num
,
sda
,
scl
,
addr
,
frequency
,
I2C_BUFFER_LENGTH
,
I2C_BUFFER_LENGTH
)
!=
ESP_OK
){
log_e
(
"Slave Init ERROR"
);
goto
end
;
}
}
is_slave
=
true
;
started
=
true
;
end:
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive
(
lock
);
#endif
return
started
;
}
if
(
sclPin
<
0
)
{
// default param passed
// Master Begin
if
(
num
==
0
)
{
bool
TwoWire
::
begin
(
int
sdaPin
,
int
sclPin
,
uint32_t
frequency
)
if
(
scl
==
-
1
)
{
{
sclPin
=
SCL
;
// use Default pin
bool
started
=
false
;
}
else
{
esp_err_t
err
=
ESP_OK
;
sclPin
=
scl
;
// reuse prior pin
#if !CONFIG_DISABLE_HAL_LOCKS
if
(
lock
==
NULL
){
lock
=
xSemaphoreCreateMutex
();
if
(
lock
==
NULL
){
log_e
(
"xSemaphoreCreateMutex failed"
);
return
false
;
}
}
}
else
{
if
(
scl
==
-
1
)
{
log_e
(
"no Default SCL Pin for Second Peripheral"
);
goto
end
;
//no Default pin for Second Peripheral
}
else
{
sclPin
=
scl
;
// reuse prior pin
}
}
//acquire lock
if
(
xSemaphoreTake
(
lock
,
portMAX_DELAY
)
!=
pdTRUE
){
log_e
(
"could not acquire lock"
);
return
false
;
}
}
#endif
if
(
is_slave
){
log_e
(
"Bus already started in Slave Mode."
);
goto
end
;
}
if
(
i2cIsInit
(
num
)){
log_w
(
"Bus already started in Master Mode."
);
started
=
true
;
goto
end
;
}
if
(
!
initPins
(
sdaPin
,
sclPin
)){
goto
end
;
}
}
sda
=
sdaPin
;
scl
=
sclPin
;
err
=
i2cInit
(
num
,
sda
,
scl
,
frequency
);
err
=
i2cInit
(
num
,
sda
,
scl
,
frequency
);
started
=
(
err
==
ESP_OK
);
started
=
(
err
==
ESP_OK
);
...
@@ -169,7 +231,12 @@ bool TwoWire::end()
...
@@ -169,7 +231,12 @@ bool TwoWire::end()
return
false
;
return
false
;
}
}
#endif
#endif
if
(
i2cIsInit
(
num
)){
if
(
is_slave
){
err
=
i2cSlaveDeinit
(
num
);
if
(
err
==
ESP_OK
){
is_slave
=
false
;
}
}
else
if
(
i2cIsInit
(
num
)){
err
=
i2cDeinit
(
num
);
err
=
i2cDeinit
(
num
);
}
}
#if !CONFIG_DISABLE_HAL_LOCKS
#if !CONFIG_DISABLE_HAL_LOCKS
...
@@ -189,7 +256,11 @@ uint32_t TwoWire::getClock()
...
@@ -189,7 +256,11 @@ uint32_t TwoWire::getClock()
log_e
(
"could not acquire lock"
);
log_e
(
"could not acquire lock"
);
}
else
{
}
else
{
#endif
#endif
if
(
is_slave
){
log_e
(
"Bus is in Slave Mode"
);
}
else
{
i2cGetClock
(
num
,
&
frequency
);
i2cGetClock
(
num
,
&
frequency
);
}
#if !CONFIG_DISABLE_HAL_LOCKS
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
//release lock
xSemaphoreGive
(
lock
);
xSemaphoreGive
(
lock
);
...
@@ -208,7 +279,12 @@ bool TwoWire::setClock(uint32_t frequency)
...
@@ -208,7 +279,12 @@ bool TwoWire::setClock(uint32_t frequency)
return
false
;
return
false
;
}
}
#endif
#endif
if
(
is_slave
){
log_e
(
"Bus is in Slave Mode"
);
err
=
ESP_FAIL
;
}
else
{
err
=
i2cSetClock
(
num
,
frequency
);
err
=
i2cSetClock
(
num
,
frequency
);
}
#if !CONFIG_DISABLE_HAL_LOCKS
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
//release lock
xSemaphoreGive
(
lock
);
xSemaphoreGive
(
lock
);
...
@@ -228,6 +304,10 @@ uint16_t TwoWire::getTimeOut()
...
@@ -228,6 +304,10 @@ uint16_t TwoWire::getTimeOut()
void
TwoWire
::
beginTransmission
(
uint16_t
address
)
void
TwoWire
::
beginTransmission
(
uint16_t
address
)
{
{
if
(
is_slave
){
log_e
(
"Bus is in Slave Mode"
);
return
;
}
#if !CONFIG_DISABLE_HAL_LOCKS
#if !CONFIG_DISABLE_HAL_LOCKS
if
(
nonStop
&&
nonStopTask
==
xTaskGetCurrentTaskHandle
()){
if
(
nonStop
&&
nonStopTask
==
xTaskGetCurrentTaskHandle
()){
log_e
(
"Unfinished Repeated Start transaction! Expected requestFrom, not beginTransmission! Clearing..."
);
log_e
(
"Unfinished Repeated Start transaction! Expected requestFrom, not beginTransmission! Clearing..."
);
...
@@ -247,6 +327,10 @@ void TwoWire::beginTransmission(uint16_t address)
...
@@ -247,6 +327,10 @@ void TwoWire::beginTransmission(uint16_t address)
uint8_t
TwoWire
::
endTransmission
(
bool
sendStop
)
uint8_t
TwoWire
::
endTransmission
(
bool
sendStop
)
{
{
if
(
is_slave
){
log_e
(
"Bus is in Slave Mode"
);
return
4
;
}
esp_err_t
err
=
ESP_OK
;
esp_err_t
err
=
ESP_OK
;
if
(
sendStop
){
if
(
sendStop
){
err
=
i2cWrite
(
num
,
txAddress
,
txBuffer
,
txLength
,
_timeOutMillis
);
err
=
i2cWrite
(
num
,
txAddress
,
txBuffer
,
txLength
,
_timeOutMillis
);
...
@@ -272,6 +356,10 @@ uint8_t TwoWire::endTransmission(bool sendStop)
...
@@ -272,6 +356,10 @@ uint8_t TwoWire::endTransmission(bool sendStop)
uint8_t
TwoWire
::
requestFrom
(
uint16_t
address
,
uint8_t
size
,
bool
sendStop
)
uint8_t
TwoWire
::
requestFrom
(
uint16_t
address
,
uint8_t
size
,
bool
sendStop
)
{
{
if
(
is_slave
){
log_e
(
"Bus is in Slave Mode"
);
return
0
;
}
esp_err_t
err
=
ESP_OK
;
esp_err_t
err
=
ESP_OK
;
if
(
nonStop
if
(
nonStop
#if !CONFIG_DISABLE_HAL_LOCKS
#if !CONFIG_DISABLE_HAL_LOCKS
...
@@ -402,5 +490,49 @@ uint8_t TwoWire::endTransmission(void)
...
@@ -402,5 +490,49 @@ uint8_t TwoWire::endTransmission(void)
return
endTransmission
(
true
);
return
endTransmission
(
true
);
}
}
size_t
TwoWire
::
slaveWrite
(
const
uint8_t
*
buffer
,
size_t
len
)
{
return
i2cSlaveWrite
(
num
,
buffer
,
len
,
_timeOutMillis
);
}
void
TwoWire
::
onReceiveService
(
uint8_t
num
,
uint8_t
*
inBytes
,
size_t
numBytes
,
bool
stop
,
void
*
arg
)
{
TwoWire
*
wire
=
(
TwoWire
*
)
arg
;
if
(
!
wire
->
user_onReceive
){
return
;
}
for
(
uint8_t
i
=
0
;
i
<
numBytes
;
++
i
){
wire
->
rxBuffer
[
i
]
=
inBytes
[
i
];
}
wire
->
rxIndex
=
0
;
wire
->
rxLength
=
numBytes
;
wire
->
user_onReceive
(
numBytes
);
}
void
TwoWire
::
onRequestService
(
uint8_t
num
,
void
*
arg
)
{
TwoWire
*
wire
=
(
TwoWire
*
)
arg
;
if
(
!
wire
->
user_onRequest
){
return
;
}
wire
->
txLength
=
0
;
wire
->
user_onRequest
();
if
(
wire
->
txLength
){
wire
->
slaveWrite
((
uint8_t
*
)
wire
->
txBuffer
,
wire
->
txLength
);
}
}
void
TwoWire
::
onReceive
(
void
(
*
function
)(
int
)
)
{
user_onReceive
=
function
;
}
// sets function called on slave read
void
TwoWire
::
onRequest
(
void
(
*
function
)(
void
)
)
{
user_onRequest
=
function
;
}
TwoWire
Wire
=
TwoWire
(
0
);
TwoWire
Wire
=
TwoWire
(
0
);
TwoWire
Wire1
=
TwoWire
(
1
);
TwoWire
Wire1
=
TwoWire
(
1
);
libraries/Wire/src/Wire.h
View file @
ed53b6c8
...
@@ -61,6 +61,13 @@ protected:
...
@@ -61,6 +61,13 @@ protected:
TaskHandle_t
nonStopTask
;
TaskHandle_t
nonStopTask
;
SemaphoreHandle_t
lock
;
SemaphoreHandle_t
lock
;
#endif
#endif
private:
bool
is_slave
;
void
(
*
user_onRequest
)(
void
);
void
(
*
user_onReceive
)(
int
);
static
void
onRequestService
(
uint8_t
,
void
*
);
static
void
onReceiveService
(
uint8_t
,
uint8_t
*
,
size_t
,
bool
,
void
*
);
bool
initPins
(
int
sdaPin
,
int
sclPin
);
public:
public:
TwoWire
(
uint8_t
bus_num
);
TwoWire
(
uint8_t
bus_num
);
...
@@ -70,6 +77,7 @@ public:
...
@@ -70,6 +77,7 @@ public:
bool
setPins
(
int
sda
,
int
scl
);
bool
setPins
(
int
sda
,
int
scl
);
bool
begin
(
int
sda
=-
1
,
int
scl
=-
1
,
uint32_t
frequency
=
0
);
// returns true, if successful init of i2c bus
bool
begin
(
int
sda
=-
1
,
int
scl
=-
1
,
uint32_t
frequency
=
0
);
// returns true, if successful init of i2c bus
bool
begin
(
uint8_t
slaveAddr
,
int
sda
=-
1
,
int
scl
=-
1
,
uint32_t
frequency
=
0
);
bool
end
();
bool
end
();
void
setTimeOut
(
uint16_t
timeOutMillis
);
// default timeout of i2c transactions is 50ms
void
setTimeOut
(
uint16_t
timeOutMillis
);
// default timeout of i2c transactions is 50ms
...
@@ -123,6 +131,7 @@ public:
...
@@ -123,6 +131,7 @@ public:
void
onReceive
(
void
(
*
)(
int
)
);
void
onReceive
(
void
(
*
)(
int
)
);
void
onRequest
(
void
(
*
)(
void
)
);
void
onRequest
(
void
(
*
)(
void
)
);
size_t
slaveWrite
(
const
uint8_t
*
,
size_t
);
};
};
extern
TwoWire
Wire
;
extern
TwoWire
Wire
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment