Advertisement
Guest User

rtc-pi

a guest
Dec 16th, 2013
630
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.51 KB | None | 0 0
  1.  
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <fcntl.h>
  6. #include <unistd.h>
  7. #include <time.h>
  8. #include <string.h>
  9. #include <errno.h>
  10. #include <sys/mman.h>
  11. #include <sys/time.h>
  12.                            
  13. #define GPIO_ADD    0x20200000L // physical address of I/O peripherals on the ARM processor
  14. #define GPIO_SEL1   1           // Offset of SEL register for GP17 & GP18 into GPIO bank  
  15. #define GPIO_SEL2   2           // Offset of SEL register for GP21 into GPIO bank  
  16. #define GPIO_SET    7           // Offset of PIN HIGH register into GPIO bank  
  17. #define GPIO_CLR    10          // Offset of PIN LOW register into GPIO bank  
  18. #define GPIO_INP    13          // Offset of PIN INPUT value register into GPIO bank  
  19. #define PAGE_SIZE   4096        
  20. #define BLOCK_SIZE  PAGE_SIZE
  21.  
  22. /* RTC Chip register definitions */
  23. #define SEC_WRITE    0x80
  24. #define MIN_WRITE    0x82
  25. #define HOUR_WRITE   0x84
  26. #define DATE_WRITE   0x86
  27. #define MONTH_WRITE  0x88
  28. #define YEAR_WRITE   0x8C
  29. #define SEC_READ     0x81
  30. #define MIN_READ     0x83
  31. #define HOUR_READ    0x85
  32. #define DATE_READ    0x87
  33. #define MONTH_READ   0x89
  34. #define YEAR_READ    0x8D
  35.  
  36.  
  37. int  mem_fd     = 0;
  38. char *gpio_mmap = NULL;
  39. char *gpio_ram  = NULL;
  40. volatile unsigned int *gpio = NULL;
  41.  
  42.  
  43. /* These 'defines' map the peripheral pin functions to our circuits DS1302 pins */
  44. /* See DS1302 datasheet REV: 110805, and Broadcom BCM2835-ARM-Peripherals.pdf 6/2/2012 */
  45. #define IO_INPUT    *(gpio+GPIO_SEL1) &= 0xF8FFFFFFL
  46. #define IO_OUTPUT   *(gpio+GPIO_SEL1) &= 0xF8FFFFFFL; *(gpio+GPIO_SEL1) |= 0x01000000L
  47. #define SCLK_OUTPUT *(gpio+GPIO_SEL2) &= 0xFFFFFFC7L; *(gpio+GPIO_SEL2) |= 0x00000008L
  48. #define CE_OUTPUT   *(gpio+GPIO_SEL1) &= 0xFF1FFFFFL; *(gpio+GPIO_SEL1) |= 0x00200000L
  49. #define IO_HIGH     *(gpio+GPIO_SET) = 0x00040000L
  50. #define IO_LOW      *(gpio+GPIO_CLR) = 0x00040000L
  51. #define SCLK_HIGH   *(gpio+GPIO_SET) = 0x00200000L
  52. #define SCLK_LOW    *(gpio+GPIO_CLR) = 0x00200000L
  53. #define CE_HIGH     *(gpio+GPIO_SET) = 0x00020000L  
  54. #define CE_LOW      *(gpio+GPIO_CLR) = 0x00020000L
  55. #define IO_LEVEL    *(gpio+GPIO_INP) & 0x00040000L
  56.  
  57.  
  58. void setup_io()
  59. {
  60.  
  61.    /* open /dev/mem to get acess to physical ram */
  62.    if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
  63.       printf("can't open /dev/mem. Did you run the program with administrator rights?\n");
  64.       exit (-1);
  65.    }
  66.  
  67.    /* Allocate a block of virtual RAM in our application's address space */
  68.    if ((gpio_ram = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
  69.       printf("allocation error \n");
  70.       exit (-1);
  71.    }
  72.  
  73.    /* Make sure the pointer is on 4K boundary */
  74.    if ((unsigned long)gpio_ram % PAGE_SIZE)
  75.      gpio_ram += PAGE_SIZE - ((unsigned long)gpio_ram % PAGE_SIZE);
  76.  
  77.    /* Now map the physical addresses of the peripheral control registers
  78.       into our address space */
  79.    gpio_mmap = (unsigned char *)mmap(
  80.       (caddr_t)gpio_ram,
  81.       BLOCK_SIZE,
  82.       PROT_READ|PROT_WRITE,
  83.       MAP_SHARED|MAP_FIXED,
  84.       mem_fd,
  85.       GPIO_ADD
  86.    );
  87.  
  88.    if ((long)gpio_mmap < 0) {
  89.       printf("unable to map the memory. Did you run the program with administrator rights?\n");
  90.       exit (-1);
  91.    }
  92.  
  93.    /* Always use a volatile pointer to hardware registers */
  94.    gpio = (volatile unsigned *)gpio_mmap;
  95.  
  96.    /* Now we have access to the hardware reigsters we can start twiddling I/O pins */
  97.  
  98.    /* Switch GPIO 0, 1 and 2 to output mode */
  99.    SCLK_OUTPUT;
  100.    IO_OUTPUT;
  101.    CE_OUTPUT;
  102.  
  103.    /* Set the SCLK, IO and CE pins to default (low) */
  104.    SCLK_LOW;
  105.    IO_LOW;
  106.    CE_LOW;
  107.  
  108.    /* Short delay to allow the I/O lines to settle. */
  109.    usleep(2);
  110. }
  111.  
  112.  
  113. unsigned char read_rtc( unsigned char add )
  114. {
  115.    unsigned char val;
  116.    int lp;
  117.  
  118.    val = add;
  119.  
  120.    /* Check LSB is set */
  121.    if ( !(add & 1 ) ) {
  122.       printf("Incorrect read address specified - LSB must be set.\n");
  123.       exit (-1);
  124.    }
  125.  
  126.    /* Check address range is valid */
  127.    if ( (add < 0x81) || (add > 0x91) ) {
  128.       printf("Incorrect read address specified - It must be in the range 0x81..0x91\n");
  129.       exit (-1);
  130.    }
  131.  
  132.    CE_HIGH;
  133.  
  134.    usleep(2);
  135.  
  136.    for (lp=0; lp<8; lp++) {
  137.       if (val & 1)
  138.          IO_HIGH;
  139.       else
  140.          IO_LOW;
  141.       val >>= 1;
  142.       usleep(2);
  143.       SCLK_HIGH;
  144.       usleep(2);
  145.       SCLK_LOW;
  146.       usleep(2);    
  147.    }
  148.  
  149.    IO_INPUT;
  150.  
  151.    for (lp=0; lp<8; lp++) {
  152.       usleep(2);
  153.       val >>= 1;
  154.       if (IO_LEVEL)
  155.          val |= 0x80;
  156.       else
  157.          val &= 0x7F;        
  158.       SCLK_HIGH;
  159.       usleep(2);
  160.       SCLK_LOW;
  161.       usleep(2);
  162.    }
  163.  
  164.    /* Set the I/O pin back to it's default, output low. */
  165.    IO_LOW;
  166.    IO_OUTPUT;
  167.  
  168.    /* Set the CE pin back to it's default, low */
  169.    CE_LOW;
  170.  
  171.    /* Short delay to allow the I/O lines to settle. */
  172.    usleep(2);    
  173.  
  174.    return val;
  175. }
  176.  
  177.  
  178. void write_rtc( unsigned char add, unsigned char val_to_write )
  179. {
  180.    unsigned char val;
  181.    int lp;
  182.  
  183.    /* Check LSB is clear */
  184.    if ( add & 1 ) {
  185.       printf("Incorrect write address specified - LSB must be cleared.\n");
  186.       exit (-1);
  187.    }
  188.  
  189.    /* Check address range is valid */
  190.    if ( (add < 0x80) || (add > 0x90) ) {
  191.       printf("Incorrect write address specified - It must be in the range 0x80..0x90\n");
  192.       exit (-1);
  193.    }
  194.  
  195.    CE_HIGH;
  196.  
  197.    usleep(2);
  198.  
  199.    val = add;
  200.  
  201.    for (lp=0; lp<8; lp++) {
  202.       if (val & 1)
  203.          IO_HIGH;
  204.       else
  205.          IO_LOW;
  206.       val >>= 1;
  207.       usleep(2);
  208.       SCLK_HIGH;
  209.       usleep(2);
  210.       SCLK_LOW;
  211.       usleep(2);    
  212.    }
  213.  
  214.    val = val_to_write;
  215.  
  216.    for (lp=0; lp<8; lp++) {
  217.       if (val & 1)
  218.          IO_HIGH;
  219.       else
  220.          IO_LOW;
  221.       val >>= 1;
  222.       usleep(2);
  223.       SCLK_HIGH;
  224.       usleep(2);
  225.       SCLK_LOW;
  226.       usleep(2);    
  227.    }
  228.  
  229.    /* Set the I/O pin back to it's default, output low. */
  230.    IO_LOW;
  231.  
  232.    /* Set the CE pin back to it's default, low */
  233.    CE_LOW;
  234.  
  235.    /* Short delay to allow the I/O lines to settle. */
  236.    usleep(2);    
  237. }
  238.  
  239.  
  240. int main(int argc, char **argv)
  241. {
  242.    int lp;
  243.    unsigned char val;
  244.    int year,month,day,hour,minute,second;
  245.    time_t epoch_time;
  246.    struct tm time_requested;
  247.    struct timeval time_setformat;
  248.    
  249.    /* Check that the program was called correctly */
  250.    if ( argc > 2 ) {
  251.       printf("Too many arguments specified.\nRun as:\nrtc-pi\nor\nrtc-pi CCYYMMDDHHMMSS\n");
  252.       exit (-1);
  253.    }
  254.  
  255.    /* Set up gpi pointer for direct register access */
  256.    setup_io();
  257.      
  258.    if ( argc == 2 ) {
  259.       /* If the number of arguments are two, that means the user enter a date & time. */
  260.       /* Read that value and write it to the RTC chip */
  261.  
  262.       sscanf(argv[1],"%4d%2d%2d%2d%2d%2d",&year,&month,&day,&hour,&minute,&second);
  263.      
  264.       /* Validate that the input date and time is basically sensible */
  265.       if ( (year < 2000) || (year > 2099) || (month < 1) || (month > 12) ||
  266.             (day < 1) || (day>31) || (hour < 0) || (hour > 23) || (minute < 0) ||
  267.             (minute > 59) || (second < 0) || (second > 59) ) {
  268.          printf("Incorrect date and time specified.\nRun as:\nrtc-pi\nor\nrtc-pi CCYYMMDDHHMMSS\n");
  269.          exit (-1);
  270.       }
  271.  
  272.       /* Got valid input - now write it to the RTC */
  273.       /* The RTC expects the values to be written in packed BCD format */
  274.       write_rtc(SEC_WRITE, ( (second/10) << 4) | ( second % 10) );
  275.       write_rtc(MIN_WRITE, ( (minute/10) << 4) | ( minute % 10) );
  276.       write_rtc(HOUR_WRITE, ( (hour/10) << 4) | ( hour % 10) );
  277.       write_rtc(DATE_WRITE, ( (day/10) << 4) | ( day % 10) );
  278.       write_rtc(MONTH_WRITE, ( (month/10) << 4) | ( month % 10) );
  279.       write_rtc(YEAR_WRITE, ( ((year-2000)/10) << 4) | (year % 10) );  
  280.  
  281.       /* Finally convert to it to EPOCH time, ie the number of seconds since January 1st 1970, and set the system time */
  282.       time_requested.tm_sec = second;
  283.       time_requested.tm_min = minute;
  284.       time_requested.tm_hour = hour;
  285.       time_requested.tm_mday = day;
  286.       time_requested.tm_mon = month-1;
  287.       time_requested.tm_year = year-1900;
  288.       time_requested.tm_wday = 0; /* not used */
  289.       time_requested.tm_yday = 0; /* not used */
  290.       time_requested.tm_isdst = -1; /* determine daylight saving time from the system */
  291.      
  292.       epoch_time = mktime(&time_requested);
  293.      
  294.       /* Now set the clock to this time */
  295.       time_setformat.tv_sec = epoch_time;
  296.       time_setformat.tv_usec = 0;
  297.  
  298.       lp = settimeofday(&time_setformat,NULL);
  299.  
  300.       /* Check that the change was successful */
  301.       if ( lp < 0 ) {  
  302.          printf("Unable to change the system time. Did you run the program as an administrator?\n");
  303.          printf("The operation returned the error message \"%s\"\n", strerror( errno ) );
  304.          exit (-1);
  305.       }
  306.      
  307.    } else {
  308.       /* The program was called without a date specified; therefore read the date and time from */
  309.       /* the RTC chip and set the system time to this */
  310.       second = read_rtc(SEC_READ);
  311.       minute = read_rtc(MIN_READ);
  312.       hour = read_rtc(HOUR_READ);
  313.       day = read_rtc(DATE_READ);
  314.       month = read_rtc(MONTH_READ);
  315.       year = read_rtc(YEAR_READ);  
  316.  
  317.       /* Finally convert to it to EPOCH time, ie the number of seconds since January 1st 1970, and set the system time */
  318.       /* Bearing in mind that the format of the time values in the RTC is packed BCD, hence the conversions */
  319.  
  320.       time_requested.tm_sec = (((second & 0x70) >> 4) * 10) + (second & 0x0F);
  321.       time_requested.tm_min = (((minute & 0x70) >> 4) * 10) + (minute & 0x0F);
  322.       time_requested.tm_hour = (((hour & 0x30) >> 4) * 10) + (hour & 0x0F);
  323.       time_requested.tm_mday = (((day & 0x30) >> 4) * 10) + (day & 0x0F);
  324.       time_requested.tm_mon = (((month & 0x10) >> 4) * 10) + (month & 0x0F) - 1;
  325.       time_requested.tm_year = (((year & 0xF0) >> 4) * 10) + (year & 0x0F) + 2000 - 1900;
  326.       time_requested.tm_wday = 0; /* not used */
  327.       time_requested.tm_yday = 0; /* not used */
  328.       time_requested.tm_isdst = -1; /* determine daylight saving time from the system */
  329.      
  330.       epoch_time = mktime(&time_requested);
  331.      
  332.       /* Now set the clock to this time */
  333.       time_setformat.tv_sec = epoch_time;
  334.       time_setformat.tv_usec = 0;
  335.  
  336.       lp = settimeofday(&time_setformat,NULL);
  337.  
  338.       /* Check that the change was successful */
  339.       if ( lp < 0 ) {  
  340.          printf("Unable to change the system time. Did you run the program as an administrator?\n");
  341.          printf("The operation returned the error message \"%s\"\n", strerror( errno ) );
  342.          exit (-1);
  343.       }
  344.    }
  345.  
  346.    return 0;
  347. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement