├── README.md ├── examples ├── rtc_basic_setup │ └── rtc_basic_setup.ino ├── rtc_led_blink │ └── rtc_led_blink.ino └── rtc_register_set_serial_print │ └── rtc_register_set_serial_print.ino ├── keywords.txt ├── library.properties └── src ├── DS1307Emulator.cpp ├── DS1307Emulator.h └── utility ├── rtc_hal.c ├── rtc_hal.h ├── timers.c └── timers.h /README.md: -------------------------------------------------------------------------------- 1 | # DS1307 Emulator Arduino Library V1.0 2 | *Licensing information is attached on the header of each file.* 3 | 4 | The DS1307 Emulator is, as stated by its name, a mere emulation of the omonym chip. This library lets your Arduino behave like such a chip, without actually having a DS1307 around. 5 | 6 | ## Compatibility 7 | Since it is really keeping the time, this library is pre-tuned (and since it is open source can be retuned) to work with a quartz crystal of the system clock, running at 16MHz. For this reason can run on any Arduino that uses an external crystal at 16 MHz. The microcontroller supported is the one from the Atmega family (like Arduino Uno, Leonardo, Nano, Micro, Mini and other Atmega derived at 16MHz crystal, like Arduino PRO). 8 | 9 | It requires to have installed the [HardWire](http://www.arduinolibraries.info/libraries/hard-wire) library. 10 | 11 | ### Library requirements 12 | When initialized with the I2C bus usage, this library occupy the: 13 | - Timer1 (no PWM output on Arduino pins 9 and 10) 14 | - If needed: I2C bus/pins 15 | - If needed: RTC output pin 16 | - At least 4.1 kB of flash available from the sketch 17 | - At least 610 Bytes of RAM available from the sketch 18 | 19 | Disconnecting the RTC logic from the bus, allow to free up the I2C resoources, like SDA and SCL pins, or use the I2C bus for other purposes or role in the bus (i.e. like using the Arduino running the emulator as I2C master for other purposes). It can subsequently reconnected to the RTC logic (see *Initialization* below). 20 | 21 | ## How to use it 22 | To use the library it is needed at least to call the initialization. It could run with just a single line of code. 23 | 24 | ### Initialization 25 | 26 | - **DS1307Emulator.init(*pin number*)** -> initialize the whole emulator, wiping all the non-volatile data and the timekeeping registers. Initialize also the I2C bus. *This step is the minimum required to get the library up and running, therefore is the only function really needed.* 27 | - **DS1307Emulator.busDisconnect()** -> detach the RTC from the I2C bus without alterating the current RTC functionality. Useful if the the bus shall be used/shared with other tasks on the same sketch. After this call, the emulator will work only inside the sketch and you can do whateve you want with the I2C bus, which will be compatible with the [Wire](https://www.arduino.cc/en/Reference/Wire) lib. 28 | - **DS1307Emulator.busConnect()** -> attach the RTC to the I2C bus without alterating the RTC functionality. 29 | 30 | Why the *pin number*? The DS1307 has an output pin, called pin number in the APIs. Let's say we have an Arduino Uno and we want to use the default LED in the port 13. The sketcher shall import the library and call the init in the *setup()*, with the pin number 13. Then, if the emulator is connected to the I2C bus, any master can interact with the Arduino. The only thing required is to call the *init(pin number)* first. 31 | 32 | ## Some use cases and the remaining functions of the library explained 33 | 34 | It is assumed that the RTC is initialized and connected to the I2C bus - i.e. standard initialization. 35 | 36 | **Use case: Physical master interfaced with the board running the emulator** 37 | 38 | 1. Be sure that the emulator software is connected to the bus. If not, issue the DS1307Emulator.busConnect(). 39 | 2. Use a master (very nice would be a second Arduino running an RTC library, or a Raspberry Pi) to talk with the Arduino running the DS1307 emulator, AKA the slave. If the master have the right RTC software (which could be any already written to talk with the original DS1307), it will issue the commands for which this emulator (slave) will answer and behave accordingly. 40 | 41 | **Use case: On-board sketch interfacing with the emulator** 42 | 43 | Function to used in sequence to *write to the emulator* using the sketch: 44 | 45 | 1. **DS1307Emulator.bufferUserData()** -> save the current time to a temporary buffer to avoid time wrapping issues (as the DS1307 chip does). 46 | 2. **DS1307Emulator.writeToRTC(*address*)** -> write the current *address* data. In this step, is the RTC internal address set to address value. 47 | 3. Issuing again the step 2 will now write RTC *data* from the previously set *address* - it will auto-increment the internal address from the one set in step 2. Repeat for as many bytes shall be written. 48 | 4. **DS1307Emulator.setUserData()** -> apply the adjusted configuration to the RTC registers and close the writing sequence. 49 | 50 | Function to used in sequence to *read from the emulator* using the sketch: 51 | 52 | 1. **DS1307Emulator.bufferUserData()** -> save the current time to a temporary buffer to avoid time wrapping issues (as the DS1307 chip does). 53 | 2. **DS1307Emulator.writeToRTC(*address*)** -> write the current address byte. *Note that the step 2 is not mandatory, provided that the address currently set is the right one.* 54 | 3. **(*char*) DS1307Emulator.readUserData()** -> read a char from the current address set in the previous point - it will auto-increment the internal address from the one set in step 2. Repeat for as many bytes shall be read. 55 | 4. There is no need to close a reading sequence. 56 | 57 | In other words, the sketch shall follow the same algoritm the bus master would do. For the moment, read the [DS1307 Datasheet](https://datasheets.maximintegrated.com/en/ds/DS1307.pdf) for informations like what data is present at what address, what to write at what address to stop and start the clock and so on. 58 | 59 | Enjoy! 60 | 61 | 62 | -------------------------------------------------------------------------------- /examples/rtc_basic_setup/rtc_basic_setup.ino: -------------------------------------------------------------------------------- 1 | /* DS1307 RTC Emulator bare minimum setup 2 | * 3 | * This is a basic setup for the RTC emulator, with the pin 13 used as eventual clock tick output. 4 | * It will be initialized the RTC core in default tick halted mode, waiting for commands from an I2C master 5 | * 6 | * Created 19 April 2016 7 | * by Enrico Sanino 8 | * 9 | * This example code is in the public domain. 10 | */ 11 | 12 | #include 13 | 14 | void setup() 15 | { 16 | DS1307Emulator.init(13); 17 | } 18 | 19 | void loop() 20 | { 21 | /* Put your sketch code here, it will run in parallel with the RTC emulator */ 22 | } 23 | -------------------------------------------------------------------------------- /examples/rtc_led_blink/rtc_led_blink.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | * DS1307 Emulator blink 5 | * 6 | * Created on 19 April 2017 7 | * by Enrico Sanino 8 | * 9 | * This example code is part of the public domain 10 | */ 11 | 12 | 13 | void setup() 14 | { 15 | 16 | DS1307Emulator.init(13); 17 | DS1307Emulator.bufferUserData(); 18 | DS1307Emulator.writeToRTC(0x00); // set address 0 19 | DS1307Emulator.writeToRTC(0x00); // start the RTC issuing the clock run command at address 0 20 | DS1307Emulator.setUserData(); 21 | DS1307Emulator.bufferUserData(); 22 | DS1307Emulator.writeToRTC(0x07); // set address 7, the conf register 23 | DS1307Emulator.writeToRTC(0x10); // set output pin to toggle at 1Hz 24 | DS1307Emulator.setUserData(); 25 | } 26 | 27 | void loop() 28 | { 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /examples/rtc_register_set_serial_print/rtc_register_set_serial_print.ino: -------------------------------------------------------------------------------- 1 | /* DS1307 RTC Emulator functionality test, with serial commands and interaction. 2 | * 3 | * Here is initialized and started the RTC emulation. 4 | * With a serial terminal, is possible to send the following commands, followed by a "\n" character (usually already enabled on the Arduino terminal): 5 | * "h" to increment the hours 6 | * "m" to increment minutes 7 | * "D" to increment days 8 | * "d" to increment date 9 | * "M" to increment months 10 | * "y" to increment years 11 | * "c"+"0xXX" to enable the writing in the control register with the "0xXX" exadecimal value. This requires to send a number and not a character, 12 | * so a terminal like Termite can do the job. 13 | * "1" to reconnect on the I2C bus 14 | * "2" to disconnect from the I2C bus 15 | * "3" to issue a soft initialization, RTC pin 13 16 | * "4" to issue a complete re-initialization, RTC pin 13 17 | * "p" to print the RTC values 18 | * 19 | * Created on 19 April 2017 20 | * by Enrico Sanino 21 | * 22 | * This example code is part of the public domain 23 | */ 24 | 25 | 26 | #include 27 | 28 | 29 | uint8_t dec2bcd(uint8_t data); 30 | uint8_t bcd2dec(uint8_t data); 31 | 32 | uint8_t hour_address = 0x02; 33 | uint8_t minute_address = 0x01; 34 | uint8_t second_address = 0x00; 35 | 36 | void setup() 37 | { 38 | // put your setup code here, to run once: 39 | 40 | Serial.begin(9600); 41 | DS1307Emulator.init(13); 42 | DS1307Emulator.bufferUserData(); 43 | DS1307Emulator.writeToRTC(0x00); // set address 0 44 | DS1307Emulator.writeToRTC(0x00); // start the RTC issuing the clock run command at address 0 45 | DS1307Emulator.setUserData(); 46 | } 47 | 48 | void loop() 49 | { 50 | char data = 0; 51 | // To be used with the "\n" in the terminal to work better 52 | if (Serial.available() >= 2) 53 | { 54 | uint8_t temp = 0; 55 | data = Serial.read(); 56 | if (data == 'h') 57 | { 58 | DS1307Emulator.bufferUserData(); 59 | DS1307Emulator.writeToRTC(hour_address); 60 | temp = DS1307Emulator.readUserData(); 61 | temp = bcd2dec(temp); 62 | temp++; 63 | temp = dec2bcd(temp); 64 | DS1307Emulator.bufferUserData(); 65 | DS1307Emulator.writeToRTC(hour_address); 66 | DS1307Emulator.writeToRTC(temp); 67 | DS1307Emulator.setUserData(); 68 | } 69 | else if (data == 'm') 70 | { 71 | DS1307Emulator.bufferUserData(); 72 | DS1307Emulator.writeToRTC(minute_address); 73 | temp = DS1307Emulator.readUserData(); 74 | temp = bcd2dec(temp); 75 | temp++; 76 | temp = dec2bcd(temp); 77 | DS1307Emulator.bufferUserData(); 78 | DS1307Emulator.writeToRTC(minute_address); 79 | DS1307Emulator.writeToRTC(temp); 80 | DS1307Emulator.setUserData(); 81 | } 82 | else if (data == 'D') 83 | { 84 | // DAY 85 | DS1307Emulator.bufferUserData(); 86 | DS1307Emulator.writeToRTC(3); 87 | temp = DS1307Emulator.readUserData(); 88 | temp = bcd2dec(temp); 89 | temp++; 90 | temp = dec2bcd(temp); 91 | DS1307Emulator.bufferUserData(); 92 | DS1307Emulator.writeToRTC(3); 93 | DS1307Emulator.writeToRTC(temp); 94 | DS1307Emulator.setUserData(); 95 | } 96 | else if (data == 'd') 97 | { 98 | // date 99 | DS1307Emulator.bufferUserData(); 100 | DS1307Emulator.writeToRTC(4); 101 | temp = DS1307Emulator.readUserData(); 102 | temp = bcd2dec(temp); 103 | temp++; 104 | temp = dec2bcd(temp); 105 | DS1307Emulator.bufferUserData(); 106 | DS1307Emulator.writeToRTC(4); 107 | DS1307Emulator.writeToRTC(temp); 108 | DS1307Emulator.setUserData(); 109 | } 110 | else if (data == 'M') 111 | { 112 | // Month 113 | DS1307Emulator.bufferUserData(); 114 | DS1307Emulator.writeToRTC(5); 115 | temp = DS1307Emulator.readUserData(); 116 | temp = bcd2dec(temp); 117 | temp++; 118 | temp = dec2bcd(temp); 119 | DS1307Emulator.bufferUserData(); 120 | DS1307Emulator.writeToRTC(5); 121 | DS1307Emulator.writeToRTC(temp); 122 | DS1307Emulator.setUserData(); 123 | } 124 | else if (data == 'y') 125 | { 126 | // guess what 127 | DS1307Emulator.bufferUserData(); 128 | DS1307Emulator.writeToRTC(6); 129 | temp = DS1307Emulator.readUserData(); 130 | temp = bcd2dec(temp); 131 | temp++; 132 | temp = dec2bcd(temp); 133 | DS1307Emulator.bufferUserData(); 134 | DS1307Emulator.writeToRTC(6); 135 | DS1307Emulator.writeToRTC(temp); 136 | DS1307Emulator.setUserData(); 137 | } 138 | else if (data == 'c') 139 | { 140 | // control register, from terminal issue c+0xXX. So a char and a number representing the control register configuration. 141 | // Cannot be done from the Arduino terminal (allows only characters), but very easily from others, like Termite terminal 142 | DS1307Emulator.bufferUserData(); 143 | DS1307Emulator.writeToRTC(7); 144 | if (Serial.available()) 145 | { 146 | DS1307Emulator.writeToRTC(Serial.read()); 147 | } 148 | DS1307Emulator.setUserData(); 149 | } 150 | else if (data == '1') 151 | { 152 | DS1307Emulator.busConnect(); 153 | } 154 | else if (data == '2') 155 | { 156 | DS1307Emulator.busDisconnect(); 157 | } 158 | else if (data == '3') 159 | { 160 | DS1307Emulator.softInit(13); 161 | } 162 | else if (data == '4') 163 | { 164 | DS1307Emulator.init(13); 165 | } 166 | else if (data == 'p') 167 | { 168 | DS1307Emulator.bufferUserData(); 169 | DS1307Emulator.writeToRTC(second_address); 170 | Serial.print("Second: "); 171 | Serial.print(DS1307Emulator.readUserData(), HEX); 172 | Serial.println(); 173 | Serial.print("Minute: "); 174 | Serial.print(DS1307Emulator.readUserData(), HEX); 175 | Serial.println(); 176 | Serial.print("Hour: "); 177 | Serial.print(DS1307Emulator.readUserData(), HEX); 178 | Serial.println(); 179 | Serial.print("Day: "); 180 | Serial.print(DS1307Emulator.readUserData(), HEX); 181 | Serial.println(); 182 | Serial.print("Date: "); 183 | Serial.print(DS1307Emulator.readUserData(), HEX); 184 | Serial.println(); 185 | Serial.print("Month: "); 186 | Serial.print(DS1307Emulator.readUserData(), HEX); 187 | Serial.println(); 188 | Serial.print("Year: "); 189 | Serial.print(DS1307Emulator.readUserData(), HEX); 190 | Serial.println(); 191 | Serial.print("Ctrl: "); 192 | Serial.print(DS1307Emulator.readUserData(), HEX); 193 | Serial.println(); 194 | } 195 | } 196 | } 197 | 198 | uint8_t dec2bcd(uint8_t data) 199 | { 200 | return ((data/10 * 16) + (data % 10)); 201 | } 202 | 203 | 204 | uint8_t bcd2dec(uint8_t data) 205 | { 206 | return ((data/16 * 10) + (data % 16)); 207 | } 208 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Wire 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | 10 | ####################################### 11 | # Methods and Functions (KEYWORD2) 12 | ####################################### 13 | 14 | init KEYWORD2 15 | softInit KEYWORD2 16 | tickIncrementISR KEYWORD2 17 | readUserData KEYWORD2 18 | writeToRTC KEYWORD2 19 | bufferUserData KEYWORD2 20 | setUserData KEYWORD2 21 | busConnect KEYWORD2 22 | busDisconnect KEYWORD2 23 | 24 | ####################################### 25 | # Instances (KEYWORD2) 26 | ####################################### 27 | 28 | DS1307Emulator KEYWORD2 29 | HardWire KEYWORD2 30 | Wire KEYWORD2 31 | 32 | ####################################### 33 | # Constants (LITERAL1) 34 | ####################################### 35 | 36 | DS1307_DEVICE_ADDRESS LITERAL1 -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=DS1307 Emulator 2 | version=1.0 3 | author=Enrico Sanino 4 | maintainer=Enrico Sanino 5 | sentence = An emulator of the DS1307, which transform the Arduino in an RTC chip without actually having a physical RTC. 6 | paragraph= It is natively compatible with any Arduino carrying and Atmega and a 16MHz crystal oscillator. 7 | category=Timing 8 | url=https://github.com/thexeno/DS1307-Emulator-Arduino-Library 9 | architectures=avr 10 | depends=HardWire 11 | -------------------------------------------------------------------------------- /src/DS1307Emulator.cpp: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright (c) 2016 Enrico Sanino 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in all 13 | //copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | //SOFTWARE. 22 | 23 | extern "C" 24 | { 25 | #include "string.h" 26 | #include "avr/interrupt.h" 27 | } 28 | #include "HardWire.h" 29 | #include "DS1307Emulator.h" 30 | 31 | 32 | /*DS RTC defines*/ 33 | #define SEC 0x00 34 | #define MIN 0x01 35 | #define HOUR 0x02 36 | #define WDAY 0x03 37 | #define MDAY 0x04 38 | #define MONTH 0x05 39 | #define YEAR 0x06 40 | #define CONTROL_ADDRESS 0x07 41 | #define NVRAM_BEGIN_ADDR 0x08 42 | 43 | 44 | #define RTC_PROTOCOL_BUFFER_SIZE 7 45 | 46 | #define MAX_RTC_ONLY_ADDRESS CONTROL_ADDRESS 47 | #define MAX_RTC_TOTAL_ADDR 0x40 48 | 49 | /* Digital/swq selection */ 50 | #define RTC_PROTOCOL_SQWE_MASK 0x10 51 | #define RTC_PROTOCOL_OUT_DIGITAL_MODE 0x00 52 | #define RTC_PROTOCOL_OUT_SQUAREW_MODE 0x10 53 | 54 | /* Prescaler selection */ 55 | #define RTC_PROTOCOL_RS_MASK 0x03 56 | #define RTC_PROTOCOL_SET_1HZ_MODE 0x00 57 | #define RTC_PROTOCOL_SET_32768HZ_MODE 0x03 58 | 59 | /* digital pin value */ 60 | #define RTC_PROTOCOL_OUT_MASK 0x80 61 | #define RTC_PROTOCOL_OUTVAL_LOW 0 62 | #define RTC_PROTOCOL_OUTVAL_HIGH 1 63 | 64 | /* CH */ 65 | #define RTC_PROTOCOL_CH_MASK 0x80 66 | #define RTC_PROTOCOL_CH_MODE 0x80 67 | #define RTC_PROTOCOL_NCH_MODE 0x00 68 | 69 | /* hour */ 70 | #define RTC_PROTOCOL_HOUR_FORMAT_MASK 0x40 71 | #define RTC_PROTOCOL_MILITARY_FORMAT_MODE 0x00 72 | #define RTC_PROTOCOL_NO_MILITARY_FORMAT_MODE 0x40 73 | 74 | #define RTC_PROTOCOL_HOUR_MASK 0x1F 75 | #define RTC_PROTOCOL_HOUR_MIL_MASK 0x3F 76 | 77 | #define RTC_PROTOCOL_AM_PM_MASK 0x20 78 | #define RTC_PROTOCOL_AM_MODE 0x00 79 | #define RTC_PROTOCOL_PM_MODE 0x20 80 | 81 | /* second */ 82 | #define RTC_PROTOCOL_SECOND_MASK 0x7F 83 | 84 | /* minute */ 85 | #define RTC_PROTOCOL_MINUTE_MASK 0x7F 86 | 87 | /* wday */ 88 | #define RTC_PROTOCOL_WDAY_MASK 0x07 89 | 90 | /* mday */ 91 | #define RTC_PROTOCOL_MDAY_MASK 0x3F 92 | 93 | /* month */ 94 | #define RTC_PROTOCOL_MONTH_MASK 0x1F 95 | 96 | /* year */ 97 | #define RTC_PROTOCOL_YEAR_MASK 0xFF 98 | 99 | 100 | static void DS1307emulatorWrapper_OnReceive(int data); 101 | static void DS1307emulatorWrapper_OnReceiveAdx(void); 102 | static void DS1307emulatorWrapper_OnReceiveData(int data); 103 | static void DS1307emulatorWrapper_OnReceiveDataNack(void); 104 | static void DS1307emulatorWrapper_OnRequest(void); 105 | static uint8_t DS1307emulatorWrapper_OnRequestData(void); 106 | static void DS1307emulatorWrapper_OnRequestDataNack(void); 107 | static void DS1307emulatorWrapper_tick(); 108 | 109 | enum 110 | { 111 | RTC_OP_RD, 112 | RTC_OP_WR 113 | }; 114 | 115 | 116 | typedef struct { 117 | uint8_t second; 118 | uint8_t minute; 119 | uint8_t hour; 120 | uint8_t Wday; 121 | uint8_t Mday; 122 | uint8_t month; 123 | uint8_t year; 124 | uint8_t NvRam[56]; 125 | uint8_t ptr; 126 | uint8_t clockHaltReq; 127 | uint8_t dataSync; 128 | uint8_t busState; 129 | uint8_t halfTick; 130 | uint8_t notLeap; 131 | uint8_t am_Pm; 132 | uint8_t sqwOutPinFreq; 133 | uint8_t sqwOutPinMode; 134 | uint8_t sqwOutPinValue; 135 | uint8_t dataByte; 136 | uint8_t clockHalt; 137 | uint8_t hourFormat; 138 | uint8_t noSet; 139 | uint8_t isrSync; 140 | uint8_t pin; 141 | uint8_t lastOperation; 142 | } DS1307_GLOBAL_DATA_T; 143 | 144 | 145 | typedef struct userRtcBuffer { 146 | uint8_t second; 147 | uint8_t minute; 148 | uint8_t hour; 149 | uint8_t Wday; 150 | uint8_t Mday; 151 | uint8_t month; 152 | uint8_t year; 153 | uint8_t am_Pm; 154 | uint8_t hourFormat; 155 | } RTC_DATA_BUFF_T; 156 | 157 | 158 | //uint8_t rtcFlag[] = {0,0,0,0,0,0,0,0}; 159 | 160 | const uint8_t nvRamReset[56] = { 161 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 163 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 168 | }; 169 | 170 | static DS1307_GLOBAL_DATA_T rtcData; 171 | static RTC_DATA_BUFF_T rtcDataBuffered; 172 | static uint8_t nvRam[56]; 173 | 174 | // Constructors //////////////////////////////////////////////////////////////// 175 | 176 | DS1307emulator::DS1307emulator() 177 | { 178 | } 179 | 180 | ISR(TIMER1_COMPA_vect) 181 | { 182 | 183 | //userTickISR(); 184 | DS1307emulatorWrapper_tick(); 185 | 186 | } 187 | 188 | static void DS1307emulatorWrapper_tick(void) 189 | { 190 | DS1307emulator::tickIncrementISR(); 191 | } 192 | 193 | static void DS1307emulatorWrapper_OnReceive(int data) 194 | { 195 | DS1307emulator::setUserData(); 196 | } 197 | 198 | void DS1307emulatorWrapper_OnReceiveAdx(void) 199 | { 200 | DS1307emulator::bufferUserData(); 201 | } 202 | 203 | void DS1307emulatorWrapper_OnReceiveData(int data) 204 | { 205 | DS1307emulator::writeToRTC((uint8_t)data); 206 | } 207 | 208 | void DS1307emulatorWrapper_OnReceiveDataNack(void) 209 | { 210 | DS1307emulator::setUserData(); 211 | } 212 | 213 | 214 | 215 | void DS1307emulatorWrapper_OnRequest(void) 216 | { 217 | uint8_t data; 218 | DS1307emulator::bufferUserData(); 219 | data = DS1307emulator::readUserData(); 220 | Wire.write(data); 221 | } 222 | 223 | 224 | uint8_t DS1307emulatorWrapper_OnRequestData(void) 225 | { 226 | return DS1307emulator::readUserData(); 227 | } 228 | 229 | void DS1307emulatorWrapper_OnRequestDataNack(void) 230 | { 231 | DS1307emulator::setUserData(); 232 | } 233 | 234 | 235 | 236 | 237 | 238 | static unsigned char bcdToDec(unsigned char data) 239 | { 240 | unsigned char temp = 0; 241 | temp = data >> 4; 242 | temp = temp*10; 243 | return (temp + (data & 0x0F)); 244 | } 245 | 246 | static unsigned char decToBcd(unsigned char data) 247 | { 248 | char temp = 0; 249 | temp = data/10; 250 | temp = temp << 4; 251 | return (temp + (data - bcdToDec(temp))); 252 | } 253 | 254 | static uint8_t leapCalc(uint8_t year) 255 | { 256 | uint8_t ret = 1; 257 | if ((year % 100) == 0) 258 | { 259 | if ((year % 400) == 0) 260 | { 261 | ret = 0; 262 | } 263 | } 264 | else if ((year % 4) == 0) 265 | { 266 | ret = 0; 267 | } 268 | return ret; 269 | } 270 | 271 | void DS1307emulator::putYear(uint8_t data) 272 | { 273 | uint8_t temp = 0; 274 | temp = bcdToDec(data); 275 | if (temp > 99) 276 | { 277 | rtcDataBuffered.year = (0x99 & RTC_PROTOCOL_YEAR_MASK); 278 | } 279 | else 280 | { 281 | rtcDataBuffered.year = (data & RTC_PROTOCOL_YEAR_MASK); 282 | } 283 | 284 | } 285 | 286 | void DS1307emulator::putMonth(uint8_t data) 287 | { 288 | uint8_t temp = 0; 289 | temp = bcdToDec(data); 290 | if (temp > 12 || temp == 0) 291 | { 292 | rtcDataBuffered.month = (0x01 & RTC_PROTOCOL_MONTH_MASK); 293 | } 294 | else 295 | { 296 | rtcDataBuffered.month = (data & RTC_PROTOCOL_MONTH_MASK); 297 | } 298 | } 299 | 300 | void DS1307emulator::putMday(uint8_t data) 301 | { 302 | uint8_t temp = 0; 303 | temp = bcdToDec(data); 304 | if (temp > 31 || temp == 0) 305 | { 306 | rtcDataBuffered.Mday = (0x01 & RTC_PROTOCOL_MDAY_MASK); 307 | } 308 | else 309 | { 310 | rtcDataBuffered.Mday = (data & RTC_PROTOCOL_MDAY_MASK); 311 | } 312 | } 313 | 314 | void DS1307emulator::putWday(uint8_t data) 315 | { 316 | uint8_t temp = 0; 317 | temp = bcdToDec(data); 318 | if (temp > 7 || temp == 0) 319 | { 320 | rtcDataBuffered.Wday = (0x01 & RTC_PROTOCOL_WDAY_MASK); 321 | } 322 | else 323 | { 324 | rtcDataBuffered.Wday = (data & RTC_PROTOCOL_WDAY_MASK); 325 | } 326 | } 327 | 328 | void DS1307emulator::putHour(uint8_t data) 329 | { 330 | uint8_t temp = 0; 331 | 332 | rtcDataBuffered.hourFormat = (data & RTC_PROTOCOL_HOUR_FORMAT_MASK); 333 | if (rtcDataBuffered.hourFormat == RTC_PROTOCOL_MILITARY_FORMAT_MODE) 334 | { 335 | rtcDataBuffered.hour = (data & RTC_PROTOCOL_HOUR_MIL_MASK); 336 | temp = bcdToDec(rtcDataBuffered.hour); 337 | if (temp > 23) 338 | { 339 | rtcDataBuffered.hour = (/*0x00*/ 0x01 & RTC_PROTOCOL_HOUR_MIL_MASK); 340 | } 341 | } 342 | else 343 | { 344 | rtcDataBuffered.hour = (data & RTC_PROTOCOL_HOUR_MASK); 345 | temp = bcdToDec(rtcDataBuffered.hour); 346 | if (temp > 12 || temp == 0) 347 | { 348 | rtcDataBuffered.hour = (0x01 & RTC_PROTOCOL_HOUR_MASK); 349 | } 350 | } 351 | rtcDataBuffered.am_Pm = (data & RTC_PROTOCOL_AM_PM_MASK); 352 | } 353 | 354 | void DS1307emulator::putMinute(uint8_t data) 355 | { 356 | uint8_t temp = 0; 357 | temp = bcdToDec(data); 358 | if (temp > 59) 359 | { 360 | rtcDataBuffered.minute = (0x00 & RTC_PROTOCOL_MINUTE_MASK); 361 | } 362 | else 363 | { 364 | rtcDataBuffered.minute = (data & RTC_PROTOCOL_MINUTE_MASK); 365 | } 366 | } 367 | 368 | void DS1307emulator::putSecond(uint8_t data) 369 | { 370 | int8_t temp = 0; 371 | rtcDataBuffered.second = (data & RTC_PROTOCOL_SECOND_MASK); 372 | rtcData.clockHalt = data & RTC_PROTOCOL_CH_MASK; 373 | temp = bcdToDec(rtcDataBuffered.second); 374 | if (temp > 59) 375 | { 376 | rtcDataBuffered.second = (0x00 & RTC_PROTOCOL_SECOND_MASK); 377 | } 378 | 379 | } 380 | void DS1307emulator::putNvRam(uint8_t data, uint8_t w_addr) 381 | { 382 | /* Not buffered */ 383 | rtcData.NvRam[w_addr-8] = data; 384 | } 385 | void DS1307emulator::putControlHandler(uint8_t data) 386 | { 387 | // Control Register from datasheet 388 | rtcData.sqwOutPinMode = data & RTC_PROTOCOL_SQWE_MASK;//RTC_PROTOCOL_OUT_DIGITAL_MODE, RTC_PROTOCOL_OUT_SQUAREW_MODE 389 | rtcData.sqwOutPinValue = data & RTC_PROTOCOL_OUT_MASK;// 390 | rtcData.sqwOutPinFreq = data & RTC_PROTOCOL_RS_MASK; //RTC_PROTOCOL_SET_1HZ_MODE 391 | } 392 | 393 | 394 | /* Read RTC data from structure */ 395 | 396 | void DS1307emulator::getControlHandler(uint8_t* val) 397 | { 398 | uint8_t data = 0; 399 | data = (rtcData.sqwOutPinMode | rtcData.sqwOutPinFreq | rtcData.sqwOutPinValue); 400 | *val = data; 401 | } 402 | 403 | void DS1307emulator::getYear(uint8_t* data) 404 | { 405 | *data = (rtcDataBuffered.year & RTC_PROTOCOL_YEAR_MASK); 406 | } 407 | 408 | void DS1307emulator::getMonth(uint8_t *data) 409 | { 410 | *data = (rtcDataBuffered.month & RTC_PROTOCOL_MONTH_MASK); 411 | } 412 | void DS1307emulator::getMday(uint8_t *data) 413 | { 414 | *data = (rtcDataBuffered.Mday & RTC_PROTOCOL_MDAY_MASK); 415 | } 416 | void DS1307emulator::getWday(uint8_t *data) 417 | { 418 | *data = (rtcDataBuffered.Wday & RTC_PROTOCOL_WDAY_MASK); 419 | } 420 | void DS1307emulator::getHour(uint8_t *data) 421 | { 422 | if (rtcDataBuffered.hourFormat == RTC_PROTOCOL_MILITARY_FORMAT_MODE) 423 | { 424 | *data = (rtcDataBuffered.hour & RTC_PROTOCOL_HOUR_MIL_MASK); 425 | } 426 | else 427 | { 428 | *data = (rtcDataBuffered.hour & RTC_PROTOCOL_HOUR_MASK); 429 | *data |= rtcDataBuffered.am_Pm; 430 | } 431 | *data |= rtcDataBuffered.hourFormat; 432 | } 433 | void DS1307emulator::getMinute(uint8_t *data) 434 | { 435 | *data = (rtcDataBuffered.minute & RTC_PROTOCOL_MINUTE_MASK); 436 | } 437 | void DS1307emulator::getSecond(uint8_t *data) 438 | { 439 | *data = (rtcDataBuffered.second & RTC_PROTOCOL_SECOND_MASK); 440 | *data |=(rtcData.clockHalt); 441 | } 442 | 443 | void DS1307emulator::getNvRam(uint8_t *data, uint8_t w_addr) 444 | { 445 | *data = rtcData.NvRam[w_addr-8]; 446 | } 447 | 448 | 449 | /* Public functions */ 450 | 451 | void DS1307emulator::setUserData(void) 452 | { 453 | 454 | if (rtcData.lastOperation == RTC_OP_RD) 455 | { 456 | /* do nothing */ 457 | } 458 | else 459 | { 460 | /* always work in decimal */ 461 | rtcHal_stopRtcTick(); 462 | 463 | rtcData.second = bcdToDec(rtcDataBuffered.second); 464 | rtcData.minute = bcdToDec(rtcDataBuffered.minute); 465 | rtcData.hour = bcdToDec(rtcDataBuffered.hour); 466 | rtcData.Wday = bcdToDec(rtcDataBuffered.Wday); 467 | rtcData.Mday = bcdToDec(rtcDataBuffered.Mday); 468 | rtcData.month = bcdToDec(rtcDataBuffered.month); 469 | rtcData.year = bcdToDec(rtcDataBuffered.year); 470 | 471 | rtcData.am_Pm = rtcDataBuffered.am_Pm; 472 | 473 | rtcData.notLeap = leapCalc(rtcData.year); 474 | /* just to be in order, since there are no mask values for leap */ 475 | if (rtcData.notLeap && rtcData.month == 2 && rtcData.Mday == 29) 476 | { 477 | rtcData.Mday = 28; 478 | } 479 | 480 | //rtcData.dataSync = 0; 481 | rtcData.halfTick = 0; 482 | /* Set other settings */ 483 | /* Update out pin RTC */ 484 | if (rtcData.sqwOutPinMode == RTC_PROTOCOL_OUT_DIGITAL_MODE) 485 | { 486 | rtcHal_setPinDigitalMode(rtcData.pin); 487 | 488 | rtcHal_setPinDigitalValue(rtcData.pin, !!rtcData.sqwOutPinValue); 489 | } 490 | else if (rtcData.sqwOutPinMode == RTC_PROTOCOL_OUT_SQUAREW_MODE) 491 | { 492 | /* Ignores the digital data */ 493 | if (rtcData.sqwOutPinFreq == RTC_PROTOCOL_SET_1HZ_MODE) 494 | { 495 | 496 | rtcHal_setPinDigitalMode(rtcData.pin); 497 | /* Digital changed in ISR */ 498 | } 499 | else 500 | { 501 | rtcHal_resetPinDigitalMode(rtcData.pin); 502 | 503 | /* And use fast waveform */ 504 | } 505 | } 506 | else 507 | { 508 | 509 | 510 | rtcHal_setPinDigitalMode(rtcData.pin); 511 | rtcHal_setPinDigitalValue(rtcData.pin, 0); 512 | } 513 | 514 | if (rtcData.clockHalt == RTC_PROTOCOL_CH_MODE) 515 | { 516 | rtcHal_stopRtcTick(); 517 | } 518 | else if (rtcData.clockHalt == RTC_PROTOCOL_NCH_MODE) 519 | { 520 | rtcHal_startRtcTick(); 521 | } 522 | rtcData.lastOperation = RTC_OP_RD; 523 | } 524 | 525 | } 526 | 527 | uint8_t DS1307emulator::readUserData(void) 528 | { 529 | uint8_t data = 0; 530 | DS1307emulator::getFromRTC(&data); 531 | rtcData.lastOperation == RTC_OP_RD; 532 | return (data); 533 | } 534 | 535 | void DS1307emulator::busDisconnect() 536 | { 537 | Wire.end(); 538 | } 539 | 540 | void DS1307emulator::busConnect() 541 | { 542 | Wire.begin(DS1307_DEVICE_ADDRESS, HARD_WIRE_MODE); 543 | Wire.onReceive(DS1307emulatorWrapper_OnReceive); 544 | Wire.onReceiveAdx(DS1307emulatorWrapper_OnReceiveAdx); 545 | Wire.onReceiveData(DS1307emulatorWrapper_OnReceiveData); 546 | Wire.onReceiveDataNack(DS1307emulatorWrapper_OnReceiveDataNack); 547 | Wire.onRequest(DS1307emulatorWrapper_OnRequest); 548 | Wire.onRequestData(DS1307emulatorWrapper_OnRequestData); 549 | Wire.onRequestDataNack(DS1307emulatorWrapper_OnRequestDataNack); 550 | } 551 | 552 | 553 | 554 | void DS1307emulator::softInit(uint8_t pin) 555 | { 556 | Wire.begin(DS1307_DEVICE_ADDRESS, HARD_WIRE_MODE); 557 | Wire.onReceive(DS1307emulatorWrapper_OnReceive); 558 | Wire.onReceiveAdx(DS1307emulatorWrapper_OnReceiveAdx); 559 | Wire.onReceiveData(DS1307emulatorWrapper_OnReceiveData); 560 | Wire.onReceiveDataNack(DS1307emulatorWrapper_OnReceiveDataNack); 561 | Wire.onRequest(DS1307emulatorWrapper_OnRequest); 562 | Wire.onRequestData(DS1307emulatorWrapper_OnRequestData); 563 | Wire.onRequestDataNack(DS1307emulatorWrapper_OnRequestDataNack); 564 | 565 | rtcData.pin = pin; 566 | rtcHal_init(rtcData.pin); 567 | } 568 | 569 | void DS1307emulator::init(uint8_t pin) 570 | { 571 | Wire.begin(DS1307_DEVICE_ADDRESS, HARD_WIRE_MODE); 572 | Wire.onReceive(DS1307emulatorWrapper_OnReceive); 573 | Wire.onReceiveAdx(DS1307emulatorWrapper_OnReceiveAdx); 574 | Wire.onReceiveData(DS1307emulatorWrapper_OnReceiveData); 575 | Wire.onReceiveDataNack(DS1307emulatorWrapper_OnReceiveDataNack); 576 | Wire.onRequest(DS1307emulatorWrapper_OnRequest); 577 | Wire.onRequestData(DS1307emulatorWrapper_OnRequestData); 578 | Wire.onRequestDataNack(DS1307emulatorWrapper_OnRequestDataNack); 579 | 580 | rtcData.pin = pin; 581 | rtcHal_init(rtcData.pin); 582 | rtcData.second = 0; 583 | rtcData.minute = 0; 584 | rtcData.hour = 0; 585 | rtcData.Wday = 1; 586 | rtcData.Mday = 1; 587 | rtcData.month = 1; 588 | rtcData.year = 0; 589 | rtcData.ptr = 0; 590 | rtcData.halfTick = 0; 591 | memcpy(rtcData.NvRam, nvRamReset, sizeof(rtcData.NvRam)); 592 | rtcData.notLeap = leapCalc(rtcData.year); 593 | rtcData.am_Pm = RTC_PROTOCOL_AM_MODE; 594 | rtcData.sqwOutPinFreq = RTC_PROTOCOL_SET_1HZ_MODE; 595 | rtcData.sqwOutPinMode = RTC_PROTOCOL_OUT_DIGITAL_MODE; 596 | rtcData.sqwOutPinValue = RTC_PROTOCOL_OUTVAL_LOW; 597 | rtcData.dataByte = 0; /* first byte rx will be adx */ 598 | rtcData.clockHalt = RTC_PROTOCOL_CH_MODE; 599 | rtcData.hourFormat = RTC_PROTOCOL_MILITARY_FORMAT_MODE; 600 | rtcData.isrSync = 1; 601 | rtcData.lastOperation = RTC_OP_WR; 602 | DS1307emulator::bufferUserData(); 603 | DS1307emulator::setUserData(); 604 | rtcData.lastOperation = RTC_OP_RD; 605 | } 606 | 607 | 608 | 609 | 610 | 611 | /* API Chiamata da ISR timer */ 612 | void DS1307emulator::tickIncrementISR(void) 613 | { 614 | uint8_t tickIncrement_hourIncr = 0; 615 | /* Counting made 0-24h, retieved converted upon approrpiate setting (mil or american format) */ 616 | /* Also the BCD format will be converted only upon request in rtcProtocol API*/ 617 | 618 | 619 | rtcData.isrSync = 0; 620 | 621 | if (rtcData.halfTick) 622 | { 623 | rtcData.halfTick = 0; 624 | } 625 | else 626 | { 627 | rtcData.halfTick = 1; 628 | } 629 | 630 | if (!rtcData.halfTick) 631 | { 632 | /* Primary tick -> execute handler */ 633 | if ((++rtcData.second)==60) 634 | { 635 | //DS1307emulator::bufferUserData(); 636 | rtcData.second = 0; 637 | if ((++rtcData.minute) == 60) 638 | { 639 | rtcData.minute = 0; 640 | if (rtcData.hourFormat == RTC_PROTOCOL_MILITARY_FORMAT_MODE) 641 | { 642 | /* 0-24 */ 643 | if ((++rtcData.hour) == 24) 644 | { 645 | rtcData.hour = 0; 646 | tickIncrement_hourIncr = 1; 647 | } 648 | else 649 | { 650 | tickIncrement_hourIncr = 0; 651 | } 652 | } 653 | else 654 | { 655 | if ((++rtcData.hour) > 12) 656 | { 657 | rtcData.hour = rtcData.hour - 12; /* back to 1 */ 658 | if (rtcData.am_Pm == RTC_PROTOCOL_AM_MODE) 659 | { 660 | rtcData.am_Pm = RTC_PROTOCOL_PM_MODE; 661 | tickIncrement_hourIncr = 0; 662 | } 663 | else 664 | { 665 | rtcData.am_Pm = RTC_PROTOCOL_AM_MODE; 666 | tickIncrement_hourIncr = 1; 667 | } 668 | } 669 | } 670 | if (tickIncrement_hourIncr == 1) 671 | { 672 | rtcData.Mday++; 673 | if (++rtcData.Wday == 8) 674 | { 675 | rtcData.Wday = 1; 676 | } 677 | 678 | if ((rtcData.Mday == 32) || 679 | ((rtcData.Mday == 31) && 680 | ((rtcData.month == 4) || (rtcData.month == 6) || 681 | (rtcData.month == 9) || (rtcData.month == 11))) || 682 | ((rtcData.month == 2) && (rtcData.Mday == 29) && rtcData.notLeap) || 683 | ((rtcData.month == 2) && (rtcData.Mday == 30))) 684 | { 685 | rtcData.Mday = 1; 686 | if ((++rtcData.month)==13) 687 | { 688 | rtcData.month = 1; 689 | rtcData.year++; 690 | rtcData.notLeap = leapCalc(rtcData.year); 691 | } 692 | } 693 | } 694 | } 695 | } 696 | } 697 | if (rtcData.sqwOutPinMode == RTC_PROTOCOL_OUT_SQUAREW_MODE && 698 | rtcData.sqwOutPinFreq == RTC_PROTOCOL_SET_1HZ_MODE) 699 | { 700 | if (rtcData.halfTick) 701 | { 702 | rtcHal_setPinDigitalValue(rtcData.pin, 1); 703 | } 704 | else 705 | { 706 | 707 | rtcHal_setPinDigitalValue(rtcData.pin, 0); 708 | } 709 | } 710 | rtcData.isrSync = 1; 711 | } 712 | 713 | 714 | uint8_t DS1307emulator::getFromRTC(unsigned char *data) 715 | { 716 | 717 | 718 | switch (rtcData.ptr){ 719 | case SEC: //seconds 720 | DS1307emulator::getSecond(data); 721 | //rtcFlag[2]++; 722 | break; 723 | 724 | case MIN: 725 | DS1307emulator::getMinute(data); 726 | //rtcFlag[3]++; 727 | break; 728 | case HOUR: // hours 729 | DS1307emulator::getHour(data); 730 | break; 731 | 732 | case WDAY: // day of week 733 | DS1307emulator::getWday(data); 734 | break; 735 | 736 | case MDAY: // day of month 737 | DS1307emulator::getMday(data); 738 | break; 739 | case MONTH : // month 740 | DS1307emulator::getMonth(data); 741 | break; 742 | case YEAR: // year yy 743 | DS1307emulator::getYear(data); 744 | break; 745 | case CONTROL_ADDRESS: 746 | DS1307emulator::getControlHandler(data); 747 | break; 748 | 749 | default: 750 | if (rtcData.ptr >= NVRAM_BEGIN_ADDR && rtcData.ptr < MAX_RTC_TOTAL_ADDR) 751 | { 752 | DS1307emulator::getNvRam(data, rtcData.ptr); 753 | //rtcFlag[1]++; 754 | } 755 | break; 756 | } 757 | 758 | rtcData.ptr++; 759 | if (rtcData.ptr >= MAX_RTC_TOTAL_ADDR-1) 760 | { 761 | rtcData.ptr = 0; 762 | //rtcFlag[5]++; 763 | } 764 | //rtcFlag[4]++; 765 | return 0; 766 | } 767 | 768 | void DS1307emulator::bufferUserData(void) 769 | { 770 | /* Save all time dependant data, as stated in DS1307 */ 771 | rtcDataBuffered.second = decToBcd(rtcData.second); 772 | rtcDataBuffered.minute = decToBcd(rtcData.minute); 773 | rtcDataBuffered.hour = decToBcd(rtcData.hour); 774 | rtcDataBuffered.Wday = decToBcd(rtcData.Wday); 775 | rtcDataBuffered.Mday = decToBcd(rtcData.Mday); 776 | rtcDataBuffered.month = decToBcd(rtcData.month); 777 | rtcDataBuffered.year = decToBcd(rtcData.year); 778 | rtcDataBuffered.am_Pm = rtcData.am_Pm; 779 | rtcData.dataByte = 0; 780 | 781 | } 782 | 783 | uint8_t DS1307emulator::writeToRTC(unsigned char data){ 784 | 785 | //uint8_t noWrite = 1; 786 | 787 | if (rtcData.dataByte == 0) 788 | { 789 | rtcData.ptr = data; 790 | // rtcFlag[0]++; 791 | } 792 | else 793 | { 794 | switch (rtcData.ptr){ 795 | case SEC: //seconds 796 | DS1307emulator::putSecond(data); 797 | break; 798 | 799 | case MIN: 800 | DS1307emulator::putMinute(data); 801 | break; 802 | case HOUR: // hours 803 | DS1307emulator::putHour(data); 804 | break; 805 | 806 | case WDAY: // day of week 807 | DS1307emulator::putWday(data); 808 | break; 809 | 810 | case MDAY: // day of month 811 | DS1307emulator::putMday(data); 812 | break; 813 | case MONTH : // month 814 | DS1307emulator::putMonth(data); 815 | break; 816 | case YEAR: // year yy 817 | DS1307emulator::putYear(data); 818 | break; 819 | case CONTROL_ADDRESS: 820 | DS1307emulator::putControlHandler(data); 821 | break; 822 | 823 | default: 824 | if (rtcData.ptr >= NVRAM_BEGIN_ADDR && rtcData.ptr < MAX_RTC_TOTAL_ADDR) 825 | { 826 | DS1307emulator::putNvRam(data, rtcData.ptr); 827 | } 828 | break; 829 | } 830 | //noWrite = 0; 831 | rtcData.lastOperation = RTC_OP_WR; 832 | } 833 | 834 | if (rtcData.dataByte == 1) 835 | { 836 | rtcData.ptr++; 837 | } 838 | else 839 | { 840 | rtcData.dataByte = 1; 841 | } 842 | 843 | //qua l'errore' 844 | if (rtcData.ptr >= MAX_RTC_TOTAL_ADDR) 845 | { 846 | rtcData.ptr = 0; 847 | } 848 | 849 | //if (noWrite == 1) 850 | //{ 851 | //rtcData.noSet = 1; 852 | //} 853 | //else 854 | //{ 855 | //rtcData.noSet = 0; 856 | //} 857 | 858 | return 0; 859 | } 860 | 861 | // Preinstantiate Objects ////////////////////////////////////////////////////// 862 | 863 | DS1307emulator DS1307Emulator = DS1307emulator(); 864 | 865 | 866 | 867 | -------------------------------------------------------------------------------- /src/DS1307Emulator.h: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright (c) 2016 Enrico Sanino 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in all 13 | //copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | //SOFTWARE. 22 | 23 | 24 | 25 | 26 | #ifndef RTC_PROTOCOL_H_ 27 | #define RTC_PROTOCOL_H_ 28 | 29 | extern "C" 30 | { 31 | #include "utility/rtc_hal.h" 32 | #include 33 | #include "avr/interrupt.h" 34 | #include "avr/io.h" 35 | } 36 | 37 | 38 | #include 39 | 40 | 41 | #define DS1307_DEVICE_ADDRESS 0x68 /* of DS1307 protocol */ 42 | 43 | 44 | 45 | 46 | 47 | 48 | class DS1307emulator 49 | { 50 | public: 51 | DS1307emulator(); 52 | void init(uint8_t); 53 | void softInit(uint8_t); 54 | static void tickIncrementISR(void); 55 | static uint8_t readUserData(void); 56 | static uint8_t writeToRTC(unsigned char data); 57 | static void bufferUserData(void); 58 | static void setUserData(void); 59 | static void busConnect(void); 60 | static void busDisconnect(void); 61 | 62 | 63 | private: 64 | 65 | static uint8_t getFromRTC(unsigned char *data); 66 | static void putYear(uint8_t data); 67 | static void putMonth(uint8_t data); 68 | static void putMday(uint8_t data); 69 | static void putWday(uint8_t data); 70 | static void putHour(uint8_t data); 71 | static void putMinute(uint8_t data); 72 | static void putSecond(uint8_t data); 73 | static void putNvRam(uint8_t data, uint8_t w_addr); 74 | static void putControlHandler(uint8_t data); 75 | static void getControlHandler(uint8_t* val); 76 | static void getYear(uint8_t* data); 77 | static void getMonth(uint8_t *data); 78 | static void getMday(uint8_t *data); 79 | static void getWday(uint8_t *data); 80 | static void getHour(uint8_t *data); 81 | static void getMinute(uint8_t *data); 82 | static void getSecond(uint8_t *data); 83 | static void getNvRam(uint8_t *data, uint8_t w_addr); 84 | }; 85 | 86 | extern DS1307emulator DS1307Emulator; 87 | 88 | #endif /* RTC_PROTOCOL_H_ */ 89 | -------------------------------------------------------------------------------- /src/utility/rtc_hal.c: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright (c) 2016 Enrico Sanino 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in all 13 | //copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | //SOFTWARE. 22 | 23 | 24 | 25 | /* Requires a timer library and i2c library */ 26 | 27 | #include "Arduino.h" 28 | 29 | #include "rtc_hal.h" 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | enum {RTC_INT_ON, RTC_INT_OFF}; 37 | 38 | 39 | 40 | void rtcHal_init(uint8_t pin) 41 | { 42 | /* For better accuracy, use a timer that allow to use a 32768Hz crystal. 43 | If not available, you should use the higher resolution timer with the lower prescaler value */ 44 | /* With Arduno board, 16MHz and prescaler 256 with 16bit Timer1, introduces error of 16ppm over the 16MHz osc ppm error */ 45 | 46 | rtcHal_setRtcTick(); 47 | rtcHal_setDefaultPin(pin); 48 | } 49 | 50 | void rtcHal_setRtcTick(void) 51 | { 52 | /* source at 32768Hz */ 53 | //initTimer2(64, NORMAL, INT_ON, TMR_EXT_CRY); 54 | //uint16_t comp = ((F_CPU)/256)-1; 55 | initCompare1(31249, COMP_A_DISCONNECT, 256, TMR_CLK_RISE, CLKOSC, TIMER_INT_ON); 56 | } 57 | 58 | void rtcHal_setDefaultPin(uint8_t pin) 59 | { 60 | pinMode(pin, OUTPUT); 61 | digitalWrite(pin, LOW); 62 | } 63 | 64 | /* La user chiama questa */ 65 | /* Ricorda le API per l'uso interno al programma.. mettile in RTC PROTOCOL */ 66 | 67 | 68 | void rtcHal_resetRtcTick(void) 69 | { 70 | writeTimer1(0); 71 | } 72 | 73 | void rtcHal_startRtcTick(void) 74 | { 75 | // rtcHal_resetRtcTick(); // riparto allineato 76 | startTimer1(); 77 | } 78 | 79 | void rtcHal_stopRtcTick(void) 80 | { 81 | stopTimer1(); 82 | } 83 | 84 | 85 | 86 | void rtcHal_resetPinDigitalMode(uint8_t pin) 87 | { 88 | pinMode(pin, INPUT); 89 | } 90 | 91 | void rtcHal_setPinDigitalMode(uint8_t pin) 92 | { 93 | pinMode(pin, OUTPUT); 94 | } 95 | 96 | void rtcHal_setPinDigitalValue(uint8_t pin, uint8_t value) 97 | { 98 | if (value) 99 | { 100 | digitalWrite(pin, HIGH); 101 | } 102 | else 103 | { 104 | digitalWrite(pin, LOW); 105 | } 106 | 107 | } 108 | #ifdef __cplusplus 109 | } 110 | #endif -------------------------------------------------------------------------------- /src/utility/rtc_hal.h: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright (c) 2016 Enrico Sanino 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in all 13 | //copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | //SOFTWARE. 22 | 23 | 24 | #ifndef DS_APPLICATION_H 25 | #define DS_APPLICATION_H 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" 31 | { 32 | #endif 33 | 34 | #include "timers.h" 35 | 36 | void rtcHal_setPinDigitalValue(uint8_t val, uint8_t value); 37 | void rtcHal_setPinDigitalMode(uint8_t); 38 | void rtcHal_resetPinDigitalMode(uint8_t); 39 | void rtcHal_stopRtcTick(void); 40 | void rtcHal_startRtcTick(void); 41 | void rtcHal_resetRtcTick(void); 42 | void rtcHal_setDefaultPin(uint8_t); 43 | void rtcHal_setRtcTick(void); 44 | void rtcHal_init(uint8_t); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif /* DS_APPLICATION_H */ 51 | 52 | -------------------------------------------------------------------------------- /src/utility/timers.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thexeno/DS1307-Emulator-Arduino-Library/d058bbe8720179d3224b60c1b6d21bc59b23579a/src/utility/timers.c -------------------------------------------------------------------------------- /src/utility/timers.h: -------------------------------------------------------------------------------- 1 | /* The MIT License (MIT) 2 | * Copyright (c) 2015 Enrico Sanino 3 | * File: timers.h 4 | * Author: Enrico Sanino 5 | * 6 | * Created on 28 febbraio 2015, 18.42 7 | */ 8 | 9 | #ifndef TIMERS_H 10 | #define TIMERS_H 11 | 12 | #include "avr/io.h" 13 | #include "avr/interrupt.h" 14 | 15 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 16 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 17 | 18 | typedef enum {CLKPIN, CLKOSC, CLKINST} _t_timer_clock; 19 | enum {TIMER_INT_OFF, TIMER_INT_ON}; 20 | 21 | typedef enum {TMR_CLK_RISE, TMR_CLK_FALL} _t_edge; 22 | typedef enum 23 | { 24 | COMP_A_TOGGLE, 25 | COMP_A_CLEAR, 26 | COMP_A_SET, 27 | COMP_B_TOGGLE, 28 | COMP_B_CLEAR, 29 | COMP_B_SET, 30 | COMP_A_DISCONNECT, 31 | COMP_B_DISCONNECT 32 | } _t_compare_sel; 33 | 34 | 35 | typedef enum 36 | { 37 | TIMER_MODE_NORMAL, 38 | TIMER_MODE_PWM, 39 | TIMER_MODE_COMPARE_MATCH, 40 | TIMER_MODE_FAST_PWM 41 | } _t_timer_mode; 42 | 43 | 44 | 45 | 46 | void initTimer1(uint16_t prescaler, _t_edge edge, _t_timer_mode mode , _t_timer_clock clock, uint8_t timer_int ); 47 | void startTimer1(); 48 | void stopTimer1(); 49 | 50 | void initCompare1 (uint16_t comp_val, _t_compare_sel comp, uint16_t prescaler, _t_edge edge, _t_timer_clock clock, uint8_t timer_int); 51 | void writeTimer1(uint16_t value); 52 | 53 | 54 | 55 | #endif /* TIMERS_H */ 56 | 57 | --------------------------------------------------------------------------------