2424#include "soc/i2c_struct.h"
2525#include "soc/dport_reg.h"
2626#include "esp_attr.h"
27-
27+ #include "esp32-hal-cpu.h" // cpu clock change support 31DEC2018
2828//#define I2C_DEV(i) (volatile i2c_dev_t *)((i)?DR_REG_I2C1_EXT_BASE:DR_REG_I2C_EXT_BASE)
2929//#define I2C_DEV(i) ((i2c_dev_t *)(REG_I2C_BASE(i)))
3030#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] = {
206206 {(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 }
207207};
208208#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)
211211
212212static i2c_t _i2c_bus_array [2 ] = {
213213 {(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
445445}
446446 // end of debug support routines
447447
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+ */
448481static 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 )
449482{
450483 I2C_COMMAND_t cmd ;
@@ -1221,6 +1254,12 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
12211254 I2C_MUTEX_UNLOCK ();
12221255 return I2C_ERROR_MEMORY ;
12231256 }
1257+ if ( !addApbChangeCallback ( i2c , i2cApbChangeCallback )) {
1258+ log_e ("install apb Callback failed" );
1259+ I2C_MUTEX_UNLOCK ();
1260+ return I2C_ERROR_DEV ;
1261+ }
1262+
12241263 }
12251264 //hang until it completes.
12261265
@@ -1352,6 +1391,9 @@ static void i2cReleaseISR(i2c_t * i2c)
13521391 if (i2c -> intr_handle ) {
13531392 esp_intr_free (i2c -> intr_handle );
13541393 i2c -> intr_handle = NULL ;
1394+ if (!removeApbChangeCallback ( i2c , i2cApbChangeCallback )) {
1395+ log_e ("unable to release apbCallback" );
1396+ }
13551397 }
13561398}
13571399
@@ -1437,15 +1479,15 @@ i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda)
14371479 * PUBLIC API
14381480 * */
14391481// 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 ) {
14421483 log_v ("num=%d sda=%d scl=%d freq=%d" ,i2c_num , sda , scl , frequency );
14431484 if (i2c_num > 1 ) {
14441485 return NULL ;
14451486 }
14461487
14471488 i2c_t * i2c = & _i2c_bus_array [i2c_num ];
14481489
1490+ // pins should be detached, else glitch
14491491 if (i2c -> sda >= 0 ){
14501492 i2cDetachSDA (i2c , i2c -> sda );
14511493 }
@@ -1457,7 +1499,7 @@ i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) //b
14571499
14581500#if !CONFIG_DISABLE_HAL_LOCKS
14591501 if (i2c -> lock == NULL ) {
1460- i2c -> lock = xSemaphoreCreateMutex ();
1502+ i2c -> lock = xSemaphoreCreateRecursiveMutex ();
14611503 if (i2c -> lock == NULL ) {
14621504 return NULL ;
14631505 }
@@ -1604,7 +1646,8 @@ i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, b
16041646 return last_error ;
16051647}
16061648
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
16081651i2c_err_t i2cSetFrequency (i2c_t * i2c , uint32_t clk_speed )
16091652{
16101653 if (i2c == NULL ) {
@@ -1614,17 +1657,18 @@ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
16141657 uint32_t period = (apb /clk_speed ) / 2 ;
16151658
16161659 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 ));
16181661 }
16191662 if (period < (MIN_I2C_CLKS /2 ) ){
16201663 period = (MIN_I2C_CLKS /2 );
16211664 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 );
16231666 } else if ( period > 4095 ) {
16241667 period = 4095 ;
16251668 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 );
16271670 }
1671+ log_v ("freq=%dHz" ,clk_speed );
16281672
16291673 uint32_t halfPeriod = period /2 ;
16301674 uint32_t quarterPeriod = period /4 ;
@@ -1633,14 +1677,19 @@ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
16331677
16341678 I2C_FIFO_CONF_t f ;
16351679
1636- // Adjust Fifo thresholds based on frequency
16371680 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 ;
16421691 i2c -> dev -> fifo_conf .val = f .val ; // set thresholds
1643- log_v ("Fifo threshold =%d" ,a );
1692+ log_v ("Fifo delta =%d" ,fifo_delta );
16441693
16451694 //the clock num during SCL is low level
16461695 i2c -> dev -> scl_low_period .period = period ;
@@ -1696,6 +1745,8 @@ uint32_t i2cGetStatus(i2c_t * i2c){
16961745 }
16971746 else return 0 ;
16981747}
1748+
1749+
16991750/* todo
17001751 22JUL18
17011752 need to add multi-thread capability, use dq.queueEvent as the group marker. When multiple threads
0 commit comments