Skip to content

Commit

Permalink
timers/mcp794xx: add option to digital trimming
Browse files Browse the repository at this point in the history
MCP794XX supports digital trimming that periodically adds or subtracts
clock cycles, resulting in small adjustments in the internal timing.
This way inaccuracies of clock source can be compensated.

This commit adds option to set the trimming register for MCP794XX.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
  • Loading branch information
michallenc committed May 28, 2024
1 parent 81b26a2 commit 5e32731
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 3 deletions.
106 changes: 103 additions & 3 deletions drivers/timers/mcp794xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
};

/****************************************************************************
Expand Down Expand Up @@ -182,6 +183,104 @@ 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
*
Expand Down Expand Up @@ -211,9 +310,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;
}

Expand Down
24 changes: 24 additions & 0 deletions include/nuttx/timers/mcp794xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down

0 comments on commit 5e32731

Please sign in to comment.