RTC with ATmega328P (ARDUINO board)

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

Hello everybody!

 

First of all, I'd like to say I'm using ARDUINO board but I don't  use ARDUINO IDE - I work with Atmel Studio 6.2 instead. That's why I'm posting here, not in ARDUINO subforum.

Yesterday I decided to make my first PCB. It is supposed to contain a RTC module (PCF8563), some battery holder and a few essential elements. I attach the schematics and board layout so you can confirm it's all ok. The PCB is very nice, only its borders are bad but it doesn't matter - all signals can go through, I checked as much as I could with my multimeter. I never worked with I2C communication (2wire in ATmega328p) before so I kept the datasheet open all the time while writing the program.

The code is shown below.

/*
	pcf8563p
*/
#define F_CPU 16000000UL

#include <util/delay.h>
#include <avr/io.h>
#include <stdio.h>

#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

#define LEDDDR DDRB
#define LEDPORT PORTB
#define LED 13

#define SLA_W 0xA2
#define SLA_R 0xA3
#define REG_SECONDS 0x02

volatile uint8_t seconds=0, minutes=0, hours=0, day=0, weekday=0, month=0, year=0;
#pragma region USART
void USART_init() {
	UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
	UBRR0L = (uint8_t)(BAUD_PRESCALLER);
	UCSR0B = (1<<RXEN0)|(1<<TXEN0);
	UCSR0C = ((1<<UCSZ00)|(1<<UCSZ01));
}
void USART_writeByte(unsigned char data) {
	while(!(UCSR0A & (1<<UDRE0)));
	UDR0 = data;
}
void USART_writeString(char* stringPtr) {
	while(*stringPtr != 0x00) {			//Here we check if there is still more chars to send, this is done checking the actual char and see if it is different from the null char
		USART_writeByte(*stringPtr);	//Using the simple send function we send one char at a time
		stringPtr++;					//We increment the pointer so we can read the next char
	}
}
#pragma endregion USART

#pragma region I2C
void TWI_init() {
	//set SCL to 400kHz
	TWSR = 0x00;
	TWBR = 0x0C;
	//enable TWI
	TWCR = (1<<TWEN);
}
void TWI_start() {
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	while(!(TWCR & (1<<TWINT)));
}
void TWI_stop() {
	TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}
void TWI_write(uint8_t data) {
	TWDR = data;
	TWCR = (1<<TWINT)|(1<<TWEN);
	while(!(TWCR & (1<<TWINT)));
}
uint8_t TWI_readACK()
{
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	while(!(TWCR & (1<<TWINT)));
	return TWDR;
}
uint8_t TWI_readNACK() {
	TWCR = (1<<TWINT)|(1<<TWEN);
	while((!TWCR & (1<<TWINT)));
	return TWDR;
}
uint8_t TWI_getStatus() {
	uint8_t status;
	//mask status
	status = TWSR & 0xF8;
	return status;
}
#pragma endregion I2C

#pragma region RTC
uint8_t RTC_toBCD(uint8_t number) {
	return (number/10*16 | (number%10));
}
uint8_t RTC_fromBCD(uint8_t number) {
	return (number/16*10 + (number%16));
}
void RTC_setTime() {
	TWI_start();		// start
	USART_writeString("RTC_setTime 1\n\r");
	TWI_write(SLA_W);	// send address, write command
	USART_writeString("RTC_setTime 2\n\r");
	TWI_write(REG_SECONDS);	// set address pointer to VL_seconds
	TWI_write(RTC_toBCD(0));	// seconds
	TWI_write(RTC_toBCD(21));	// minutes
	TWI_write(RTC_toBCD(2));	// hour
	TWI_write(RTC_toBCD(25));	// day in month
	TWI_write(RTC_toBCD(3));	// weekday
	TWI_write(RTC_toBCD(2));	// month
	TWI_write(RTC_toBCD(15));	// year
	TWI_stop();			// stop
}
void RTC_readTime() {
	TWI_start();		// start
	TWI_write(SLA_W);	// send address, read command
	TWI_write(REG_SECONDS);	// set address pointer to VL_seconds
	TWI_write(SLA_R);
	
	USART_writeString("RTC_readTime zaczynam czytac\n\r");
	
	seconds = TWI_readACK();
	minutes = TWI_readACK();
	hours = TWI_readACK();
	day = TWI_readACK();
	weekday = TWI_readACK();
	month = TWI_readACK();
	year = TWI_readNACK();
	TWI_stop();			// stop
}
#pragma endregion RTC

int main(void) {
	char usart_string[40];
	
	USART_init();
	USART_writeString("usart initialized\n\r");
	TWI_init();
	USART_writeString("twi initialized\n\r");
	RTC_setTime();
	
	LEDDDR |= (1 << LED);
	LEDPORT |= (1 << LED);
	
	USART_writeString("While loop ahead\n\r");
	while(1) {
		RTC_readTime();
		sprintf(usart_string, "%u:%u:%u, %u/.%u/.%u, %u\n\r", RTC_fromBCD(hours), RTC_fromBCD(minutes), RTC_fromBCD(seconds), RTC_fromBCD(day), RTC_fromBCD(month), RTC_fromBCD(year), RTC_fromBCD(weekday));
		USART_writeString(usart_string);
		LEDPORT ^= (1 << LED);
		_delay_ms(1000);
	}
}

 

The problem is my TWI_write function - my USART debugger (:D) always stops at RTC_setTime 1 text in RTC_setTime function. Never goes through the TWI_write(SLA_W) function, stops at its while loop, making it infinite. The other issue is that the RTC takes some time before responding for START signal (like 10-15 seconds, I don't think it's normal but I'm new to 2 wire communications).

 

Please help me, as I really don't know what's wrong, where to look for mistakes. To make the schematics I used RTC's datasheet, ATmega328p specification and I searched the Internet for similar projects. You all can see it's an easy projects with not many things that can go wrong. But still it's not working. I think we should assume that the PCB is OK (I used some PCBs and made one before - it was done in a professional way, not home made - so let's assume I know how a working PCB should look like) and look for problems in schematics and the code.

And yes, I soldered everything properly, although the RTC I bought did not have any sign pointing the first leg but I searched the Internet and found pictures of this module and comparing the writings on it I put it the right way (I think).

 

Greetings,

Daniel

 

PS:

The code will be split into a header file and a .cpp implementation but only after I make it work. So you don't need to point my little mess :D.

Attachment(s): 

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

Well, when you don't know if its hw or a sw problem, best to use one of known condition, ie.   Use a known good twi library to verify the hw works first, such as the arduino twi library.  Look for a sketch that will test your hardware first.  Once you know it works, then debug your home made twi functions.  

 

 

Jim

 

 

Keys to wealth:

Invest for cash flow, not capital gains!

Wealth is attracted, not chased! 

Income is proportional to how many you serve!

 

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

Ok, I will do that tomorrow, I need to go to sleep now. I would be really glad and thankful if someone could just look at the schematics and verify it. As soon as I get home after university tomorrow, I'll use arduino library to check the rtc. Thanks for the reply, Jim!

 

Daniel

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

Ok, I found the solution but (this may sound strange) I don't know what the problem is. I thought - maybe there is something wrong with power supply (cause I didn't connect battery ground to arduino board ground, I'm not an electronic engineer, I wasn't sure if I should have done so in schematics). I took the battery out and connected my pcb to arduino power supply (5V and GND) and the code I took from the Internet worked.

 

Let's sum it up. Battery was giving me something like 3V3 but the RTC itself was directly connected to arduino pins which operates on 5V. Both arduino and my pcb have own grounds. It doesn't work like that.

When I take the battery out and supply the pcb with 5V it all works.

I assume it's either ground problem or missunderstood logic level (caused by different supply voltage for pcb and arduino). I guess for those of you who know more about electronics it will be easy to point what I did wrong - please do it!

 

Daniel

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

It best to use the same voltage logic levels, or the level translation will really complicate your world.  Do a systems design first, will I use 3.3v logic or 5v logic,

don't try to mix until you have much more experience.

And when powering your circuits, you should use the same power supply, or tie the two grounds together so you have a common reference.    The reason for that, is the logic levels are high/low in reference to ground, if the two references (grounds) are left to float, or in other words, not connected together, then what is high/low referenced to which ground?   What is high to one may not be high to the other...

 

Hope that helps

 

Jim

 

Keys to wealth:

Invest for cash flow, not capital gains!

Wealth is attracted, not chased! 

Income is proportional to how many you serve!

 

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

A rtc module cannot be left without power supply, it's just useless and changing its Vcc to 5V is also a bad idea cause the battery will have to be physically bigger - and this module should be as small as possible. If I connect their grounds (arduino and rtc) together it will still be a problem because of different electrical characteristics for Input Low Voltage, Input High Voltage, right? So would adding a level shifter be the only good solution?

Last Edited: Fri. Feb 27, 2015 - 08:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I've not used this chip, or an Arduino board...

 

But Vdd (V+) for the RTC is 1.8 V to 5.5V.

I think your Arduino PCB is running at 5V.

 

So, I would connect both the Arduino's +5V and the back up battery's +3V to the RTC's V+, each through a small schottky diode.

 

When the Arduino has power, the diode to the battery will be reverse biased, and the RTC will run from the Arduino.

When the Arduino is powered down, the Battery will kick in, and it won't back power the Arduino, because of the Arduino's diode.

 

You can tolerate the voltage drop of the diode  in each supply leg as the Vdd is down to 1.8 V

 

The RTC, Arduino, and the backup battery all must share a common ground.

 

JC

 

 

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

Aranha,

 

I recognise this from the Arduino "world". Why are you using it?

#define LED 13

 

... and yes all Gnd points must be interconnected.

 

Cheers,

 

Ross

 

Ross McKenzie ValuSoft Melbourne Australia

Last Edited: Fri. Feb 27, 2015 - 10:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The battery + should go to pin 7 vback not to VCC. No need for diodes as the chip does the job.

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

@Ross

Sorry, I don't understand why I shouldn't be using preprocessor directive 'define'. It's not from arduino world.

 

@Kartman

Unfortunatelly the pin named 'VBACK' is actually a CLKOUT and generates square signal with adjustable frequency. So it's an output pin, not a supply pin.

 

@JC

Thank you very much for your help!

 

Thank you all for the help, I think the discussion might be finished, I know everything I wanted to know. Have a great weekend!

 

Daniel

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

#define LED 13 pin 13 would be an Arduino creation.
According to the x1205 datasheet it is vback.

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

Oh yes, sure, I'm sorry for garbage in the code.

I used that rtc module in schematics because I couldn't find PCF8563 and I only needed something in so8 package. So it's not x1205 but, as I wrote at the beginning of this discussion, it's PCF8563. Maybe I should have emphasized it better. Sorry!