24
24
#include "soc/i2c_struct.h"
25
25
#include "soc/dport_reg.h"
26
26
#include "esp_attr.h"
27
-
27
+ #include "esp32-hal-cpu.h" // cpu clock change support 31DEC2018
28
28
//#define I2C_DEV(i) (volatile i2c_dev_t *)((i)?DR_REG_I2C1_EXT_BASE:DR_REG_I2C_EXT_BASE)
29
29
//#define I2C_DEV(i) ((i2c_dev_t *)(REG_I2C_BASE(i)))
30
30
#define I2C_SCL_IDX (p ) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
@@ -206,8 +206,8 @@ static i2c_t _i2c_bus_array[2] = {
206
206
{(volatile i2c_dev_t * )(DR_REG_I2C1_EXT_BASE_FIXED ), 1 , -1 , -1 ,I2C_NONE ,I2C_NONE ,I2C_ERROR_OK ,NULL ,NULL ,NULL ,0 ,0 ,0 ,0 ,0 }
207
207
};
208
208
#else
209
- #define I2C_MUTEX_LOCK () do {} while (xSemaphoreTake (i2c->lock, portMAX_DELAY) != pdPASS)
210
- #define I2C_MUTEX_UNLOCK () xSemaphoreGive (i2c->lock)
209
+ #define I2C_MUTEX_LOCK () do {} while (xSemaphoreTakeRecursive (i2c->lock, portMAX_DELAY) != pdPASS)
210
+ #define I2C_MUTEX_UNLOCK () xSemaphoreGiveRecursive (i2c->lock)
211
211
212
212
static i2c_t _i2c_bus_array [2 ] = {
213
213
{(volatile i2c_dev_t * )(DR_REG_I2C_EXT_BASE_FIXED ), NULL , 0 , -1 , -1 , I2C_NONE ,I2C_NONE ,I2C_ERROR_OK ,NULL ,NULL ,NULL ,0 ,0 ,0 ,0 ,0 ,0 },
@@ -445,6 +445,39 @@ static void IRAM_ATTR i2cTriggerDumps(i2c_t * i2c, uint8_t trigger, const char l
445
445
}
446
446
// end of debug support routines
447
447
448
+ /* Start of CPU Clock change Support
449
+ */
450
+
451
+ static void i2cApbChangeCallback (void * arg , apb_change_ev_t ev_type , uint32_t old_apb , uint32_t new_apb ){
452
+ i2c_t * i2c = (i2c_t * ) arg ; // recover data
453
+ if (i2c == NULL ) { // point to peripheral control block does not exits
454
+ return false;
455
+ }
456
+ uint32_t oldFreq = 0 ;
457
+ switch (ev_type ){
458
+ case APB_BEFORE_CHANGE :
459
+ if (new_apb < 3000000 ) {// too slow
460
+ log_e ("apb speed %d too slow" ,new_apb );
461
+ break ;
462
+ }
463
+ I2C_MUTEX_LOCK (); // lock will spin until current transaction is completed
464
+ break ;
465
+ case APB_AFTER_CHANGE :
466
+ oldFreq = (i2c -> dev -> scl_low_period .period + i2c -> dev -> scl_high_period .period ); //read old apbCycles
467
+ if (oldFreq > 0 ) { // was configured with value
468
+ oldFreq = old_apb / oldFreq ;
469
+ i2cSetFrequency (i2c ,oldFreq );
470
+ }
471
+ I2C_MUTEX_UNLOCK ();
472
+ break ;
473
+ default :
474
+ log_e ("unk ev %u" ,ev_type );
475
+ I2C_MUTEX_UNLOCK ();
476
+ }
477
+ return ;
478
+ }
479
+ /* End of CPU Clock change Support
480
+ */
448
481
static void IRAM_ATTR i2cSetCmd (i2c_t * i2c , uint8_t index , uint8_t op_code , uint8_t byte_num , bool ack_val , bool ack_exp , bool ack_check )
449
482
{
450
483
I2C_COMMAND_t cmd ;
@@ -1221,6 +1254,12 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
1221
1254
I2C_MUTEX_UNLOCK ();
1222
1255
return I2C_ERROR_MEMORY ;
1223
1256
}
1257
+ if ( !addApbChangeCallback ( i2c , i2cApbChangeCallback )) {
1258
+ log_e ("install apb Callback failed" );
1259
+ I2C_MUTEX_UNLOCK ();
1260
+ return I2C_ERROR_DEV ;
1261
+ }
1262
+
1224
1263
}
1225
1264
//hang until it completes.
1226
1265
@@ -1352,6 +1391,9 @@ static void i2cReleaseISR(i2c_t * i2c)
1352
1391
if (i2c -> intr_handle ) {
1353
1392
esp_intr_free (i2c -> intr_handle );
1354
1393
i2c -> intr_handle = NULL ;
1394
+ if (!removeApbChangeCallback ( i2c , i2cApbChangeCallback )) {
1395
+ log_e ("unable to release apbCallback" );
1396
+ }
1355
1397
}
1356
1398
}
1357
1399
@@ -1437,15 +1479,15 @@ i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda)
1437
1479
* PUBLIC API
1438
1480
* */
1439
1481
// 24Nov17 only supports Master Mode
1440
- i2c_t * i2cInit (uint8_t i2c_num , int8_t sda , int8_t scl , uint32_t frequency ) //before this is called, pins should be detached, else glitch
1441
- {
1482
+ i2c_t * i2cInit (uint8_t i2c_num , int8_t sda , int8_t scl , uint32_t frequency ) {
1442
1483
log_v ("num=%d sda=%d scl=%d freq=%d" ,i2c_num , sda , scl , frequency );
1443
1484
if (i2c_num > 1 ) {
1444
1485
return NULL ;
1445
1486
}
1446
1487
1447
1488
i2c_t * i2c = & _i2c_bus_array [i2c_num ];
1448
1489
1490
+ // pins should be detached, else glitch
1449
1491
if (i2c -> sda >= 0 ){
1450
1492
i2cDetachSDA (i2c , i2c -> sda );
1451
1493
}
@@ -1457,7 +1499,7 @@ i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) //b
1457
1499
1458
1500
#if !CONFIG_DISABLE_HAL_LOCKS
1459
1501
if (i2c -> lock == NULL ) {
1460
- i2c -> lock = xSemaphoreCreateMutex ();
1502
+ i2c -> lock = xSemaphoreCreateRecursiveMutex ();
1461
1503
if (i2c -> lock == NULL ) {
1462
1504
return NULL ;
1463
1505
}
@@ -1604,7 +1646,8 @@ i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, b
1604
1646
return last_error ;
1605
1647
}
1606
1648
1607
- #define MIN_I2C_CLKS 100
1649
+ #define MIN_I2C_CLKS 100 // minimum ratio between cpu and i2c Bus clocks
1650
+ #define INTERRUPT_CYCLE_OVERHEAD 16000 // number of cpu clocks necessary to respond to interrupt
1608
1651
i2c_err_t i2cSetFrequency (i2c_t * i2c , uint32_t clk_speed )
1609
1652
{
1610
1653
if (i2c == NULL ) {
@@ -1614,17 +1657,18 @@ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
1614
1657
uint32_t period = (apb /clk_speed ) / 2 ;
1615
1658
1616
1659
if ((apb /8192 > clk_speed )|| (apb /MIN_I2C_CLKS < clk_speed )){ //out of bounds
1617
- log_w ("i2c freq(%d) out of bounds.vs APB Clock(%d), min=%d, max=%d" ,clk_speed ,apb ,(apb /8192 ),(apb /MIN_I2C_CLKS ));
1660
+ log_d ("i2c freq(%d) out of bounds.vs APB Clock(%d), min=%d, max=%d" ,clk_speed ,apb ,(apb /8192 ),(apb /MIN_I2C_CLKS ));
1618
1661
}
1619
1662
if (period < (MIN_I2C_CLKS /2 ) ){
1620
1663
period = (MIN_I2C_CLKS /2 );
1621
1664
clk_speed = apb /(period * 2 );
1622
- log_w ("APB Freq too slow, Reducing i2c Freq to %d Hz" ,clk_speed );
1665
+ log_d ("APB Freq too slow, Reducing i2c Freq to %d Hz" ,clk_speed );
1623
1666
} else if ( period > 4095 ) {
1624
1667
period = 4095 ;
1625
1668
clk_speed = apb /(period * 2 );
1626
- log_w ("APB Freq too fast, Increasing i2c Freq to %d Hz" ,clk_speed );
1669
+ log_d ("APB Freq too fast, Increasing i2c Freq to %d Hz" ,clk_speed );
1627
1670
}
1671
+ log_v ("freq=%dHz" ,clk_speed );
1628
1672
1629
1673
uint32_t halfPeriod = period /2 ;
1630
1674
uint32_t quarterPeriod = period /4 ;
@@ -1633,14 +1677,19 @@ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
1633
1677
1634
1678
I2C_FIFO_CONF_t f ;
1635
1679
1636
- // Adjust Fifo thresholds based on frequency
1637
1680
f .val = i2c -> dev -> fifo_conf .val ;
1638
- uint32_t a = (clk_speed / 50000L )+ 1 ;
1639
- if (a > 24 ) a = 24 ;
1640
- f .rx_fifo_full_thrhd = 32 - a ;
1641
- f .tx_fifo_empty_thrhd = a ;
1681
+ /* Adjust Fifo thresholds based on differential between cpu frequency and bus clock.
1682
+ The fifo_delta is calculated such that at least INTERRUPT_CYCLE_OVERHEAD cpu clocks are
1683
+ available when a Fifo interrupt is triggered. This allows enough room in the Fifo so that
1684
+ interrupt latency does not cause a Fifo overflow/underflow event.
1685
+ */
1686
+ log_v ("cpu Freq=%dMhz, i2c Freq=%dHz" ,getCpuFrequencyMhz (),clk_speed );
1687
+ uint32_t fifo_delta = (INTERRUPT_CYCLE_OVERHEAD /((getCpuFrequencyMhz ()* 1000000 / clk_speed )* 10 ))+ 1 ;
1688
+ if (fifo_delta > 24 ) fifo_delta = 24 ;
1689
+ f .rx_fifo_full_thrhd = 32 - fifo_delta ;
1690
+ f .tx_fifo_empty_thrhd = fifo_delta ;
1642
1691
i2c -> dev -> fifo_conf .val = f .val ; // set thresholds
1643
- log_v ("Fifo threshold =%d" ,a );
1692
+ log_v ("Fifo delta =%d" ,fifo_delta );
1644
1693
1645
1694
//the clock num during SCL is low level
1646
1695
i2c -> dev -> scl_low_period .period = period ;
@@ -1696,6 +1745,8 @@ uint32_t i2cGetStatus(i2c_t * i2c){
1696
1745
}
1697
1746
else return 0 ;
1698
1747
}
1748
+
1749
+
1699
1750
/* todo
1700
1751
22JUL18
1701
1752
need to add multi-thread capability, use dq.queueEvent as the group marker. When multiple threads
0 commit comments