基于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(), andtwi_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()returnsTWI_SUCCESSor 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
相关产品推荐
相关产品推荐

