RTC and mega324p

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

Hi all,

I recently purchased a max6901 rtc and a atmega324pv micro. Now the rtc has 3 wires (atleast 3 that I need) and I connected them to uart 2 of the microcontroller. I'm using uart2 as SPI. First I tried bit banging and it works!, but it's slow :(. So now I tried to initialize the uart in SPI mode all I get back is zero's. One thing I think it might be is because its one IO pin and not 2 (to connect to MISO and MOSI). By the way pin connections are:
IO - TXD1 (PD3)
CLK - XCK1 (PD4)
CS - PD5
I'm thinking that my data is actually coming back on the RXD1 line, I'm going to hook it up to an oscope tomorrow to verify, but is there a way to make the uart spi 3 wired mode? I did look at the document and it says 3 Three-wire Synchronous Data Transfer, but Im guessing they mean miso, mosi, xck. So I guess I really need 2 wire :? .

Heres my code:
Uart init:

	UBRR1 = 0;
	UCSR1C = 0xC3;	
	UCSR1B = (1<<RXEN1)|(1<<TXEN1);		UBRR1L = 0x2F;	
	UBRR1H = 0x2F>>8;

Uart xfer/recieve function:

unsigned char USART_Xfer_Receive(unsigned char data )
{
	while ( !( UCSR1A & (1<<UDRE1)) );	
	UDR1 = data;				
	while ( !(UCSR1A & (1<<RXC1)) );	
	return UDR1;				
}

Read, Write, and Clear RTC

unsigned char read_rtc()
{
	unsigned char in_byte=0;
	SETBIT(PORTD,CS_RTC);
	_delay_ms(25);
	in_byte = USART_Xfer_Receive(0x00);
	return in_byte;
}


// write to a register
void write_rtc(unsigned char data)
{
	SETBIT(PORTD,CS_RTC);	
        _delay_ms(25);
	USART_Xfer_Receive(data);
}

void clear_rtc()
{
	CLEARBIT(PORTD, CS_RTC);
	_delay_ms(2000);
}

And last buy not least my init RTC too see if everything works:

void init_rtc()
{
	clear_rtc();
	write_rtc(0x0F);
	write_rtc(0x00);
	clear_rtc();
	
	clear_rtc();
	write_rtc(0xBE);	//burst write
	write_rtc(0x81);	//set secs = 01
	write_rtc(0x01);	//set mins = 01
	write_rtc(0x00);	//set hours = 00 (24hr mode)
	write_rtc(0x01);	//set day = 1st
	write_rtc(0x01);	//set month = January (1st month)
	write_rtc(0x01);	//set day of week = Monday (Mon=1)
	write_rtc(0x08);	//set year = 08
	write_rtc(0x00);	//clear write-protect bit
	reset_rtc();
	write_rtc(0x92);	//write to century register
	write_rtc(0x20);	//set year to 20XX
	clear_rtc();

// testing
	clear_rtc();
	write_rtc(0xBF);	//burst read
	initSec = read_rtc() - 0x80;
	printf("\nsec= %x",initSec);
	initMin = read_rtc();
	printf("\nmin= %x", initMin);
	initHr = read_rtc();	
	printf("\nhr= %x", initHr);	
	initDay = read_rtc();
	printf("\nday= %x",initDay );			//read day
	read_rtc();			//read month	
	read_rtc();			//read day of week	
	read_rtc();			//read year
	read_rtc();			//read dummy reg
	clear_rtc();
	write_rtc(0x93);						//read to century register
	printf("\ncentury= %02x", read_rtc());	//read century
	clear_rtc();					
}

Please let me know if you see anything im doing wrong, or if im just thinking about this all wrong.

Thanks :cry:

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

The device doesn't have an SPI interface so I'm not sure how it would help to try using the SPI block in a AVR? I'd have thought that bit-bang was the way to go but I haven't a clue why that should be "slow"? It's an RTC after all so operates in the realms of seconds or possibly milliseconds but certainly not microseconds which is how long a bit banged transfer could take. If there was something "slow" in the operation of the program I'd suggest it was somewhere other than the actual byte transfer routines.

Cliff

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

bootloadernoob wrote:
First I tried bit banging and it works!, but it's slow :(.

Come on!

Even with bit-banging, reading or writing should be over, far away from the next second.
So there is absolutely no remarkable loss of CPU-Power.

SPI use separate data pins for every direction, but the RTC was bidirectional, thus it can not work.
Maybe you can attach the master output over a resistor (e.g. 4.7k), so the slave can override it, if he enable its output.

Peter

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

Oh maybe I am doing something wrong then.. Here is my big bang routines:

unsigned char read_rtc()
{
	unsigned char in_byte=0;
	char temp=0, i=0;
	DDRC &= 0xFB; // set IO_RTC as input
	SETBIT(PORTC,CS_RTC);	//set cs high to begin transmission
	_delay_ms(25);
	for(i=0; i<8; i++)
	{
		SETBIT(PORTC, CLK_RTC);
		_delay_us(25);

	    CLEARBIT(PORTC, CLK_RTC); //Toggle the clock
		_delay_us(25);

    	temp = (CHECKBIT(PINC,IO_RTC) >> 2); 
		temp &= 0x01;
		if(temp)
		{
			in_byte >>= 1;
			in_byte += 0x80;
		}
		else
		{
			in_byte >>= 1; 
		}	

	}
	return in_byte;
}


// write to a register
void write_rtc(unsigned char data)
{
	unsigned char i;
	DDRC |= 0x05; // set IO_RTC as output

	SETBIT(PORTC,CS_RTC);	//set cs high to begin transmission

	// send the data we're writing
	for(i=0; i<8; i++)
	{
	    if(data & 0x01){ SETBIT(PORTC,IO_RTC);} //Put bit on IO data bus
		else{CLEARBIT(PORTC,IO_RTC);}

	    CLEARBIT(PORTC, CLK_RTC);
		_delay_us(25);

	    SETBIT(PORTC, CLK_RTC); //Toggle the clock
		_delay_us(25);
		data >>= 1; //shift bits
	}
	DDRC &= 0xFB; // set IO_RTC as input
}

When I took out the delays it didn't work.., but those shouldn't slow it that much right?

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

WOWWOWOWOWOWOW, sorry guys, I had _delay_ms(2000) in my main, that slowed it. Its nice and fast now. Sorry for any inconvience :oops:

Thanks for all the help

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

Two things:

1) As it stands if I build the write_rtc() function for a F_CPU 1000000UL then a call to write_rtc() lasts 520 machine cycles - that's about 0.5ms on 1MHz - is that "slow"

2) but anyway where did your arbitrary 25 value for the _delay_us() calls come from anyway? If I look at the Maxim datasheet it says the device can operate with a 2MHz SCK at 5V (or 500KHz at 2V). So a clock pulse only needs (assuming 5V) to be 0.5us wide. Your code is setting it to orders of magnitude larger than this. I'm guessing _delay_us(1) would work in this case the routine drops to 184 cycles in the simulator.

Cliff

PS our posts crossed - glad you have it sorted - but I'd still consider whether 25us is the right delay

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

Oh ok, yea it was just a number I chose...I tried the 1us it worked! Ty again! :)

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

Quote:

Here is my big bang routines:

Hmm.. I thought bit-banging was done in asm. :| Well. maybe I've learned something new today. ;)

If you think education is expensive, try ignorance.

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

Quote:
Hmm.. I thought bit-banging was done in asm

Well ultimately bit-banging is done by AVR opcodes - what you used to generate those (Asm, C BASIC, Forth, Pascal, hand editing Intel .hex file with opcode bit patterns, etc.) makes no difference whatsoever.

As always, one point is that C is just a a souped up macro assembler. If you've ener used "macro" in an assembler to wrap up an if/then or a while/wend or commonly occuring routine then you were only one step away fom C anyway.