We are working on external RTC MCP7940(i2c) interfaced with nrf52840. Please check if drivers of the same for nrf52/51 are available or any implementation of CLOCK using MCP7940 with NRF?
Regards
Vishal Aditya
Embedded Software Engineer
We are working on external RTC MCP7940(i2c) interfaced with nrf52840. Please check if drivers of the same for nrf52/51 are available or any implementation of CLOCK using MCP7940 with NRF?
Regards
Vishal Aditya
Embedded Software Engineer
HI Vishal,
I am afraid that we do not have any dedicated drivers from the MCP7940. I am also not aware of any customers that have used the MCP7940 as the 32kHz clock source for the nRF5x series, but Ithink it should be possible.
We have TWI hardware drivers in our nRF5 SDK for the nRF51 and 52 series, see Driver support matrix.
Best regards
Bjørn
bjorn-spockeli
I am writing drivers by myself & stuck in the first step of I2C DETECT not happening.
SDK: nRF5_SDK_15.2.0_9412b96\examples\peripheral\twi_scanner
MCP7940 Break-out: https://rheingoldheavy.com/product/breakout-board-mcp7940/ which works perfectly with Arduino at I2C Address: 0x6F
But I2C DETECT not working with nrf52840 DK. Please suggest how to debug this issue? We have an Oscilloscope!
Yes calling init_MCP7940()
Below register maps:
const uint8_t MCP7940_I2C = 0xDE;
const uint8_t MCP7940_RTCSEC = 0x00; ///< Timekeeping, RTCSEC Register address
const uint8_t MCP7940_RTCMIN = 0x01; ///< Timekeeping, RTCMIN Register address
const uint8_t MCP7940_RTCHOUR = 0x02; ///< Timekeeping, RTCHOUR Register address
const uint8_t MCP7940_RTCWKDAY = 0x03; ///< Timekeeping, RTCWKDAY Register address
const uint8_t MCP7940_RTCDATE = 0x04; ///< Timekeeping, RTCDATE Register address
const uint8_t MCP7940_RTCMTH = 0x05; ///< Timekeeping, RTCMTH Register address
const uint8_t MCP7940_RTCYEAR = 0x06; ///< Timekeeping, RTCYEAR Register address
const uint8_t MCP7940_CONTROL = 0x07; ///< Timekeeping, RTCCONTROL Register address
const uint8_t MCP7940_OSCTRIM = 0x08; ///< Timekeeping, RTCOSCTRIM Register address
const uint8_t MCP7940_ALM0SEC = 0x0A; ///< Alarm 0, ALM0SEC Register address
const uint8_t MCP7940_ALM0MIN = 0x0B; ///< Alarm 0, ALM0MIN Register address
const uint8_t MCP7940_ALM0HOUR = 0x0C; ///< Alarm 0, ALM0HOUR Register address
const uint8_t MCP7940_ALM0WKDAY = 0x0D; ///< Alarm 0, ALM0WKDAY Register address
const uint8_t MCP7940_ALM0DATE = 0x0E; ///< Alarm 0, ALM0DATE Register address
const uint8_t MCP7940_ALM0MTH = 0x0F; ///< Alarm 0, ALM0MTH Register address
const uint8_t MCP7940_ALM1SEC = 0x11; ///< Alarm 1, ALM1SEC Register address
const uint8_t MCP7940_ALM1MIN = 0x12; ///< Alarm 1, ALM1MIN Register address
const uint8_t MCP7940_ALM1HOUR = 0x13; ///< Alarm 1, ALM1HOUR Register address
const uint8_t MCP7940_ALM1WKDAY = 0x14; ///< Alarm 1, ALM1WKDAY Register address
const uint8_t MCP7940_ALM1DATE = 0x15; ///< Alarm 1, ALM1DATE Register address
const uint8_t MCP7940_ALM1MTH = 0x16; ///< Alarm 1, ALM1MONTH Register address
const uint8_t MCP7940_PWRDNMIN = 0x18; ///< Power-Fail, PWRDNMIN Register address
const uint8_t MCP7940_PWRDNHOUR = 0x19; ///< Power-Fail, PWRDNHOUR Register address
const uint8_t MCP7940_PWRDNDATE = 0x1A; ///< Power-Fail, PWDNDATE Register address
const uint8_t MCP7940_PWRDNMTH = 0x1B; ///< Power-Fail, PWRDNMTH Register address
const uint8_t MCP7940_PWRUPMIN = 0x1C; ///< Power-Fail, PWRUPMIN Register address
const uint8_t MCP7940_PWRUPHOUR = 0x1D; ///< Power-Fail, PWRUPHOUR Register address
const uint8_t MCP7940_PWRUPDATE = 0x1E; ///< Power-Fail, PWRUPDATE Register address
const uint8_t MCP7940_PWRUPMTH = 0x1F; ///< Power-Fail, PWRUPMTH Register address
const uint8_t MCP7940_RAM_ADDRESS = 0x20; ///< NVRAM - Start address for SRAM
const uint8_t MCP7940_ST = 7; ///< MCP7940 register bits. RTCSEC reg
const uint8_t MCP7940_12_24 = 6; ///< RTCHOUR, PWRDNHOUR & PWRUPHOUR
const uint8_t MCP7940_AM_PM = 5; ///< RTCHOUR, PWRDNHOUR & PWRUPHOUR
const uint8_t MCP7940_OSCRUN = 5; ///< RTCWKDAY register
const uint8_t MCP7940_PWRFAIL = 4; ///< RTCWKDAY register
const uint8_t MCP7940_VBATEN = 3; ///< RTCWKDAY register
const uint8_t MCP7940_LPYR = 5; ///< RTCMTH register
const uint8_t MCP7940_OUT = 7; ///< CONTROL register
const uint8_t MCP7940_SQWEN = 6; ///< CONTROL register
const uint8_t MCP7940_ALM1EN = 5; ///< CONTROL register
const uint8_t MCP7940_ALM0EN = 4; ///< CONTROL register
const uint8_t MCP7940_EXTOSC = 3; ///< CONTROL register
const uint8_t MCP7940_CRSTRIM = 2; ///< CONTROL register
const uint8_t MCP7940_SQWFS1 = 1; ///< CONTROL register
const uint8_t MCP7940_SQWFS0 = 0; ///< CONTROL register
const uint8_t MCP7940_SIGN = 7; ///< OSCTRIM register
const uint8_t MCP7940_ALMPOL = 7; ///< ALM0WKDAY register
const uint8_t MCP7940_ALM0IF = 3; ///< ALM0WKDAY register
const uint8_t MCP7940_ALM1IF = 3; ///< ALM1WKDAY register
const uint32_t SECONDS_PER_DAY = 86400; ///< 60 secs * 60 mins * 24 hours
const uint32_t SECONDS_FROM_1970_TO_2000 = 946684800; ///< Seconds between year 1970 and 2000
Please let me know if any traces required at any line with break-point? Also, I can send the drivers again with a private link to your INBOX it is required?
The trace clearly show that its only the MCP7940_I2C address that is transmitted. The nrf_drv_twi_tx documentation states that the data passed to it should be a uint8_t pointer, so try passing it like this
uint8_t tx_data = REG_RTCHOUR;
err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C,&tx_data , sizeof(tx_data));
APP_ERROR_CHECK(err_code)
Furthermore what does the bitClear (registerValue, 6) and bitSet (registerValue, 6) functions do? You are passing they're return value as the length parameter to nrf_drv_twi_tx and nrf_drv_twi_rx.
void init_MCP7940() {
char registerValue = 0x00; // Holds the received register value
char twelveHour = 0x00; // 0 = 24 Hour Clock Mode / 1 = 12 Hour Clock Mode
char startClock = 0x01; // 0 = Start Oscillator / 1 = Stop Oscillator
// Turn on/off: 12 hour vs. 24 hour clock
err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C, REG_RTCHOUR, 1);
err_code = nrf_drv_twi_rx(&m_twi, MCP7940_I2C, registerValue, sizeof(MCP7940_I2C));
if (twelveHour == 0x00) err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C, REG_RTCHOUR, bitClear (registerValue, 6));
if (twelveHour == 0x01) err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C, REG_RTCHOUR, bitSet (registerValue, 6));
// Turn on/off: Oscillator (starts the clock)
err_code = nrf_drv_twi_rx(&m_twi, MCP7940_I2C, registerValue, 1);
if (startClock == 0x00) err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C, REG_RTCSEC, bitClear (registerValue, 7));
if (startClock == 0x01) err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C, REG_RTCSEC, bitSet (registerValue, 7));
}
Custom defined which works as below:
https://www.arduino.cc/reference/en/language/functions/bits-and-bytes/bitclear/
https://www.arduino.cc/reference/en/language/functions/bits-and-bytes/bitset/
Will update the traces & API call as per this soon!
uint8_t tx_data = REG_RTCHOUR;
err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C,&tx_data , sizeof(tx_data));
APP_ERROR_CHECK(err_code)
Pls check the trace of REG_RTCHOUR,
const uint8_t MCP7940_RTCHOUR = 0x02; ///< Timekeeping, RTCHOUR Register address
Yes, now you are writing to register with address 0x02 of the device with address 0xDE, but you are not providing the value you want to write to register 0x02.
uint8_t tx_data[] = {REG_RTCHOUR, <value to write to REG_RTCHOUR register> }; err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C,tx_data , sizeof(tx_data)); APP_ERROR_CHECK(err_code)
Yes, now you are writing to register with address 0x02 of the device with address 0xDE, but you are not providing the value you want to write to register 0x02.
uint8_t tx_data[] = {REG_RTCHOUR, <value to write to REG_RTCHOUR register> }; err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C,tx_data , sizeof(tx_data)); APP_ERROR_CHECK(err_code)
Pls check
const uint8_t MCP7940_ST = 7; ///< MCP7940 register bits. RTCSEC reg //REST variables remains same as above while(1) { uint8_t tx_data[] = {REG_RTCSEC, MCP7940_ST }; uint8_t rx_data[] = REG_RTCSEC; //trying to start oscillator err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C,tx_data , sizeof(tx_data),false); APP_ERROR_CHECK(err_code); err_code = nrf_drv_twi_rx(&m_twi,MCP7940_I2C,rx_data,1); nrf_delay_ms(1); }
If you want to start the oscillator, then you need to set bit 7 in REG_RTCSEC to 1, i.e. you need to write 0x80 not 0x07.
The read operation is Not Acknowledged so it could be that you have to select the register you want to read from before
// Read REG_RTCSEC register
uint8_t tx_data[] = {REG_RTCSEC };
uint8_t rx_data[] = {0};
// Select REG_RTCSEC register and use repeated start
err_code = nrf_drv_twi_tx(&m_twi,MCP7940_I2C,tx_data , sizeof(tx_data),true);
APP_ERROR_CHECK(err_code);
// Read REG_RTCSEC register
err_code = nrf_drv_twi_rx(&m_twi,MCP7940_I2C,rx_data,1);
APP_ERROR_CHECK(err_code);
Please check still NAK
Yes, but you are reading back the value of the register, i.e. 0x07. Wasnt that what you wrote to the register previously? What is the return code of nrf_drv_twi_rx()? Is it NRF_ERROR_DRV_TWI_ERR_DNACK or NRF_ERROR_DRV_TWI_ERR_ANACK?
err_code = 0