ATmega644P + RTC: I2C problems

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys. I've been trying to figure out I2C the past couple of days and I am stuck with a few bugs which I cannot rid myself of.

 

Short version: I have established an I2C link between the ATmega644P and a breakout board of the DS3231 RTC module, but when I request data I receive what appears to be nonsense.

 

Long version: Here is a schematic of what I have wired up (forgive my love for pen and paper, I'm slightly conservative):

The resonator runs at 16 MHz and I am using Atmel Studio 6.2 with the Atmel ICE debugger to program the AVR. I am using the TWI_master library from Atmel to do the protocol stuff which a friend of mine provided me with. I cannot say I fully understand the code, which is probably where my problem is. All the code can be found in the bottom of this post, and I hope my comments in main.c clarify what I'm thinking. The datasheet for the RTC module can be found here: http://datasheets.maximintegrated.com/en/ds/DS3231.pdf 

 

The bytes I receive are put onto PORTD and I am using a virtual instrument called Level Reader with NI's myDAQ to read the output.

 

Symptoms:

  • I do receive data, but when I am "sampling" every 2000 ms the 2nd byte of the buffer contains a random bit pattern, leading me to believe that the DS3231 does not set its register pointer correctly. 
  • The first byte of the buffer, which should always be the address (0x68) of the module, is constantly equal to 0xD1. Correction: I forgot to bit-shift the 7 bit address and was therefore reading it incorrectly. The first byte of the received message is indeed the RTC's address 0x68.
  • I can read and write to the RTC module using an Arduino Uno and the Wire.h library without problems, so the problem is most likely software-related.

 

I do not have access to a logic analyzer at this time, so debugging is indeed a bit difficult. I hope I have provided you with enough information.

 

/*****************************************************************************
*
* Atmel Corporation
*
* File              : TWI_Master.h
* Compiler          : IAR EWAAVR 2.28a/3.10c
* Revision          : $Revision: 1.13 $
* Date              : $Date: 24. mai 2004 11:31:22 $
* Updated by        : $Author: ltwa $
*
* Support mail      : avr@atmel.com
*
* Supported devices : All devices with a TWI module can be used.
*                     The example is written for the ATmega16
*
* AppNote           : AVR315 - TWI Master Implementation
*
* Description       : Header file for TWI_Master.c
*                     Include this file in the application.
*
****************************************************************************/

/****************************************************************************
  TWI Status/Control register definitions
****************************************************************************/
#define TWI_BUFFER_SIZE 10   // Set this to the largest message size that will be sent including address byte.

#define TWI_TWBR            0x0C        // TWI Bit rate Register setting.
                                        // Se Application note for detailed
                                        // information on setting this value.
										// Gives 400 kHz SCL frq.
// Not used defines!
//#define TWI_TWPS          0x00        // This driver presumes prescaler = 00

/****************************************************************************
  Global definitions
****************************************************************************/

union TWI_statusReg                       // Status byte holding flags.
{
    unsigned char all;
    struct
    {
        unsigned char lastTransOK:1;
        unsigned char unusedBits:7;
    };
};

extern union TWI_statusReg TWI_statusReg;

/****************************************************************************
  Function definitions
****************************************************************************/
void TWI_Master_Initialise( void );
unsigned char TWI_Transceiver_Busy( void );
unsigned char TWI_Get_State_Info( void );
void TWI_Start_Transceiver_With_Data( unsigned char * , unsigned char );
void TWI_Start_Transceiver( void );
unsigned char TWI_Get_Data_From_Transceiver( unsigned char *, unsigned char );

/****************************************************************************
  Bit and byte definitions
****************************************************************************/
#define TWI_READ_BIT  0       // Bit position for R/W bit in "address byte".
#define TWI_ADR_BITS  1       // Bit position for LSB of the slave address bits in the init byte.

#define TRUE          1
#define FALSE         0

/****************************************************************************
  TWI State codes
****************************************************************************/
// General TWI Master staus codes
#define TWI_START                  0x08  // START has been transmitted
#define TWI_REP_START              0x10  // Repeated START has been transmitted
#define TWI_ARB_LOST               0x38  // Arbitration lost

// TWI Master Transmitter staus codes
#define TWI_MTX_ADR_ACK            0x18  // SLA+W has been tramsmitted and ACK received
#define TWI_MTX_ADR_NACK           0x20  // SLA+W has been tramsmitted and NACK received
#define TWI_MTX_DATA_ACK           0x28  // Data byte has been tramsmitted and ACK received
#define TWI_MTX_DATA_NACK          0x30  // Data byte has been tramsmitted and NACK received 

// TWI Master Receiver staus codes
#define TWI_MRX_ADR_ACK            0x40  // SLA+R has been tramsmitted and ACK received
#define TWI_MRX_ADR_NACK           0x48  // SLA+R has been tramsmitted and NACK received
#define TWI_MRX_DATA_ACK           0x50  // Data byte has been received and ACK tramsmitted
#define TWI_MRX_DATA_NACK          0x58  // Data byte has been received and NACK tramsmitted

// TWI Slave Transmitter staus codes
#define TWI_STX_ADR_ACK            0xA8  // Own SLA+R has been received; ACK has been returned
#define TWI_STX_ADR_ACK_M_ARB_LOST 0xB0  // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned
#define TWI_STX_DATA_ACK           0xB8  // Data byte in TWDR has been transmitted; ACK has been received
#define TWI_STX_DATA_NACK          0xC0  // Data byte in TWDR has been transmitted; NOT ACK has been received
#define TWI_STX_DATA_ACK_LAST_BYTE 0xC8  // Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received

// TWI Slave Receiver staus codes
#define TWI_SRX_ADR_ACK            0x60  // Own SLA+W has been received ACK has been returned
#define TWI_SRX_ADR_ACK_M_ARB_LOST 0x68  // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned
#define TWI_SRX_GEN_ACK            0x70  // General call address has been received; ACK has been returned
#define TWI_SRX_GEN_ACK_M_ARB_LOST 0x78  // Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returned
#define TWI_SRX_ADR_DATA_ACK       0x80  // Previously addressed with own SLA+W; data has been received; ACK has been returned
#define TWI_SRX_ADR_DATA_NACK      0x88  // Previously addressed with own SLA+W; data has been received; NOT ACK has been returned
#define TWI_SRX_GEN_DATA_ACK       0x90  // Previously addressed with general call; data has been received; ACK has been returned
#define TWI_SRX_GEN_DATA_NACK      0x98  // Previously addressed with general call; data has been received; NOT ACK has been returned
#define TWI_SRX_STOP_RESTART       0xA0  // A STOP condition or repeated START condition has been received while still addressed as Slave

// TWI Miscellaneous status codes
#define TWI_NO_STATE               0xF8  // No relevant state information available; TWINT = “0”
#define TWI_BUS_ERROR              0x00  // Bus error due to an illegal START or STOP condition
/*****************************************************************************
*
* Atmel Corporation
*
* File              : TWI_Master.c
* Compiler          : IAR EWAAVR 2.28a/3.10c
* Revision          : $Revision: 1.13 $
* Date              : $Date: 24. mai 2004 11:31:20 $
* Updated by        : $Author: ltwa $
*
* Support mail      : avr@atmel.com
*
* Supported devices : All devices with a TWI module can be used.
*                     The example is written for the ATmega16
*
* AppNote           : AVR315 - TWI Master Implementation
*
* Description       : This is a sample driver for the TWI hardware modules.
*                     It is interrupt driveren. All functionality is controlled through
*                     passing information to and from functions. Se main.c for samples
*                     of how to use the driver.
*
*
****************************************************************************/

#include <avr/io.h>
#include <avr/interrupt.h>
#include "TWI_Master.h"

static unsigned char TWI_buf[ TWI_BUFFER_SIZE ];    // Transceiver buffer
static unsigned char TWI_msgSize;                   // Number of bytes to be transmitted.
static unsigned char TWI_state = TWI_NO_STATE;      // State byte. Default set to TWI_NO_STATE.

union TWI_statusReg TWI_statusReg = {0};            // TWI_statusReg is defined in TWI_Master.h

/****************************************************************************
Call this function to set up the TWI master to its initial standby state.
Remember to enable interrupts from the main application after initializing the TWI.
****************************************************************************/
void TWI_Master_Initialise(void)
{
	TWBR = TWI_TWBR;                        // Set bit rate register (Baudrate). Defined in header file.
	// TWSR = TWI_TWPS;                     // Not used. Driver presumes prescaler to be 00.
	TWDR = 0xFF;                            // Default content = SDA released.
	TWCR = (1<<TWEN)|						// Enable TWI-interface and release TWI pins.
	(0<<TWIE)|(0<<TWINT)|                   // Disable Interupt.
	(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|        // No Signal requests.
	(0<<TWWC);
}

/****************************************************************************
Call this function to test if the TWI_ISR is busy transmitting.
****************************************************************************/
unsigned char TWI_Transceiver_Busy( void )
{
	return ( TWCR & (1<<TWIE) );                  // IF TWI Interrupt is enabled then the Transceiver is busy
}

/****************************************************************************
Call this function to fetch the state information of the previous operation. The function will hold execution (loop)
until the TWI_ISR has completed with the previous operation. If there was an error, then the function
will return the TWI State code.
****************************************************************************/
unsigned char TWI_Get_State_Info( void )
{
	while ( TWI_Transceiver_Busy() );             // Wait until TWI has completed the transmission.
	return ( TWI_state );                         // Return error state.
}

/****************************************************************************
Call this function to send a prepared message. The first byte must contain the slave address and the
read/write bit. Consecutive bytes contain the data to be sent, or empty locations for data to be read
from the slave. Also include how many bytes that should be sent/read including the address byte.
The function will hold execution (loop) until the TWI_ISR has completed with the previous operation,
then initialize the next operation and return.
****************************************************************************/
void TWI_Start_Transceiver_With_Data( unsigned char *msg, unsigned char msgSize )
{
	unsigned char temp;

	while ( TWI_Transceiver_Busy() );             // Wait until TWI is ready for next transmission.

	TWI_msgSize = msgSize;                        // Number of data to transmit.
	TWI_buf[0]  = msg[0];                         // Store slave address with R/W setting.
	if (!( msg[0] & (TRUE<<TWI_READ_BIT) ))       // If it is a write operation, then also copy data.
	{
		for ( temp = 1; temp < msgSize; temp++ )
		TWI_buf[ temp ] = msg[ temp ];
	}
	TWI_statusReg.all = 0;
	TWI_state         = TWI_NO_STATE ;
	TWCR = (1<<TWEN)|                             // TWI Interface enabled.
	(1<<TWIE)|(1<<TWINT)|                  // Enable TWI Interupt and clear the flag.
	(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)|       // Initiate a START condition.
	(0<<TWWC);                             //
}

/****************************************************************************
Call this function to resend the last message. The driver will reuse the data previously put in the transceiver buffers.
The function will hold execution (loop) until the TWI_ISR has completed with the previous operation,
then initialize the next operation and return.
****************************************************************************/
void TWI_Start_Transceiver( void )
{
	while ( TWI_Transceiver_Busy() );             // Wait until TWI is ready for next transmission.
	TWI_statusReg.all = 0;
	TWI_state         = TWI_NO_STATE ;
	TWCR = (1<<TWEN)|                      // TWI Interface enabled.
	(1<<TWIE)|(1<<TWINT)|                  // Enable TWI Interupt and clear the flag.
	(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)|       // Initiate a START condition.
	(0<<TWWC);                             //
}

/****************************************************************************
Call this function to read out the requested data from the TWI transceiver buffer. I.e. first call
TWI_Start_Transceiver to send a request for data to the slave. Then Run this function to collect the
data when they have arrived. Include a pointer to where to place the data and the number of bytes
requested (including the address field) in the function call. The function will hold execution (loop)
until the TWI_ISR has completed with the previous operation, before reading out the data and returning.
If there was an error in the previous transmission the function will return the TWI error code.
****************************************************************************/
unsigned char TWI_Get_Data_From_Transceiver( unsigned char *msg, unsigned char msgSize )
{
	unsigned char i;

	while ( TWI_Transceiver_Busy() );             // Wait until TWI is ready for next transmission.

	if( TWI_statusReg.lastTransOK )               // Last transmission competed successfully.
	{
		for ( i=0; i<msgSize; i++ )                 // Copy data from Transceiver buffer.
		{
			msg[ i ] = TWI_buf[ i ];
		}
	}
	return( TWI_statusReg.lastTransOK );
}

// ********** Interrupt Handlers ********** //
/****************************************************************************
This function is the Interrupt Service Routine (ISR), and called when the TWI interrupt is triggered;
that is whenever a TWI event has occurred. This function should not be called directly from the main
application.
****************************************************************************/
//#pragma vector=TWI_vect
//__interrupt void TWI_ISR(void)
ISR(TWI_vect)
{
	static unsigned char TWI_bufPtr;

	switch (TWSR)
	{
		case TWI_START:             // START has been transmitted
		case TWI_REP_START:         // Repeated START has been transmitted
		TWI_bufPtr = 0;                                     // Set buffer pointer to the TWI Address location
		case TWI_MTX_ADR_ACK:       // SLA+W has been tramsmitted and ACK received
		case TWI_MTX_DATA_ACK:      // Data byte has been tramsmitted and ACK received
		if (TWI_bufPtr < TWI_msgSize)
		{
			TWDR = TWI_buf[TWI_bufPtr++];
			TWCR = (1<<TWEN)|                                 // TWI Interface enabled
			(1<<TWIE)|(1<<TWINT)|                      // Enable TWI Interupt and clear the flag to send byte
			(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           //
			(0<<TWWC);                                 //
		}else                    // Send STOP after last byte
		{
			TWI_statusReg.lastTransOK = TRUE;                 // Set status bits to completed successfully.
			TWCR = (1<<TWEN)|                                 // TWI Interface enabled
			(0<<TWIE)|(1<<TWINT)|                      // Disable TWI Interrupt and clear the flag
			(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|           // Initiate a STOP condition.
			(0<<TWWC);                                 //
		}
		break;
		case TWI_MRX_DATA_ACK:      // Data byte has been received and ACK tramsmitted
		TWI_buf[TWI_bufPtr++] = TWDR;
		case TWI_MRX_ADR_ACK:       // SLA+R has been tramsmitted and ACK received
		if (TWI_bufPtr < (TWI_msgSize-1) )                  // Detect the last byte to NACK it.
		{
			TWCR = (1<<TWEN)|                                 // TWI Interface enabled
			(1<<TWIE)|(1<<TWINT)|                      // Enable TWI Interupt and clear the flag to read next byte
			(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           // Send ACK after reception
			(0<<TWWC);                                 //
		}else                    // Send NACK after next reception
		{
			TWCR = (1<<TWEN)|                                 // TWI Interface enabled
			(1<<TWIE)|(1<<TWINT)|                      // Enable TWI Interupt and clear the flag to read next byte
			(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           // Send NACK after reception
			(0<<TWWC);                                 //
		}
		break;
		case TWI_MRX_DATA_NACK:     // Data byte has been received and NACK tramsmitted
		TWI_buf[TWI_bufPtr] = TWDR;
		TWI_statusReg.lastTransOK = TRUE;                 // Set status bits to completed successfully.
		TWCR = (1<<TWEN)|                                 // TWI Interface enabled
		(0<<TWIE)|(1<<TWINT)|                      // Disable TWI Interrupt and clear the flag
		(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|           // Initiate a STOP condition.
		(0<<TWWC);                                 //
		break;
		case TWI_ARB_LOST:          // Arbitration lost
		TWCR = (1<<TWEN)|                                 // TWI Interface enabled
		(1<<TWIE)|(1<<TWINT)|                      // Enable TWI Interupt and clear the flag
		(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)|           // Initiate a (RE)START condition.
		(0<<TWWC);                                 //
		break;
		case TWI_MTX_ADR_NACK:      // SLA+W has been tramsmitted and NACK received
		case TWI_MRX_ADR_NACK:      // SLA+R has been tramsmitted and NACK received
		case TWI_MTX_DATA_NACK:     // Data byte has been tramsmitted and NACK received
		//    case TWI_NO_STATE              // No relevant state information available; TWINT = “0”
		case TWI_BUS_ERROR:         // Bus error due to an illegal START or STOP condition
		default:
		TWI_state = TWSR;                                 // Store TWSR and automatically sets clears noErrors bit.
		// Reset TWI Interface
		TWCR = (1<<TWEN)|                                 // Enable TWI-interface and release TWI pins
		(0<<TWIE)|(0<<TWINT)|                      // Disable Interupt
		(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           // No Signal requests
		(0<<TWWC);                                 //
	}
}
/*****************************************************************************
*
* main.c, constructed using examples found in the main file provided by Atmel
*
****************************************************************************/
#define F_CPU 16000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "TWI_Master.h"
#define TWI_GEN_CALL         0x00  // The General Call address is 0
// Sample TWI transmission commands
#define TWI_CMD_MASTER_WRITE 0x10
#define TWI_CMD_MASTER_READ  0x20
// Sample TWI transmission states, used in the main application.
#define SEND_DATA             0x01
#define REQUEST_DATA          0x02
#define READ_DATA_FROM_BUFFER 0x03

#define DS3231		      0x68 // address of RTC

unsigned char bcdToDec(unsigned char val){
	return((val / 16 * 10) + (val % 16));
}

unsigned char decToBcd(unsigned char val){
	return((val / 10 * 16) + (val % 10));
}

void readTime(unsigned char* buffer, unsigned char bufferSize){
	unsigned char messageBuf[2];

	// send request for 2 bytes
	messageBuf[0] = (DS3231 << TWI_ADR_BITS) | (TRUE << TWI_READ_BIT);	                // first byte: slave adr. and r/w bit.
	messageBuf[1] = 0;								        // second byte: pointer to address

	TWI_Start_Transceiver_With_Data(messageBuf, 2);						// send command to DS3231

	TWI_Get_Data_From_Transceiver(buffer, bufferSize);					// collect data, request 4 bytes [addr], s, m, h

}

int main( void ){

	DDRD  = 0xff;							//feedback/debug port
	PORTD = 0x0;

	TWI_Master_Initialise();					// initialize i2c

	sei();							        // enable all interrupts

	unsigned char readBuf[4]{};					// contains [addr], seconds, minutes, hour

	while(1){
		readTime(readBuf, 4);					// reads time from DS3231 into buffer
		PORTD = bcdToDec(readBuf[1] & 0x7f);	                // output data to Digital Reader
								        // masking out MSB bit and converting to decimal
		_delay_ms(2000);
	}
}

There is probably a better way to include code, but am unfamiliar with this editor.

This topic has a solution.

Last Edited: Wed. Dec 2, 2015 - 09:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You never tell the RTC which register to begin reading from. 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your reply.

 

In readTime() I set the 2nd byte of messageBuf to 0, which I thought was equivalent to telling the RTC to start reading from address 0x00. Is this not the case?

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

 

"Is this not the case?"

Nope. In an I2C read transaction, nothing will be sent to the slave beyond its I2C address (plus the read flag). To specify the register to begin reading from, you must perform an I2C write transaction, before performing a read transaction.

 

In other words, once an I2C Master has placed the slave address on the bus for a READ transaction, the MASTER is 'all ears', so to speak.

 

 

 

Last Edited: Wed. Dec 2, 2015 - 09:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You're absolutely right, it works now. I didn't realize I had to send two individual "messages". Thank you!

 

Here is the updated code if anybody should happen to stumble across this thread:

 

void readTime(unsigned char* buffer, unsigned char bufferSize){
	unsigned char messageBuf[2];
	
	// set pointer in RTC registers
	messageBuf[0] = (DS3231 << TWI_ADR_BITS) | (FALSE << TWI_READ_BIT);	// first byte: slave adr, write
	messageBuf[1] = 0;													// second byte: pointer to address

	TWI_Start_Transceiver_With_Data(messageBuf, 2);						// send command to DS3231
	
	// send request for 2 bytes (will return [address, seconds]
	messageBuf[0] = (DS3231 << TWI_ADR_BITS) | (TRUE << TWI_READ_BIT);	// first byte: slave adr, read
	TWI_Start_Transceiver_With_Data(messageBuf, 2);						// send command to DS3231
	
	TWI_Get_Data_From_Transceiver(buffer, bufferSize);					// collect data, request 4 bytes [addr], s, m, h

}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cooooool. Mark this one solved.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I feel like an idiot re-opening this, but I have another issue. When I request more than two bytes all the bytes after the 2nd one (which is seconds) are 0. According to the DS3231 datasheet it should update its register pointer after every ACK from the master, so I would believe that this should work. Can you spot any more problems with my code?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
messageBuf[0] = (DS3231 << TWI_ADR_BITS) | (TRUE << TWI_READ_BIT);	// first byte: slave adr, read
TWI_Start_Transceiver_With_Data(messageBuf, 2);	

This code only requests 1 byte

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When you're trying to read additional bytes, you're increasing the size of messageBuf from the 2 bytes shown in your code, right?

 

My code is radically different, but I definitely read the seconds through year data from the DS3231 back to back using the acknowledge to increment the register pointer in the RTC.    If nothing else, that confirms what you're intending to do with the DS3231 should work.  

Environment: Win 7 64-bit, Atmel Studio 7, Atmel AVRISPMKII

AVR Projects: Time display, X10 automation, matrix LEDs, Caller ID, Halloween props, Pyrotechnic (all hobby)

AVR devices: mostly ATMEGA328, ATMEGA2560, ATMEGA32, ATTINY2313, AT90S2313, AT90S8515

Other hobbies: Electronics, 3D printing, collective-pitch RC helicopters

Last Edited: Thu. Dec 3, 2015 - 11:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I increase the buffer size and request 4 bytes. 

 

I'll try to explain: Changing nothing but the amount of bytes I request and the size of buffer[], all bytes after seconds are zero. If I explicitly set the bytes at address 0x01, 0x02 etc to particular values, I get the same values back. I don't see why this should happen, as I am using the DS3231 with the backup battery and it should therefore not reset its registers. I hope this is an indication as to what is wrong and does not confuse you guys any further.. Obviously there is something wrong with how I request the bytes, but I cannot see what is wrong here. 

 

EDIT: Here is what the function looks like when requesting four bytes. setGlobalTime() simply updates a 7 segment array in order to display the time, which I know works trouble-free.

void Clock::getTime(){
		unsigned char messageBuf[2];
		unsigned char dataBuffer[4];
		unsigned char seconds, minutes, hour;
		
		// reset pointer to 00h
		messageBuf[0] = (DS3231 << TWI_ADR_BITS) | (FALSE << TWI_READ_BIT);	// first byte: slave adr, write
		messageBuf[1] = 0x00;												// second byte: pointer to address
		
		TWI_Start_Transceiver_With_Data(messageBuf, 2);						// send command to DS3231
		
		// send request for seconds:
		messageBuf[0] = (DS3231 << TWI_ADR_BITS) | (TRUE << TWI_READ_BIT);	// first byte: slave adr, read
		TWI_Start_Transceiver_With_Data(messageBuf, 1);						// send command to DS3231
		
		TWI_Get_Data_From_Transceiver(dataBuffer, 4);						// collect data, request 4 bytes [addr], s, m, h
		
		seconds = bcdToDec(dataBuffer[1] & 0x7f);
		minutes = bcdToDec(dataBuffer[2]);
		hour = bcdToDec(dataBuffer[3] & 0x3f);
		
		setGlobalTime(seconds, minutes, hour);	
}

 

Last Edited: Fri. Dec 4, 2015 - 03:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Don't you need to set the TWEA bit in the TWCR register at the start of the multiple byte read?  Isn't that the bit that tells the AVR TWI hardware to automatically send the acknowledge after a byte is read?

Environment: Win 7 64-bit, Atmel Studio 7, Atmel AVRISPMKII

AVR Projects: Time display, X10 automation, matrix LEDs, Caller ID, Halloween props, Pyrotechnic (all hobby)

AVR devices: mostly ATMEGA328, ATMEGA2560, ATMEGA32, ATTINY2313, AT90S2313, AT90S8515

Other hobbies: Electronics, 3D printing, collective-pitch RC helicopters

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

/****************************************************************************
Call this function to send a prepared message. The first byte must contain the slave address and the
read/write bit. Consecutive bytes contain the data to be sent, or empty locations for data to be read
from the slave. Also include how many bytes that should be sent/read including the address byte.
The function will hold execution (loop) until the TWI_ISR has completed with the previous operation,
then initialize the next operation and return.
****************************************************************************/
void TWI_Start_Transceiver_With_Data( unsigned char *msg, unsigned char msgSize )

Note that it says msgSize must indicate the number of "bytes to be sent/read including the address byte."

 

The actual transfer of data over the I2C bus is done by TW__Start_Transceiver_With_Data(). That function places the data (in this case seconds, minutes & etc) into its' own 'private' buffer (TWI_buf). Then, when you call TWI_Get_Data_From_Transceiver, the contents of the private buffer is copied to YOUR buffer.

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mikericetga wrote:

Note that it says msgSize must indicate the number of "bytes to be sent/read including the address byte."

 

 

Noted. All is working now, thanks guys.