You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于ATSAMG55J19的MCP79411 RTC I2C/TWI通信问题求助

Fixing MCP79411 I2C Communication with ATSAMG55 (ASF 3)

Let's break down the issues in your current code and walk through the correct I2C transaction flow for the MCP79411—ASF's TWI library requires explicit control over start/stop/repeated start signals, which your code is missing, leading to failed reads.

Key Issues in Your Current Code

  • Reinitializing TWI on every operation: Your i2c_start() function resets the TWI peripheral every time it's called, which breaks bus state consistency. TWI initialization should happen once at system startup, not per transaction.
  • Missing critical bus control signals: ASF's TWI library doesn't auto-send start/stop/repeated start signals. You need to explicitly call functions like twi_master_send_start(), twi_master_send_repeated_start(), and twi_master_send_stop() to manage the bus.
  • Incorrect read transaction flow: To read from an RTC register, you first write the register address, then send a repeated start before switching to read mode. Your code skips this critical step.
  • Improper byte read handling: When reading multiple bytes, send an ACK for all bytes except the last one (send a NACK to signal the end of the read).

Step-by-Step Corrected Implementation

1. Global TWI Initialization (Run Once)

First, initialize the TWI peripheral once at system startup (e.g., in main() before calling rtc_Init()):

#include <asf.h>

// MCP79411 I2C Address (7-bit base address is 0x6F)
#define RTCC_ADDR 0x6F
#define RTCC_WRITE_ADDR (RTCC_ADDR << 1) | 0x00
#define RTCC_READ_ADDR  (RTCC_ADDR << 1) | 0x01

// MCP79411 Register Addresses
#define RTCC_REG_SEC   0x00
#define RTCC_REG_MIN   0x01
#define RTCC_REG_HR    0x02
#define RTCC_REG_CTRL  0x07

static void twi_init(void) {
    flexcom_enable(FLEXCOM4);
    flexcom_set_opmode(FLEXCOM4, FLEXCOM_TWI);
    
    twi_options_t twi_options;
    twi_options.master_clk = sysclk_get_cpu_hz();
    twi_options.speed = 100000; // 100kHz standard I2C mode
    twi_options.smbus = 0;
    
    if (twi_master_init(TWI4, &twi_options) != TWI_SUCCESS) {
        // Handle initialization error (e.g., trap in loop)
        while(1);
    }
}

2. Corrected RTC Initialization

The MCP79411 requires setting the ST bit (bit 7 of the seconds register) to start its oscillator. Here's the proper transaction flow:

// Helper functions (ensure these are defined in your code)
uint8_t bcd2bin(uint8_t bcd) { return ((bcd >> 4) * 10) + (bcd & 0x0F); }
uint8_t bin2bcd(uint8_t bin) { return ((bin / 10) << 4) + (bin % 10); }

void rtc_Init(void) {
    uint8_t seconds;
    
    // Step 1: Read current seconds register value
    twi_master_send_start(TWI4, RTCC_WRITE_ADDR, TWI_WRITE);
    twi_master_write_byte(TWI4, RTCC_REG_SEC, TWI_MASTER_ACTIVE);
    twi_master_send_repeated_start(TWI4, RTCC_READ_ADDR, TWI_READ);
    
    // Read seconds (send NACK since it's the only byte, then stop)
    twi_master_read_byte(TWI4, &seconds, TWI_MASTER_STOP);
    
    // Step 2: Set ST bit to start oscillator, preserve current seconds value
    seconds = bcd2bin(seconds & 0x7F); // Mask out existing ST bit
    uint8_t sec_bcd = bin2bcd(seconds) | 0x80; // Set ST bit
    
    twi_master_send_start(TWI4, RTCC_WRITE_ADDR, TWI_WRITE);
    twi_master_write_byte(TWI4, RTCC_REG_SEC, TWI_MASTER_ACTIVE);
    twi_master_write_byte(TWI4, sec_bcd, TWI_MASTER_STOP);
    
    // Step 3: Disable square wave output (control register 0x07, bit 7 = 1 disables)
    twi_master_send_start(TWI4, RTCC_WRITE_ADDR, TWI_WRITE);
    twi_master_write_byte(TWI4, RTCC_REG_CTRL, TWI_MASTER_ACTIVE);
    twi_master_write_byte(TWI4, 0x80, TWI_MASTER_STOP);
}

3. Corrected Time Read Function

To read hours, minutes, and seconds, follow the standard I2C read flow for register-based devices:

void rtc_get_time(uint8_t *hr, uint8_t *min, uint8_t *sec) {
    // Step 1: Send start, write device address, write starting register (0x00)
    twi_master_send_start(TWI4, RTCC_WRITE_ADDR, TWI_WRITE);
    twi_master_write_byte(TWI4, RTCC_REG_SEC, TWI_MASTER_ACTIVE);
    
    // Step 2: Repeated start to switch to read mode
    twi_master_send_repeated_start(TWI4, RTCC_READ_ADDR, TWI_READ);
    
    // Step 3: Read bytes - send ACK for first two, NACK + stop for last
    twi_master_read_byte(TWI4, sec, TWI_MASTER_ACTIVE); // Seconds (ACK)
    twi_master_read_byte(TWI4, min, TWI_MASTER_ACTIVE); // Minutes (ACK)
    twi_master_read_byte(TWI4, hr, TWI_MASTER_STOP);    // Hours (NACK + Stop)
    
    // Convert BCD to binary and mask out non-time bits
    *sec = bcd2bin(*sec & 0x7F);
    *min = bcd2bin(*min & 0x7F);
    *hr = bcd2bin(*hr & 0x3F); // Mask out 12/24 mode and AM/PM bits for 24h format
}

Important Notes

  • Error Handling: For robustness, add checks for return values of all TWI functions (e.g., twi_master_send_start() returns TWI_SUCCESS or an error code) to catch issues like no ACK from the RTC module.
  • Hardware Checks: Ensure 4.7kΩ pull-up resistors are connected to SDA and SCL lines (standard for 100kHz I2C).
  • Debugging: If issues persist, use an oscilloscope or logic analyzer to verify:
    • Presence of valid start/stop signals
    • Correct device and register addresses being sent
    • RTC sending ACKs after each transmitted byte

内容的提问来源于stack exchange,提问作者Edoardo Lobbiani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 12:32:31