Demo the function of RTC module AM1805

Dependencies:   mbed-dev

Fork of I2C_HelloWorld_Mbed by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AM1805.cpp Source File

AM1805.cpp

00001 /* AM1805 Sample code: external RTC module is used by host MCU */
00002 
00003 #include "mbed.h"
00004 #include "AM1805.h"
00005 
00006 #define I2C_SDA p28
00007 #define I2C_SCL p27
00008 #define AM1805_I2C_ADDRESS 0xD2
00009 /* Register Map */
00010 #define AM1805_REG_HUNDREDTHS   0x00
00011 #define AM1805_REG_ALM_HUN      0x08
00012 #define AM1805_REG_STATUS       0x0F
00013 #define AM1805_REG_CTRL1        0x10
00014 #define AM1805_REG_CTRL2        0x11
00015 #define AM1805_REG_INTMASK      0x12
00016 #define AM1805_REG_SLEEPCTRL    0x17
00017 #define AM1805_REG_TIM_CTRL     0x18
00018 #define AM1805_REG_CDTIM        0x19
00019 #define AM1805_REG_TIMINIT      0x1A
00020 #define AM1805_REG_WDT          0x1B
00021 #define AM1805_REG_OSCSTATUS    0x1D
00022 #define AM1805_REG_ID0          0x28
00023 #define AM1805_REG_EXTADDR_REG  0x3F
00024 /* Register Value */
00025 #define AM1805_VALUE_ID0 0x18
00026 
00027 #define AM1805_DEBUG 0
00028 
00029 I2C i2c(I2C_SDA, I2C_SCL);
00030 #if AM1805_DEBUG
00031 Serial pc(p13,p14);
00032 #endif
00033 
00034 static uint8_t get_extension_address(uint8_t address)
00035 {
00036     uint8_t xadd;
00037     char temp;
00038 
00039     am1805_register_read(AM1805_REG_EXTADDR_REG, &temp, 1);
00040     temp = temp & 0xC0;
00041 
00042     if (address < 64) { xadd = 0x8; }
00043     else if (address < 128) { xadd = 0x9; }
00044     else if (address < 192) { xadd = 0xA; }
00045     else { xadd = 0xB; }
00046     return (xadd | temp);
00047 }
00048 
00049 /* Set one or more bits in the selected register, selected by 1's in the mask */
00050 static void setreg(char address, uint8_t mask)
00051 {
00052     char temp;
00053 
00054     am1805_register_read(address, &temp, 1);
00055     temp |= mask;
00056     am1805_register_write(address, temp);
00057 }
00058 
00059 /* Clear one or more bits in the selected register, selected by 1's in the mask */
00060 static void clrreg(char address, uint8_t mask)
00061 {
00062     char temp;
00063     
00064     am1805_register_read(address, &temp, 1);
00065     temp &= ~mask;
00066     am1805_register_write(address, temp);
00067 }
00068 
00069 static bool am1805_verify_product_id(void)
00070 {
00071     char who_am_i[1];
00072     am1805_register_read(AM1805_REG_ID0, &who_am_i[0], 1);    
00073 #if AM1805_DEBUG    
00074     pc.printf("ID:%x\r\n",who_am_i[0]);
00075 #endif    
00076     if (who_am_i[0] != AM1805_VALUE_ID0) 
00077         return false;
00078     else 
00079         return true;
00080 }
00081 
00082 bool am1805_init(void)
00083 {   
00084   bool transfer_succeeded = false;
00085 
00086   i2c.frequency(400000);
00087        
00088   /* Read and verify product ID */
00089   transfer_succeeded = am1805_verify_product_id();
00090 
00091   return transfer_succeeded;
00092 }
00093 
00094 void am1805_register_read(char register_address, char *destination, uint8_t number_of_bytes)
00095 {
00096   i2c.write(AM1805_I2C_ADDRESS, &register_address, 1, 1);
00097   i2c.read(AM1805_I2C_ADDRESS, destination, number_of_bytes);    
00098 }
00099 
00100 void am1805_register_write(char register_address, uint8_t value)
00101 {   
00102     char tx_data[2];
00103     
00104     tx_data[0] = register_address;
00105     tx_data[1] = value;
00106     i2c.write(AM1805_I2C_ADDRESS, tx_data, 2);      
00107 
00108 }
00109 
00110 void am1805_burst_write(uint8_t *tx_data, uint8_t number_of_bytes)
00111 {
00112     i2c.write(AM1805_I2C_ADDRESS, (char *)tx_data, number_of_bytes);
00113 }
00114 
00115 void am1805_config_input_interrupt(input_interrupt_t index_Interrupt)
00116 {
00117     switch(index_Interrupt) {
00118         case XT1_INTERRUPT:
00119             /* Set input interrupt pin EX1T */
00120             clrreg(AM1805_REG_STATUS,0x01);             // Clear EX1
00121             setreg(AM1805_REG_INTMASK,0x01);            // Set EX1E    
00122             break;
00123         case XT2_INTERRUPT:
00124             /* Set input interrupt pin WDI */
00125             clrreg(AM1805_REG_STATUS,0x02);             // Clear EX2
00126             setreg(AM1805_REG_INTMASK,0x02);            // Set EX2E       
00127             break;
00128         default:
00129 #if AM1805_DEBUG    
00130             pc.printf("Wrong Input Interrupt Index\r\n");
00131 #endif         
00132             break;        
00133     }
00134 }
00135 
00136 
00137 // Read a byte from local RAM
00138 uint8_t am1805_read_ram(uint8_t address)
00139 {
00140     uint8_t xadd;
00141     char temp;
00142     uint8_t reg_ram = 0;
00143 
00144     xadd = get_extension_address(address);                  // Calc XADDR value from address
00145     am1805_register_write(AM1805_REG_EXTADDR_REG, xadd);    // Load the XADDR register
00146     reg_ram = (address & 0x3F) | 0x40;                      // Read the data
00147     am1805_register_read(reg_ram, &temp, 1);
00148 #if AM1805_DEBUG  
00149     pc.printf("Read from addr:%x Data:%x\r\n",address,temp);
00150 #endif    
00151     return (uint8_t)temp;                
00152 }
00153 
00154 // Write a byte to local RAM
00155 void am1805_write_ram(uint8_t address, uint8_t data)
00156 {
00157     uint8_t xadd;
00158     uint8_t reg_ram = 0;
00159 
00160     xadd = get_extension_address(address);                  // Calc XADDR value from address
00161     am1805_register_write(AM1805_REG_EXTADDR_REG, xadd);    // Load the XADDR register
00162     reg_ram = (address & 0x3F) | 0x40;  
00163     am1805_register_write(reg_ram, data);                   // Write the data
00164 }
00165 
00166 /*
00167  * hundredth : 0 ~ 99
00168  * second : 0 ~ 59
00169  * minute : 0 ~ 59
00170  * weekday : 0 ~ 6
00171  * month : 1 ~ 12
00172  * year : 0 ~ 99
00173  * mode : 0 ~ 2
00174  */
00175 void am1805_set_time(time_reg_struct_t time_regs)
00176 {
00177     char temp;
00178     uint8_t temp_buff[9];
00179 
00180     /* 
00181      * Determine whether 12 or 24-hour timekeeping mode is being used
00182      * and set the 1224 bit appropriately
00183      */
00184     if (time_regs.mode == 2)        // 24-hour day
00185     {
00186         clrreg(AM1805_REG_CTRL1, 0x40);
00187     }
00188     else if (time_regs.mode == 1)   // 12-hour day PM
00189     {
00190         time_regs.hour |= 0x20;     // Set AM/PM
00191         setreg(AM1805_REG_CTRL1, 0x40);
00192     }
00193     else                            // 12-hour day AM
00194     {
00195         setreg(AM1805_REG_CTRL1, 0x40);
00196     }
00197 
00198     /* Set the WRTC bit to enable counter writes. */
00199     setreg(AM1805_REG_CTRL1, 0x01);
00200 
00201     /* Set the correct century */
00202     if (time_regs.century == 0)
00203     {
00204         clrreg(AM1805_REG_STATUS, 0x80);
00205     }
00206     else
00207     {
00208         setreg(AM1805_REG_STATUS, 0x80);
00209     }
00210 
00211     /* Write all of the time counters */
00212     temp_buff[0] = AM1805_REG_HUNDREDTHS;
00213     temp_buff[1] = time_regs.hundredth;
00214     temp_buff[2] = time_regs.second;
00215     temp_buff[3] = time_regs.minute;
00216     temp_buff[4] = time_regs.hour;
00217     temp_buff[5] = time_regs.date;
00218     temp_buff[6] = time_regs.month;
00219     temp_buff[7] = time_regs.year;
00220     temp_buff[8] = time_regs.weekday;
00221 
00222     /* Write the values to the AM18XX */
00223     am1805_burst_write(temp_buff, sizeof(temp_buff));
00224 
00225     /* Load the final value of the WRTC bit based on the value of protect */
00226     am1805_register_read(AM1805_REG_CTRL1, &temp, 1);
00227     temp &= 0x7E;                   // Clear the WRTC bit and the STOP bit
00228     //temp_buff[1] |= (0x01 & (~protect));    // Invert the protect bit and update WRTC
00229     am1805_register_write(AM1805_REG_CTRL1, temp);
00230        
00231     return;    
00232 }
00233 
00234 void am1805_get_time(time_reg_struct_t *time_regs)
00235 {
00236     char temp_buff[8];
00237     char time_mode;
00238 
00239     /* Read the counters. */
00240     am1805_register_read(AM1805_REG_HUNDREDTHS, temp_buff, 8);
00241 
00242     time_regs->hundredth = temp_buff[0];
00243     time_regs->second = temp_buff[1];
00244     time_regs->minute = temp_buff[2];
00245     time_regs->hour = temp_buff[3];
00246     time_regs->date = temp_buff[4];
00247     time_regs->month = temp_buff[5];
00248     time_regs->year = temp_buff[6];
00249     time_regs->weekday = temp_buff[7];
00250 
00251     /* Get the current hours format mode 12:24 */
00252     am1805_register_read(AM1805_REG_CTRL1, &time_mode, 1);
00253     if ((time_mode & 0x40) == 0)
00254     {
00255         /* 24-hour mode. */
00256         time_regs->mode = 2;
00257         time_regs->hour = time_regs->hour & 0x3F;           // Get tens:ones
00258     }
00259     else
00260     {
00261         /* 12-hour mode.  Get PM:AM. */
00262         time_regs->mode = (time_regs->hour & 0x20) ? 1 : 0;  // PM : AM
00263         time_regs->hour &= 0x1F;                            // Get tens:ones
00264     }
00265 
00266     time_regs->hundredth = temp_buff[0];
00267     time_regs->second = temp_buff[1];
00268     time_regs->minute = temp_buff[2];
00269     time_regs->hour = temp_buff[3];
00270     time_regs->date = temp_buff[4];
00271     time_regs->month = temp_buff[5];
00272     time_regs->year = temp_buff[6];
00273     time_regs->weekday = temp_buff[7];
00274 
00275 #if AM1805_DEBUG 
00276     pc.printf("hundredth:%x\r\n",time_regs->hundredth);
00277     pc.printf("second:%x\r\n",time_regs->second);
00278     pc.printf("minute:%x\r\n",time_regs->minute);
00279     pc.printf("hour:%x\r\n",time_regs->hour);
00280     pc.printf("date:%x\r\n",time_regs->date);
00281     pc.printf("month:%x\r\n",time_regs->month);
00282     pc.printf("year:%x\r\n",time_regs->year);
00283     pc.printf("weekday:%x\r\n",time_regs->weekday);
00284 #endif     
00285 }
00286 
00287 void am1805_config_alarm(time_reg_struct_t time_regs, alarm_repeat_t repeat, interrupt_mode_t intmode, interrupt_pin_t pin)
00288 { 
00289     char temp;
00290     uint8_t temp_buff[9];
00291 
00292     /* Determine whether a 12-hour or a 24-hour time keeping mode is being used */
00293     if (time_regs.mode == 1)
00294     {
00295         /* A 12-hour day PM */
00296         time_regs.hour = time_regs.hour | 0x20;   // Set AM/PM
00297     }
00298 
00299     /* Write all of the time counters */
00300     temp_buff[0] = AM1805_REG_ALM_HUN;
00301     temp_buff[1] = time_regs.hundredth;
00302     temp_buff[2] = time_regs.second;
00303     temp_buff[3] = time_regs.minute;
00304     temp_buff[4] = time_regs.hour;
00305     temp_buff[5] = time_regs.date;
00306     temp_buff[6] = time_regs.month;
00307     temp_buff[7] = time_regs.weekday;
00308 
00309     clrreg(AM1805_REG_TIM_CTRL, 0x1C);      // Clear the RPT field
00310     clrreg(AM1805_REG_INTMASK, 0x64);       // Clear the AIE bit and IM field
00311     clrreg(AM1805_REG_STATUS, 0x04);        // Clear the ALM flag
00312 
00313     if (pin == PIN_FOUT_nIRQ)
00314     {
00315         /* Interrupt on FOUT/nIRQ */
00316         am1805_register_read(AM1805_REG_CTRL2, &temp, 1);   // Get the Control2 Register       
00317         temp = (temp & 0x03);               // Extract the OUT1S field        
00318         if (temp != 0)                      // Not already selecting nIRQ
00319         {
00320             setreg(AM1805_REG_CTRL2, 0x03);    // Set OUT1S to 3           
00321         }        
00322     }
00323     if (pin == PIN_PSW_nIRQ2)
00324     {
00325         /* Interrupt on PSW/nIRQ2 */
00326         am1805_register_read(AM1805_REG_CTRL2, &temp, 1);   // Get the Control2 Register
00327         temp &= 0x1C;                       // Extract the OUT2S field
00328         if (temp != 0)                      // Not already selecting nIRQ
00329         {
00330             clrreg(AM1805_REG_CTRL2, 0x1C);    // Clear OUT2S
00331             setreg(AM1805_REG_CTRL2, 0x0C);    // Set OUT2S to 3
00332         }
00333     }
00334 
00335     if (repeat == ONCE_PER_10TH_SEC)
00336     {
00337         /* 10ths interrupt */
00338         temp_buff[1] |= 0xF0;
00339         repeat = ONCE_PER_SECOND;                   // Select correct RPT value
00340     }
00341     if (repeat == ONCE_PER_100TH_SEC)
00342     {
00343         /* 100ths interrupt */
00344         temp_buff[1] = 0xFF;
00345         repeat = ONCE_PER_SECOND;                   // Select correct RPT value
00346     }
00347     if (repeat != 0)                                // Don't initiate if repeat = 0
00348     {
00349         temp = (repeat << 2);                       // Set the RPT field to the value of repeat
00350         setreg(AM1805_REG_TIM_CTRL, temp);          // Was previously cleared
00351         setreg(AM1805_REG_INTMASK, (intmode << 5)); // Set the alarm interrupt mode
00352         setreg(AM1805_REG_INTMASK, 0x60); // Set the alarm interrupt mode
00353         am1805_burst_write(temp_buff, 8);           // Execute the burst write
00354         setreg(AM1805_REG_INTMASK, 0x04);           // Set the AIE bit        
00355     }
00356     else
00357         setreg(AM1805_REG_INTMASK, 0x60);           // Set IM field to 0x3 (reset value) to minimize current draw
00358     
00359     return;
00360 }
00361 
00362 void am1805_config_countdown_timer(count_down_range_t range, int32_t period, count_down_repeat_t repeat, interrupt_pin_t pin)
00363 {
00364     uint8_t tm;
00365     uint8_t trpt;
00366     uint8_t tfs;
00367     uint8_t te;
00368     char temp;
00369     char tctrl;
00370     int32_t timer;
00371     char oscmode; 
00372 
00373     /* 0 = XT, 1 = RC */
00374     am1805_register_read(AM1805_REG_OSCSTATUS, &oscmode, 1);   
00375     oscmode = (oscmode & 0x10) ? 1 : 0;
00376     
00377     /* disable count down timer */
00378     if (pin == INTERNAL_FLAG)
00379     {
00380         te = 0;
00381     }
00382     else
00383     {
00384         te = 1;
00385         if (repeat == SINGLE_LEVEL_INTERRUPT)
00386         {
00387             /* Level interrupt */
00388             tm = 1;                                     // Level
00389             trpt = 0;                                   // No repeat
00390             if (range == PERIOD_US)
00391             {
00392                 /* Microseconds */
00393                 if (oscmode == 0)
00394                 {
00395                     /* XT Mode */
00396                     if (period <= 62500)                // Use 4K Hz
00397                     {
00398                         tfs = 0;
00399                         timer = (period * 4096);
00400                         timer = timer / 1000000;
00401                         timer = timer - 1;
00402                     }
00403                     else if (period <= 16384000)        // Use 64 Hz
00404                     {
00405                         tfs = 1;
00406                         timer = (period * 64);
00407                         timer /= 1000000;
00408                         timer = timer - 1;
00409                     }
00410                     else                                // Use 1 Hz
00411                     {
00412                         tfs = 2;
00413                         timer = period / 1000000;
00414                         timer = timer - 1;
00415                     }
00416                 }
00417                 else
00418                 {
00419                     /* RC Mode */
00420                     if (period <= 2000000) {            // Use 128 Hz
00421                         tfs = 0;
00422                         timer = (period * 128);
00423                         timer /= 1000000;
00424                         timer = timer - 1;
00425                     }
00426                     else if (period <= 4000000) {       // Use 64 Hz
00427                         tfs = 1;
00428                         timer = (period * 64);
00429                         timer /= 1000000;
00430                         timer = timer - 1;
00431                     }
00432                     else {                              // Use 1 Hz
00433                         tfs = 2;
00434                         timer = period / 1000000;
00435                         timer = timer - 1;
00436                     }
00437                 }
00438             }
00439             else
00440             {
00441                 /* Seconds */
00442                 if (period <= 256)
00443                 {
00444                     /* Use 1 Hz */
00445                     tfs = 2;
00446                     timer = period - 1;
00447                 }
00448                 else
00449                 {
00450                     /* Use 1/60 Hz */
00451                     tfs = 3;
00452                     timer = period / 60;
00453                     timer = timer - 1;
00454                 }
00455             }
00456         }
00457         else
00458         {
00459             /* Pulse interrupts */
00460             tm = 0;                 // Pulse
00461             trpt = repeat & 0x01;   // Set up repeat
00462             if (repeat < REPEAT_PLUSE_1_128_SEC)
00463             {
00464                 tfs = 0;
00465                 if (oscmode == 0)
00466                 {
00467                         timer = (period * 4096);
00468                         timer /= 1000000;
00469                         timer = timer - 1;
00470                 }
00471                 else
00472                 {
00473                         timer = (period * 128);
00474                         timer /= 1000000;
00475                         timer = timer - 1;
00476                 }
00477             }
00478             else if (repeat < REPEAT_PLUSE_1_64_SEC)
00479             {
00480                 tfs = 1;
00481                 timer = (period * 128);
00482                 timer /= 1000000;
00483                 timer = timer - 1;
00484             }
00485             else if (period <= 256)
00486             {
00487                 /* Use 1 Hz */
00488                 tfs = 2;
00489                 timer = period - 1;
00490             }
00491             else
00492             {
00493                 /* Use 1/60 Hz */
00494                 tfs = 3;
00495                 timer = period / 60;
00496                 timer = timer - 1;
00497             }
00498         }
00499     }
00500     
00501     am1805_register_read(AM1805_REG_TIM_CTRL, &tctrl, 1);               // Get TCTRL, keep RPT, clear TE
00502     tctrl = tctrl & 0x1C;
00503     am1805_register_write(AM1805_REG_TIM_CTRL, tctrl);
00504 
00505     tctrl = tctrl | (te * 0x80) | (tm * 0x40) | (trpt * 0x20) | tfs;    // Merge the fields
00506     
00507     if (pin == PIN_FOUT_nIRQ)                                           // generate nTIRQ interrupt on FOUT/nIRQ (asserted low)
00508     {
00509          clrreg(AM1805_REG_CTRL2, 0x3);                                 // Clear OUT1S
00510     }
00511     if (pin == PIN_PSW_nIRQ2)                                           // generate nTIRQ interrupt on PSW/nIRQ2 (asserted low)
00512     {
00513          am1805_register_read(AM1805_REG_CTRL2, &temp, 1);              // Get OUT2S
00514          if ((temp & 0x1C) != 0)
00515          {
00516              temp = (temp & 0xE3) | 0x14;                               // If OUT2S != 0, set OUT2S to 5
00517          }
00518          am1805_register_write(AM1805_REG_CTRL2, temp);                 // Write back
00519     }
00520     if (pin != 0)
00521     {
00522         clrreg(AM1805_REG_STATUS,0x08);                     // Clear TIM
00523         setreg(AM1805_REG_INTMASK,0x08);                    // Set TIE
00524         am1805_register_write(AM1805_REG_CDTIM, timer);     // Initialize the timer
00525         am1805_register_write(AM1805_REG_TIMINIT, timer);   // Initialize the timer repeat
00526         am1805_register_write(AM1805_REG_TIM_CTRL, tctrl);  // Start the timer        
00527     }
00528     
00529     return ;    
00530 }
00531 
00532 /** Parameter:
00533  *  timeout - minimum timeout period in 7.8 ms periods (0 to 7)
00534  *  mode - sleep mode (nRST modes not available in AM08xx)
00535  *      0 => nRST is pulled low in sleep mode
00536  *      1 => PSW/nIRQ2 is pulled high on a sleep
00537  *      2 => nRST pulled low and PSW/nIRQ2 pulled high on sleep
00538  *  error ?returned value of the attempted sleep command
00539  *      0 => sleep request accepted, sleep mode will be initiated in timeout seconds
00540  *      1 => illegal input values
00541  *      2 => sleep request declined, interrupt is currently pending
00542  *      3 => sleep request declined, no sleep trigger interrupt enabled
00543 **/
00544 void am1805_set_sleep(uint8_t timeout, uint8_t mode)
00545 {
00546     uint8_t slres = 0;
00547     char temp = 0;
00548 
00549 #if AM1805_DEBUG    
00550     am1805_register_read(AM1805_REG_CTRL2, &temp, 1);       // Get SLST bit (temp & 0x08)
00551     
00552     if ( ( temp & 0x08 ) == 0)
00553     {
00554         pc.printf("Previous Sleep Failed\r\n");
00555     } else {
00556         pc.printf("Previous Sleep Successful\r\n");    
00557     }
00558     clrreg(AM1805_REG_CTRL2,0x08);                     // Clear SLST
00559     
00560     am1805_register_read(AM1805_REG_CTRL2, &temp, 1);       // Get SLST bit (temp & 0x08)
00561     
00562     if ( ( temp & 0x08 ) == 0)
00563     {
00564         pc.printf("Clear Succ\r\n");
00565     } else {
00566         pc.printf("Clear Fail\r\n");    
00567     }
00568     clrreg(AM1805_REG_CTRL2,0x08);                     // Clear SLST   
00569 #endif
00570  
00571     if (mode > 0)
00572     {
00573         /* Sleep to PSW/nIRQ2 */
00574         am1805_register_read(AM1805_REG_CTRL2, &temp, 1);   // Read OUT2S
00575         temp = (temp & 0xE3) | 0x18;                        // MUST NOT WRITE OUT2S WITH 000
00576         am1805_register_write(AM1805_REG_CTRL2, temp);      // Write value to OUT2S
00577         slres = 0;
00578     } 
00579     
00580     temp = timeout | (slres << 6) | 0x80;                   // Assemble SLEEP register value
00581     am1805_register_write(AM1805_REG_SLEEPCTRL, temp);      // Write to the register    
00582 
00583 #if AM1805_DEBUG
00584     /* Determine if SLEEP was accepted */
00585     am1805_register_read(AM1805_REG_CTRL2, &temp, 1);       // Get SLP bit (temp & 0x80)
00586     
00587     if ( ( temp & 0x80 ) == 0)
00588     {
00589         char reg_wdi_value = 0;
00590         /* SLEEP did not happen - determine why and return reason. */
00591         am1805_register_read(AM1805_REG_INTMASK, &temp, 1);         // Get status register interrupt enables
00592         am1805_register_read(AM1805_REG_WDT, &reg_wdi_value, 1);    // Get WDT register
00593         if ((( temp & 0x0F ) == 0) & (((reg_wdi_value & 0x7C) == 0) || ((reg_wdi_value & 0x80) == 0x80)))
00594         {
00595             pc.printf("No trigger interrupts enabled\r\n");
00596         }
00597         else
00598         {
00599             pc.printf("Interrupt pending\r\n");
00600         }
00601     }
00602     else
00603     {
00604         pc.printf("SLEEP request successful\r\n");
00605     }
00606 #endif
00607 }