Demo the function of RTC module AM1805
Dependencies: mbed-dev
Fork of I2C_HelloWorld_Mbed by
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, ®ister_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, ®_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 }
Generated on Wed Jul 13 2022 11:36:42 by 1.7.2