Difference between revisions of "Arduino: realtime clock test"

From Luky-Wiki
Jump to: navigation, search
(Technical description)
(Source code)
Line 10: Line 10:
  
 
=== Source code ===
 
=== Source code ===
Here is source code of my test. Please note that this code is "dirty" and designed only for this test. There are several parts which can result in race condition or are creating additional load to CPU. For example there is no need to update whole date/time string each second.
+
Here is source code of my test. Please note that this code designed only for this test. There are several parts which can result in race condition or are creating additional load to CPU. For example there is no need to update whole date/time string each second.
 
<pre>
 
<pre>
 
#define F_CPU 16000000
 
#define F_CPU 16000000
Line 32: Line 32:
  
 
//                          012345678901234567890123456789
 
//                          012345678901234567890123456789
volatile uint8_t buf[30] = "2012-00-00 00:00:00       \r\n";
+
volatile uint8_t buf[30] = "2012-00-00 00:00:00         \r";
 
volatile uint8_t i;
 
volatile uint8_t i;
  
Line 38: Line 38:
 
         uint8_t tmp = UDR0;
 
         uint8_t tmp = UDR0;
  
         // set initial time
+
         if (tmp == 's') {
        time.month = 8;
+
                // set initial time
        time.day = 10;
+
                time.month = 8;
        time.hour = 23;
+
                time.day = 14;
        time.minute = 30;
+
                time.hour = 20;
        time.second = 0;
+
                time.minute = 0;
 +
                time.second = 0;
 +
        };
  
 
}
 
}
Line 97: Line 99:
 
void main (void) {
 
void main (void) {
 
         // setup serial port
 
         // setup serial port
 +
        // 9600, 8 bit, 1 stop, no parity, interupt handler on RX/TX
 
         UBRR0H = UBRRH_VALUE;
 
         UBRR0H = UBRRH_VALUE;
 
         UBRR0L = UBRRL_VALUE;
 
         UBRR0L = UBRRL_VALUE;
Line 102: Line 105:
 
         UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
 
         UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
  
         // setup realtime interupt
+
         // Timer1 top value (for autoreload)
         //ATOMIC_BLOCK(ATOMIC_FORCEON) {
+
         // Note: this is two byte operation
                OCR1A = 15624;
+
        //      it should be secured by atomic block
 +
        //      when accessing while interupts are enabled
 +
        OCR1A = 62500;
  
         //}
+
         // Time1, 1/256, autoreload, interupt on compare
         TCCR1B = _BV(CS12) | _BV(CS10) | _BV(WGM12);
+
         TCCR1B = _BV(CS12) | _BV(WGM12);
 
         TIMSK1 = _BV(OCIE1A);
 
         TIMSK1 = _BV(OCIE1A);
  
Line 133: Line 138:
 
</pre>
 
</pre>
 
I'll keep ruining this code for several days to see what will be difference between "atomic" time and "my" time.
 
I'll keep ruining this code for several days to see what will be difference between "atomic" time and "my" time.
 +
 
=== Result ===
 
=== Result ===

Revision as of 14:44, 14 August 2012

Description of test

In past I created programs only for PC like architecture. I think my knowledge of C language is almost on expert level. I also know assembler, internal details about microprocessing architecture (AVR) and details about ISP communication. Apparently I should have all required knowledge to program Arduino UNO board with Atmel microprocessor but it is first time for me. Therefore I created "small" program to test "real time" clock configuration and simple UART communication.

Technical description

  • Arduino UNO board contain 16MHz crystal. Timer1 is 16bit. Once configured to auto-reload at 62500 and take clock source via 1/256 pre-scaler I get interrupt exactly at one second time (16MHz / 256 = 62500 ticks per second, Timer1 is calculating from zero). Clock update routine is invoked via interrupt handler.
  • To see "current" time I configured UART. Data are send on each update.
  • Currently I don't know how long it will take to setup hardware and start "counting" time so i created small routine to set time. There is interrupt handler for received characters. Once this routine receive character "s" it reset time to predefined time in code.
  • Reset of device is indicated by rapid blinking "L" diode. On each update diode change state (e.g. from On to Off and vice versa).
  • I cut "reset-en" to ensure that microprocessor is not accidentally reset by connected computer. As I am programming code memory via ISP it is not required to successfully flash data. In future I am planing to use my own boot-loader with code update capabilities included in my code.
  • I changed prescaler after first test. In beginning i used /1024 but this value is so high for fine tuning. Changing top value by "1" (one) cause approximately 4 seconds difference per day.

Source code

Here is source code of my test. Please note that this code designed only for this test. There are several parts which can result in race condition or are creating additional load to CPU. For example there is no need to update whole date/time string each second.

#define F_CPU 16000000
#define BAUD 9600

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <avr/sleep.h>
#include <util/setbaud.h>
#include <util/atomic.h>
#include <util/delay.h>

volatile struct {
        uint8_t month;
        uint8_t day;
        uint8_t hour;
        uint8_t minute;
        uint8_t second;
} time;

//                          012345678901234567890123456789
volatile uint8_t buf[30] = "2012-00-00 00:00:00          \r";
volatile uint8_t i;

ISR(USART_RX_vect) {
        uint8_t tmp = UDR0;

        if (tmp == 's') {
                // set initial time
                time.month = 8;
                time.day = 14;
                time.hour = 20;
                time.minute = 0;
                time.second = 0;
        };

}

ISR(USART_TX_vect) {
        if(i < 30) {
                UDR0 = buf[i];
                i++;
        } else {
                i = 0;
        }
}

ISR(TIMER1_COMPA_vect) {

        time.second++;
        if (time.second > 59) {
                time.second = 0;
                time.minute++;
        if (time.minute > 59) {
                time.minute = 0;
                time.hour++;
        if (time.hour > 23) {
                time.hour = 0;
                time.day++;
        if (time.day > 31) {
                time.day = 1;
                time.month++;
        if (time.month > 12) {
                time.month = 1;
        }}}}};

        buf[17] = time.second / 10 + '0';
        buf[18] = time.second % 10 + '0';

        buf[14] = time.minute / 10 + '0';
        buf[15] = time.minute % 10 + '0';

        buf[11] = time.hour / 10 + '0';
        buf[12] = time.hour % 10 + '0';

        buf[8] = time.day / 10 + '0';
        buf[9] = time.day % 10 + '0';

        buf[5] = time.month / 10 + '0';
        buf[6] = time.month % 10 + '0';

        UDR0 = ' ';
        PORTB = ( time.second & 0x01 ) ? _BV(PORTB5) : 0 ;

}

void main (void) {
        // setup serial port
        // 9600, 8 bit, 1 stop, no parity, interupt handler on RX/TX
        UBRR0H = UBRRH_VALUE;
        UBRR0L = UBRRL_VALUE;
        UCSR0B = _BV(RXCIE0) | _BV(TXCIE0) | _BV(RXEN0) | _BV(TXEN0);
        UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);

        // Timer1 top value (for autoreload)
        // Note: this is two byte operation
        //       it should be secured by atomic block
        //       when accessing while interupts are enabled
        OCR1A = 62500;

        // Time1, 1/256, autoreload, interupt on compare
        TCCR1B = _BV(CS12) | _BV(WGM12);
        TIMSK1 = _BV(OCIE1A);

        //setup "L" led and blink to indicate startup
        DDRB = _BV(DDB5);
        {
          uint8_t i;
          for(i = 0; i < 10; i++){
                PORTB = _BV(PORTB5);
                _delay_ms ( 50 );
                PORTB = 0;
                _delay_ms ( 50 );
          }
        }

        // enable interupts
        sei();

        // send "start" character;
        UDR0= 's';

        // all done, wait for interupt
        for(;;) sleep_mode();
}

I'll keep ruining this code for several days to see what will be difference between "atomic" time and "my" time.

Result