diff --git a/drivers/timers/mcp794xx.c b/drivers/timers/mcp794xx.c index 54953a0c73..2734c87f5a 100644 --- a/drivers/timers/mcp794xx.c +++ b/drivers/timers/mcp794xx.c @@ -77,6 +77,7 @@ struct mcp794xx_dev_s { FAR struct i2c_master_s *i2c; /* Contained reference to the I2C bus driver. */ uint8_t addr; /* The I2C device address. */ + bool coarse_trim; /* Coarse trim mode */ }; /**************************************************************************** @@ -182,6 +183,105 @@ static int rtc_bcd2bin(uint8_t value) * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: mcp794xx_rtc_set_trim + * + * Description: + * Sets the digital trimming to correct for inaccuracies of clock source. + * Digital trimming consists of the MCP794XX periodically adding or + * subtracting clock cycles, resulting in small adjustments in the internal + * timing. + * + * Input Parameters: + * trim_val - Calculated trimming value, refer to MCP794XX reference + * manual. + * rtc_slow - True indicates RTC is behind real clock, false otherwise. + * This has to be set to ensure correct trimming direction. + * coarse_mode - MCP794XX allows coarse mode that trims every second + * instead of every minute. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int mcp794xx_rtc_set_trim(uint8_t trim_val, bool rtc_slow, bool coarse_mode) +{ + struct i2c_msg_s msg[2]; + uint8_t buffer[2]; + uint8_t address; + uint8_t ctrl; + int ret; + + if (g_mcp794xx.coarse_trim != coarse_mode) + { + address = MCP794XX_REG_CONTROL; + msg[0].frequency = CONFIG_MCP794XX_I2C_FREQUENCY; + msg[0].addr = g_mcp794xx.addr; + msg[0].flags = I2C_M_NOSTOP; + msg[0].buffer = &address; + msg[0].length = 1; + + msg[1].frequency = CONFIG_MCP794XX_I2C_FREQUENCY; + msg[1].addr = g_mcp794xx.addr; + msg[1].flags = I2C_M_READ; + msg[1].buffer = &ctrl; + msg[1].length = 1; + + ret = I2C_TRANSFER(g_mcp794xx.i2c, msg, 2); + if (ret < 0) + { + rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret); + return ret; + } + + ctrl &= ~MCP794XX_CONTROL_CRSTRIM; + if (coarse_mode) + { + ctrl |= MCP794XX_CONTROL_CRSTRIM; + } + + buffer[0] = MCP794XX_REG_CONTROL; + buffer[1] = ctrl; + msg[0].frequency = CONFIG_MCP794XX_I2C_FREQUENCY; + msg[0].addr = g_mcp794xx.addr; + msg[0].flags = 0; + msg[0].buffer = buffer; + msg[0].length = 2; + + ret = I2C_TRANSFER(g_mcp794xx.i2c, msg, 1); + if (ret < 0) + { + rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret); + return ret; + } + + g_mcp794xx.coarse_trim = coarse_mode; + } + + buffer[0] = MCP794XX_REG_OSCTRIM; + buffer[1] = trim_val & 0x7; + if (rtc_slow) + { + buffer[1] |= MCP794XX_OSCTRIM_SIGN; + } + + msg[0].frequency = CONFIG_MCP794XX_I2C_FREQUENCY; + msg[0].addr = g_mcp794xx.addr; + msg[0].flags = 0; + msg[0].buffer = buffer; + msg[0].length = 2; + + ret = I2C_TRANSFER(g_mcp794xx.i2c, msg, 1); + if (ret < 0) + { + rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret); + return ret; + } + + return OK; +} + /**************************************************************************** * Name: mcp794xx_rtc_initialize * @@ -211,9 +311,10 @@ int mcp794xx_rtc_initialize(FAR struct i2c_master_s *i2c, uint8_t addr) { /* Remember the i2c device and claim that the RTC is enabled */ - g_mcp794xx.i2c = i2c; - g_mcp794xx.addr = addr; - g_rtc_enabled = true; + g_mcp794xx.i2c = i2c; + g_mcp794xx.addr = addr; + g_mcp794xx.coarse_trim = false; + g_rtc_enabled = true; return OK; } diff --git a/include/nuttx/timers/mcp794xx.h b/include/nuttx/timers/mcp794xx.h index 7b8abf1f9b..d75c63356c 100644 --- a/include/nuttx/timers/mcp794xx.h +++ b/include/nuttx/timers/mcp794xx.h @@ -41,6 +41,30 @@ extern "C" #define EXTERN extern #endif +/**************************************************************************** + * Name: mcp794xx_rtc_set_trim + * + * Description: + * Sets the digital trimming to correct for inaccuracies of clock source. + * Digital trimming consists of the MCP794XX periodically adding or + * subtracting clock cycles, resulting in small adjustments in the internal + * timing. + * + * Input Parameters: + * trim_val - Calculated trimming value, refer to MCP794XX reference + * manual. + * rtc_slow - True indicates RTC is behind real clock, false otherwise. + * This has to be set to ensure correct trimming direction. + * coarse_mode - MCP794XX allows coarse mode that trims every second + * instead of every minute. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int mcp794xx_rtc_set_trim(uint8_t trim_val, bool rtc_slow, bool coarse_mode); + /**************************************************************************** * Name: mcp794xx_rtc_initialize *