Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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:31:38 by
1.7.2
AM1805 Real-Time Clock with Power Management