├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md └── workflows │ ├── stale.yml │ └── sync_issues.yml ├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── examples ├── alarm_samd21 │ └── alarm_samd21.ino ├── alarm_samd51 │ └── alarm_samd51.ino ├── rtc_samd21 │ └── rtc_samd21.ino └── rtc_samd51 │ └── rtc_samd51.ino ├── keywords.txt ├── library.properties └── src ├── DateTime.cpp ├── DateTime.h ├── RTC_SAMD21.cpp ├── RTC_SAMD21.h ├── RTC_SAMD51.cpp └── RTC_SAMD51.h /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 4 * * *' 7 | 8 | jobs: 9 | stale: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Checkout script repository 17 | uses: actions/checkout@v4 18 | with: 19 | repository: Seeed-Studio/sync-github-all-issues 20 | path: ci 21 | 22 | - name: Run script 23 | run: ./ci/tools/stale.sh 24 | env: 25 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.github/workflows/sync_issues.yml: -------------------------------------------------------------------------------- 1 | name: Automate Issue Management 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - edited 8 | - assigned 9 | - unassigned 10 | - labeled 11 | - unlabeled 12 | - reopened 13 | 14 | jobs: 15 | add_issue_to_project: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Add issue to GitHub Project 19 | uses: actions/add-to-project@v1.0.2 20 | with: 21 | project-url: https://github.com/orgs/Seeed-Studio/projects/17 22 | github-token: ${{ secrets.ISSUE_ASSEMBLE }} 23 | labeled: bug 24 | label-operator: NOT -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | dist: bionic 3 | sudo: false 4 | cache: 5 | directories: 6 | - ~/arduino_ide 7 | - ~/.arduino15/packages/ 8 | 9 | before_install: 10 | - wget -c https://files.seeedstudio.com/arduino/seeed-arduino-ci.sh 11 | script: 12 | - chmod +x seeed-arduino-ci.sh 13 | - cat $PWD/seeed-arduino-ci.sh 14 | - $PWD/seeed-arduino-ci.sh -b "Seeeduino:samd:seeed_wio_terminal" -s rtc_samd51/alarm_samd51 15 | - $PWD/seeed-arduino-ci.sh -b "Seeeduino:samd:seeed_XIAO_m0" -s rtc_samd21/alarm_samd21 16 | 17 | notifications: 18 | email: 19 | on_success: change 20 | on_failure: change 21 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at zuobaozhu@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing guidelines 2 | 3 | All guidelines for contributing to the Seeed_Arduino_RTC repository can be found at [`How to contribute guideline`](https://github.com/Seeed-Studio/Seeed_Arduino_RTC/wiki/How_to_contribute). 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Seeed Studio 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Seeed_Arduino_RTC [![Build Status](https://travis-ci.com/Seeed-Studio/Seeed_Arduino_RTC.svg?branch=master)](https://travis-ci.com/Seeed-Studio/Seeed_Arduino_RTC) 2 | ## Introduction 3 | Seeed Arduino RTC is a Arduino library for RTC Moudle. At present, samd21 is supported and samd51 has built-in RTC module. 4 | ## How to install Arduino Library 5 | please refer [here](https://wiki.seeedstudio.com/How_to_install_Arduino_Library/). 6 | 7 | ## Usage 8 | 9 | ```C++ 10 | #include "RTC_SAMD21.h" 11 | #include "DateTime.h" 12 | 13 | RTC_SAMD21 rtc; 14 | void setup() 15 | { 16 | rtc.begin(); 17 | 18 | Serial.begin(115200); 19 | 20 | while (!Serial) 21 | { 22 | ; 23 | } 24 | 25 | DateTime now = DateTime(F(__DATE__), F(__TIME__)); 26 | Serial.println("adjust time!"); 27 | rtc.adjust(now); 28 | 29 | now = rtc.now(); 30 | 31 | Serial.print(now.year(), DEC); 32 | Serial.print('/'); 33 | Serial.print(now.month(), DEC); 34 | Serial.print('/'); 35 | Serial.print(now.day(), DEC); 36 | Serial.print(" "); 37 | Serial.print(now.hour(), DEC); 38 | Serial.print(':'); 39 | Serial.print(now.minute(), DEC); 40 | Serial.print(':'); 41 | Serial.print(now.second(), DEC); 42 | Serial.println(); 43 | 44 | } 45 | void loop() 46 | { 47 | now = rtc.now(); 48 | 49 | Serial.print(now.year(), DEC); 50 | Serial.print('/'); 51 | Serial.print(now.month(), DEC); 52 | Serial.print('/'); 53 | Serial.print(now.day(), DEC); 54 | Serial.print(" "); 55 | Serial.print(now.hour(), DEC); 56 | Serial.print(':'); 57 | Serial.print(now.minute(), DEC); 58 | Serial.print(':'); 59 | Serial.print(now.second(), DEC); 60 | Serial.println(); 61 | 62 | } 63 | 64 | ``` 65 | 66 | ## API Reference 67 | - **begin(*void*) : bool** 68 | ```C++ 69 | rtc.begin() 70 | ``` 71 | - **now(*void*) : DateTime** 72 | ```C++ 73 | DateTime now = rtc.now(); 74 | ``` 75 | - **adjust(*const DateTime*) : void** 76 | ```C++ 77 | DateTime now = DateTime(F(__DATE__), F(__TIME__)); 78 | rtc.adjust(now); 79 | DateTime now = DateTime(2020, 7, 15, 0, 0, 0); 80 | rtc.adjust(now); 81 | ``` 82 | - **setAlarm(*const DateTime*) : void** 83 | ```C++ 84 | DateTime alarm = DateTime(2020, 7, 15, 18, 0, 0); 85 | rtc.setAlarm(now); 86 | ``` 87 | - **alarm(*void*) : DateTime** 88 | ```C++ 89 | DateTime now = rtc.alarm(); 90 | ``` 91 | - **disableAlarm(*uint8_t*) : void** 92 | ```C++ 93 | rtc.disableAlarm(0); 94 | ``` 95 | - **enableAlarm(*uint8_t*) : void** 96 | ```C++ 97 | rtc.enableAlarm(0); 98 | ``` 99 | - **attachInterrupt(*rtcCallBack*) : void** 100 | ```C++ 101 | rtc.attachInterrupt(rtcCallBack); 102 | ``` 103 | - **detachInterrupt(*void*) : void** 104 | ```C++ 105 | rtc.detachInterrupt(); 106 | ``` 107 | 108 | ---- 109 | ## License 110 | This software is written by seeed studio
111 | and is licensed under [The MIT License](http://opensource.org/licenses/mit-license.php). Check License.txt for more information.
112 | 113 | Contributing to this software is warmly welcomed. You can do this basically by
114 | [forking](https://help.github.com/articles/fork-a-repo), committing modifications and then [pulling requests](https://help.github.com/articles/using-pull-requests) (follow the links above
115 | for operating guide). Adding change log and your contact into file header is encouraged.
116 | Thanks for your contribution. 117 | 118 | Seeed Studio is an open hardware facilitation company based in Shenzhen, China.
119 | Benefiting from local manufacture power and convenient global logistic system,
120 | we integrate resources to serve new era of innovation. Seeed also works with
121 | global distributors and partners to push open hardware movement.
-------------------------------------------------------------------------------- /examples/alarm_samd21/alarm_samd21.ino: -------------------------------------------------------------------------------- 1 | #include "RTC_SAMD21.h" 2 | #include "DateTime.h" 3 | 4 | RTC_SAMD21 rtc; 5 | void setup() 6 | { 7 | rtc.begin(); 8 | 9 | Serial.begin(115200); 10 | 11 | while (!Serial) 12 | { 13 | ; 14 | } 15 | 16 | 17 | DateTime now = DateTime(F(__DATE__), F(__TIME__)); 18 | 19 | //!!! notice The year is limited to 2000-2099 20 | Serial.println("adjust time!"); 21 | rtc.adjust(now); 22 | 23 | now = rtc.now(); 24 | 25 | Serial.print(now.year(), DEC); 26 | Serial.print('/'); 27 | Serial.print(now.month(), DEC); 28 | Serial.print('/'); 29 | Serial.print(now.day(), DEC); 30 | Serial.print(" "); 31 | Serial.print(now.hour(), DEC); 32 | Serial.print(':'); 33 | Serial.print(now.minute(), DEC); 34 | Serial.print(':'); 35 | Serial.print(now.second(), DEC); 36 | Serial.println(); 37 | 38 | DateTime alarm = DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second() + 15); 39 | 40 | rtc.setAlarm(alarm); // match after 15 seconds 41 | rtc.enableAlarm(rtc.MATCH_HHMMSS); // match Every Day 42 | 43 | rtc.attachInterrupt(alarmMatch); // callback while alarm is match 44 | 45 | } 46 | 47 | void loop() 48 | { 49 | } 50 | 51 | void alarmMatch() 52 | { 53 | 54 | Serial.println("Alarm Match!"); 55 | DateTime now = rtc.now(); 56 | Serial.print(now.year(), DEC); 57 | Serial.print('/'); 58 | Serial.print(now.month(), DEC); 59 | Serial.print('/'); 60 | Serial.print(now.day(), DEC); 61 | Serial.print(" "); 62 | Serial.print(now.hour(), DEC); 63 | Serial.print(':'); 64 | Serial.print(now.minute(), DEC); 65 | Serial.print(':'); 66 | Serial.print(now.second(), DEC); 67 | Serial.println(); 68 | } 69 | -------------------------------------------------------------------------------- /examples/alarm_samd51/alarm_samd51.ino: -------------------------------------------------------------------------------- 1 | #include "RTC_SAMD51.h" 2 | #include "DateTime.h" 3 | 4 | RTC_SAMD51 rtc; 5 | void setup() 6 | { 7 | rtc.begin(); 8 | 9 | Serial.begin(115200); 10 | 11 | while (!Serial) 12 | { 13 | ; 14 | } 15 | 16 | 17 | DateTime now = DateTime(F(__DATE__), F(__TIME__)); 18 | 19 | //!!! notice The year is limited to 2000-2099 20 | Serial.println("adjust time!"); 21 | rtc.adjust(now); 22 | 23 | now = rtc.now(); 24 | 25 | Serial.print(now.year(), DEC); 26 | Serial.print('/'); 27 | Serial.print(now.month(), DEC); 28 | Serial.print('/'); 29 | Serial.print(now.day(), DEC); 30 | Serial.print(" "); 31 | Serial.print(now.hour(), DEC); 32 | Serial.print(':'); 33 | Serial.print(now.minute(), DEC); 34 | Serial.print(':'); 35 | Serial.print(now.second(), DEC); 36 | Serial.println(); 37 | 38 | DateTime alarm = DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second() + 15); 39 | 40 | rtc.setAlarm(0,alarm); // match after 15 seconds 41 | rtc.enableAlarm(0, rtc.MATCH_HHMMSS); // match Every Day 42 | 43 | rtc.attachInterrupt(alarmMatch); // callback while alarm is match 44 | 45 | } 46 | 47 | void loop() 48 | { 49 | } 50 | 51 | void alarmMatch(uint32_t flag) 52 | { 53 | 54 | Serial.println("Alarm Match!"); 55 | DateTime now = rtc.now(); 56 | Serial.print(now.year(), DEC); 57 | Serial.print('/'); 58 | Serial.print(now.month(), DEC); 59 | Serial.print('/'); 60 | Serial.print(now.day(), DEC); 61 | Serial.print(" "); 62 | Serial.print(now.hour(), DEC); 63 | Serial.print(':'); 64 | Serial.print(now.minute(), DEC); 65 | Serial.print(':'); 66 | Serial.print(now.second(), DEC); 67 | Serial.println(); 68 | } 69 | -------------------------------------------------------------------------------- /examples/rtc_samd21/rtc_samd21.ino: -------------------------------------------------------------------------------- 1 | #include "RTC_SAMD21.h" 2 | #include "DateTime.h" 3 | 4 | RTC_SAMD21 rtc; 5 | char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 6 | void setup() 7 | { 8 | Serial.begin(115200); 9 | rtc.begin(); 10 | 11 | DateTime now = DateTime(F(__DATE__), F(__TIME__)); 12 | //!!! notice The year is limited to 2000-2099 13 | Serial.println("adjust time!"); 14 | rtc.adjust(now); 15 | 16 | } 17 | 18 | void loop() 19 | { 20 | 21 | DateTime now = rtc.now(); 22 | 23 | Serial.print(now.year(), DEC); 24 | Serial.print('/'); 25 | Serial.print(now.month(), DEC); 26 | Serial.print('/'); 27 | Serial.print(now.day(), DEC); 28 | 29 | Serial.print(" ("); 30 | Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); 31 | Serial.print(") "); 32 | Serial.print(now.hour(), DEC); 33 | Serial.print(':'); 34 | Serial.print(now.minute(), DEC); 35 | Serial.print(':'); 36 | Serial.print(now.second(), DEC); 37 | Serial.println(); 38 | 39 | Serial.print(" since midnight 1/1/1970 = "); 40 | Serial.print(now.unixtime()); 41 | Serial.print("s = "); 42 | Serial.print(now.unixtime() / 86400L); 43 | Serial.println("d"); 44 | 45 | // calculate a date which is 7 days, 12 hours, 30 minutes, and 6 seconds into the future 46 | DateTime future(now + TimeSpan(7, 12, 30, 6)); 47 | 48 | Serial.print(" now + 7d + 12h + 30m + 6s: "); 49 | Serial.print(future.year(), DEC); 50 | Serial.print('/'); 51 | Serial.print(future.month(), DEC); 52 | Serial.print('/'); 53 | Serial.print(future.day(), DEC); 54 | Serial.print(' '); 55 | Serial.print(future.hour(), DEC); 56 | Serial.print(':'); 57 | Serial.print(future.minute(), DEC); 58 | Serial.print(':'); 59 | Serial.print(future.second(), DEC); 60 | Serial.println(); 61 | 62 | Serial.println(); 63 | delay(1000); 64 | } 65 | -------------------------------------------------------------------------------- /examples/rtc_samd51/rtc_samd51.ino: -------------------------------------------------------------------------------- 1 | #include "RTC_SAMD51.h" 2 | #include "DateTime.h" 3 | 4 | RTC_SAMD51 rtc; 5 | char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 6 | void setup() 7 | { 8 | Serial.begin(115200); 9 | rtc.begin(); 10 | 11 | DateTime now = DateTime(F(__DATE__), F(__TIME__)); 12 | //!!! notice The year is limited to 2000-2099 13 | Serial.println("adjust time!"); 14 | rtc.adjust(now); 15 | 16 | } 17 | 18 | void loop() 19 | { 20 | 21 | DateTime now = rtc.now(); 22 | 23 | Serial.print(now.year(), DEC); 24 | Serial.print('/'); 25 | Serial.print(now.month(), DEC); 26 | Serial.print('/'); 27 | Serial.print(now.day(), DEC); 28 | 29 | Serial.print(" ("); 30 | Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); 31 | Serial.print(") "); 32 | Serial.print(now.hour(), DEC); 33 | Serial.print(':'); 34 | Serial.print(now.minute(), DEC); 35 | Serial.print(':'); 36 | Serial.print(now.second(), DEC); 37 | Serial.println(); 38 | 39 | Serial.print(" since midnight 1/1/1970 = "); 40 | Serial.print(now.unixtime()); 41 | Serial.print("s = "); 42 | Serial.print(now.unixtime() / 86400L); 43 | Serial.println("d"); 44 | 45 | // calculate a date which is 7 days, 12 hours, 30 minutes, and 6 seconds into the future 46 | DateTime future(now + TimeSpan(7, 12, 30, 6)); 47 | 48 | Serial.print(" now + 7d + 12h + 30m + 6s: "); 49 | Serial.print(future.year(), DEC); 50 | Serial.print('/'); 51 | Serial.print(future.month(), DEC); 52 | Serial.print('/'); 53 | Serial.print(future.day(), DEC); 54 | Serial.print(' '); 55 | Serial.print(future.hour(), DEC); 56 | Serial.print(':'); 57 | Serial.print(future.minute(), DEC); 58 | Serial.print(':'); 59 | Serial.print(future.second(), DEC); 60 | Serial.println(); 61 | 62 | Serial.println(); 63 | delay(1000); 64 | } -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Seeed Arduino RTC 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | DateTime KEYWORD1 10 | TimeSpan KEYWORD1 11 | RTC_SAMD21 KEYWORD1 12 | RTC_SAMD51 KEYWORD1 13 | 14 | 15 | ####################################### 16 | # Methods and Functions (KEYWORD2) 17 | ####################################### 18 | 19 | year KEYWORD2 20 | month KEYWORD2 21 | day KEYWORD2 22 | hour KEYWORD2 23 | twelveHour KEYWORD2 24 | isPM KEYWORD2 25 | minute KEYWORD2 26 | second KEYWORD2 27 | dayOfTheWeek KEYWORD2 28 | secondstime KEYWORD2 29 | unixtime KEYWORD2 30 | days KEYWORD2 31 | hours KEYWORD2 32 | minutes KEYWORD2 33 | seconds KEYWORD2 34 | totalseconds KEYWORD2 35 | begin KEYWORD2 36 | adjust KEYWORD2 37 | now KEYWORD2 38 | timestamp KEYWORD2 39 | toString KEYWORD2 40 | writenvram KEYWORD2 41 | setAlarm KEYWORD2 42 | disableAlarm KEYWORD2 43 | 44 | ####################################### 45 | # Constants (LITERAL1) 46 | ####################################### 47 | TIMESTAMP_FULL LITERAL1 48 | TIMESTAMP_DATE LITERAL1 49 | TIMESTAMP_TIME LITERAL1 50 | 51 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Seeed Arduino RTC 2 | version=2.0.0 3 | author=Seeed Studio 4 | maintainer=Seeed Studio 5 | sentence=RTC library for SAMD21 and SAMD51. 6 | paragraph=When your project needs to be unplugged, how to keep the time counting? This library can help you keep the current time 7 | category=Timing 8 | url=https://github.com/Seeed-Studio/Seeed_Arduino_RTC 9 | architectures=samd 10 | -------------------------------------------------------------------------------- /src/DateTime.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file RTClib.h 4 | Original library by JeeLabs http://news.jeelabs.org/code/, released to the 5 | public domain 6 | License: MIT (see LICENSE) 7 | This is a fork of JeeLab's fantastic real time clock library for Arduino. 8 | For details on using this library with an RTC module like the DS1307, PCF8523, 9 | or DS3231, see the guide at: 10 | https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview 11 | Adafruit invests time and resources providing this open source code, 12 | please support Adafruit and open-source hardware by purchasing 13 | products from Adafruit! 14 | */ 15 | /**************************************************************************/ 16 | 17 | 18 | #include "DateTime.h" 19 | 20 | 21 | /** 22 | Number of days in each month, from January to November. December is not 23 | needed. Omitting it avoids an incompatibility with Paul Stoffregen's Time 24 | library. C.f. https://github.com/adafruit/RTClib/issues/114 25 | */ 26 | static const uint8_t daysInMonth[] PROGMEM = {31, 28, 31, 30, 31, 30, 27 | 31, 31, 30, 31, 30}; 28 | 29 | /**************************************************************************/ 30 | /*! 31 | @brief Given a date, return number of days since 2000/01/01, 32 | valid for 2000--2099 33 | @param y Year 34 | @param m Month 35 | @param d Day 36 | @return Number of days 37 | */ 38 | /**************************************************************************/ 39 | static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) { 40 | if (y >= 2000) 41 | y -= 2000; 42 | uint16_t days = d; 43 | for (uint8_t i = 1; i < m; ++i) 44 | days += pgm_read_byte(daysInMonth + i - 1); 45 | if (m > 2 && y % 4 == 0) 46 | ++days; 47 | return days + 365 * y + (y + 3) / 4 - 1; 48 | } 49 | 50 | /**************************************************************************/ 51 | /*! 52 | @brief Given a number of days, hours, minutes, and seconds, return the 53 | total seconds 54 | @param days Days 55 | @param h Hours 56 | @param m Minutes 57 | @param s Seconds 58 | @return Number of seconds total 59 | */ 60 | /**************************************************************************/ 61 | static uint32_t time2ulong(uint16_t days, uint8_t h, uint8_t m, uint8_t s) { 62 | return ((days * 24UL + h) * 60 + m) * 60 + s; 63 | } 64 | 65 | 66 | /**************************************************************************/ 67 | /*! 68 | @brief Constructor from 69 | [Unix time](https://en.wikipedia.org/wiki/Unix_time). 70 | This builds a DateTime from an integer specifying the number of seconds 71 | elapsed since the epoch: 1970-01-01 00:00:00. This number is analogous 72 | to Unix time, with two small differences: 73 | - The Unix epoch is specified to be at 00:00:00 74 | [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time), 75 | whereas this class has no notion of time zones. The epoch used in 76 | this class is then at 00:00:00 on whatever time zone the user chooses 77 | to use, ignoring changes in DST. 78 | - Unix time is conventionally represented with signed numbers, whereas 79 | this constructor takes an unsigned argument. Because of this, it does 80 | _not_ suffer from the 81 | [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem). 82 | If called without argument, it returns the earliest time representable 83 | by this class: 2000-01-01 00:00:00. 84 | @see The `unixtime()` method is the converse of this constructor. 85 | @param t Time elapsed in seconds since 1970-01-01 00:00:00. 86 | */ 87 | /**************************************************************************/ 88 | DateTime::DateTime(uint32_t t) { 89 | t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970 90 | 91 | ss = t % 60; 92 | t /= 60; 93 | mm = t % 60; 94 | t /= 60; 95 | hh = t % 24; 96 | uint16_t days = t / 24; 97 | uint8_t leap; 98 | for (yOff = 0;; ++yOff) { 99 | leap = yOff % 4 == 0; 100 | if (days < 365U + leap) 101 | break; 102 | days -= 365 + leap; 103 | } 104 | for (m = 1; m < 12; ++m) { 105 | uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1); 106 | if (leap && m == 2) 107 | ++daysPerMonth; 108 | if (days < daysPerMonth) 109 | break; 110 | days -= daysPerMonth; 111 | } 112 | d = days + 1; 113 | } 114 | 115 | /**************************************************************************/ 116 | /*! 117 | @brief Constructor from (year, month, day, hour, minute, second). 118 | @warning If the provided parameters are not valid (e.g. 31 February), 119 | the constructed DateTime will be invalid. 120 | @see The `isValid()` method can be used to test whether the 121 | constructed DateTime is valid. 122 | @param year Either the full year (range: 2000--2099) or the offset from 123 | year 2000 (range: 0--99). 124 | @param month Month number (1--12). 125 | @param day Day of the month (1--31). 126 | @param hour,min,sec Hour (0--23), minute (0--59) and second (0--59). 127 | */ 128 | /**************************************************************************/ 129 | DateTime::DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, 130 | uint8_t min, uint8_t sec) { 131 | if (year >= 2000) 132 | year -= 2000; 133 | yOff = year; 134 | m = month; 135 | d = day; 136 | hh = hour; 137 | mm = min; 138 | ss = sec; 139 | } 140 | 141 | /**************************************************************************/ 142 | /*! 143 | @brief Copy constructor. 144 | @param copy DateTime to copy. 145 | */ 146 | /**************************************************************************/ 147 | DateTime::DateTime(const DateTime ©) 148 | : yOff(copy.yOff), m(copy.m), d(copy.d), hh(copy.hh), mm(copy.mm), 149 | ss(copy.ss) {} 150 | 151 | 152 | /**************************************************************************/ 153 | /*! 154 | @brief Convert a string containing two digits to uint8_t, e.g. "09" returns 155 | 9 156 | @param p Pointer to a string containing two digits 157 | */ 158 | /**************************************************************************/ 159 | static uint8_t conv2d(const char *p) { 160 | uint8_t v = 0; 161 | if ('0' <= *p && *p <= '9') 162 | v = *p - '0'; 163 | return 10 * v + *++p - '0'; 164 | } 165 | 166 | /**************************************************************************/ 167 | /*! 168 | @brief Constructor for generating the build time. 169 | This constructor expects its parameters to be strings in the format 170 | generated by the compiler's preprocessor macros `__DATE__` and 171 | `__TIME__`. Usage: 172 | ``` 173 | DateTime buildTime(__DATE__, __TIME__); 174 | ``` 175 | @note The `F()` macro can be used to reduce the RAM footprint, see 176 | the next constructor. 177 | @param date Date string, e.g. "Apr 16 2020". 178 | @param time Time string, e.g. "18:34:56". 179 | */ 180 | /**************************************************************************/ 181 | DateTime::DateTime(const char *date, const char *time) { 182 | yOff = conv2d(date + 9); 183 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 184 | switch (date[0]) { 185 | case 'J': 186 | m = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7); 187 | break; 188 | case 'F': 189 | m = 2; 190 | break; 191 | case 'A': 192 | m = date[2] == 'r' ? 4 : 8; 193 | break; 194 | case 'M': 195 | m = date[2] == 'r' ? 3 : 5; 196 | break; 197 | case 'S': 198 | m = 9; 199 | break; 200 | case 'O': 201 | m = 10; 202 | break; 203 | case 'N': 204 | m = 11; 205 | break; 206 | case 'D': 207 | m = 12; 208 | break; 209 | } 210 | d = conv2d(date + 4); 211 | hh = conv2d(time); 212 | mm = conv2d(time + 3); 213 | ss = conv2d(time + 6); 214 | } 215 | 216 | /**************************************************************************/ 217 | /*! 218 | @brief Memory friendly constructor for generating the build time. 219 | This version is intended to save RAM by keeping the date and time 220 | strings in program memory. Use it with the `F()` macro: 221 | ``` 222 | DateTime buildTime(F(__DATE__), F(__TIME__)); 223 | ``` 224 | @param date Date PROGMEM string, e.g. F("Apr 16 2020"). 225 | @param time Time PROGMEM string, e.g. F("18:34:56"). 226 | */ 227 | /**************************************************************************/ 228 | DateTime::DateTime(const __FlashStringHelper *date, 229 | const __FlashStringHelper *time) { 230 | char buff[11]; 231 | memcpy_P(buff, date, 11); 232 | yOff = conv2d(buff + 9); 233 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 234 | switch (buff[0]) { 235 | case 'J': 236 | m = (buff[1] == 'a') ? 1 : ((buff[2] == 'n') ? 6 : 7); 237 | break; 238 | case 'F': 239 | m = 2; 240 | break; 241 | case 'A': 242 | m = buff[2] == 'r' ? 4 : 8; 243 | break; 244 | case 'M': 245 | m = buff[2] == 'r' ? 3 : 5; 246 | break; 247 | case 'S': 248 | m = 9; 249 | break; 250 | case 'O': 251 | m = 10; 252 | break; 253 | case 'N': 254 | m = 11; 255 | break; 256 | case 'D': 257 | m = 12; 258 | break; 259 | } 260 | d = conv2d(buff + 4); 261 | memcpy_P(buff, time, 8); 262 | hh = conv2d(buff); 263 | mm = conv2d(buff + 3); 264 | ss = conv2d(buff + 6); 265 | } 266 | 267 | /**************************************************************************/ 268 | /*! 269 | @brief Constructor for creating a DateTime from an ISO8601 date string. 270 | This constructor expects its parameters to be a string in the 271 | https://en.wikipedia.org/wiki/ISO_8601 format, e.g: 272 | "2020-06-25T15:29:37" 273 | Usage: 274 | ``` 275 | DateTime dt("2020-06-25T15:29:37"); 276 | ``` 277 | @note The year must be > 2000, as only the yOff is considered. 278 | @param iso8601dateTime 279 | A dateTime string in iso8601 format, 280 | e.g. "2020-06-25T15:29:37". 281 | */ 282 | /**************************************************************************/ 283 | DateTime::DateTime(const char *iso8601dateTime) { 284 | char ref[] = "2000-01-01T00:00:00"; 285 | memcpy(ref, iso8601dateTime, min(strlen(ref), strlen(iso8601dateTime))); 286 | yOff = conv2d(ref + 2); 287 | m = conv2d(ref + 5); 288 | d = conv2d(ref + 8); 289 | hh = conv2d(ref + 11); 290 | mm = conv2d(ref + 14); 291 | ss = conv2d(ref + 17); 292 | } 293 | 294 | /**************************************************************************/ 295 | /*! 296 | @brief Check whether this DateTime is valid. 297 | @return true if valid, false if not. 298 | */ 299 | /**************************************************************************/ 300 | bool DateTime::isValid() const { 301 | if (yOff >= 100) 302 | return false; 303 | DateTime other(unixtime()); 304 | return yOff == other.yOff && m == other.m && d == other.d && hh == other.hh && 305 | mm == other.mm && ss == other.ss; 306 | } 307 | 308 | /**************************************************************************/ 309 | /*! 310 | @brief Writes the DateTime as a string in a user-defined format. 311 | The _buffer_ parameter should be initialized by the caller with a string 312 | specifying the requested format. This format string may contain any of 313 | the following specifiers: 314 | | specifier | output | 315 | |-----------|--------------------------------------------------------| 316 | | YYYY | the year as a 4-digit number (2000--2099) | 317 | | YY | the year as a 2-digit number (00--99) | 318 | | MM | the month as a 2-digit number (01--12) | 319 | | MMM | the abbreviated English month name ("Jan"--"Dec") | 320 | | DD | the day as a 2-digit number (01--31) | 321 | | DDD | the abbreviated English day of the week ("Mon"--"Sun") | 322 | | AP | either "AM" or "PM" | 323 | | ap | either "am" or "pm" | 324 | | hh | the hour as a 2-digit number (00--23 or 01--12) | 325 | | mm | the minute as a 2-digit number (00--59) | 326 | | ss | the second as a 2-digit number (00--59) | 327 | If either "AP" or "ap" is used, the "hh" specifier uses 12-hour mode 328 | (range: 01--12). Otherwise it works in 24-hour mode (range: 00--23). 329 | The specifiers within _buffer_ will be overwritten with the appropriate 330 | values from the DateTime. Any characters not belonging to one of the 331 | above specifiers are left as-is. 332 | __Example__: The format "DDD, DD MMM YYYY hh:mm:ss" generates an output 333 | of the form "Thu, 16 Apr 2020 18:34:56. 334 | @see The `timestamp()` method provides similar functionnality, but it 335 | returns a `String` object and supports a limited choice of 336 | predefined formats. 337 | @param[in,out] buffer Array of `char` for holding the format description 338 | and the formatted DateTime. Before calling this method, the buffer 339 | should be initialized by the user with the format string. The method 340 | will overwrite the buffer with the formatted date and/or time. 341 | @return A pointer to the provided buffer. This is returned for 342 | convenience, in order to enable idioms such as 343 | `Serial.println(now.toString(buffer));` 344 | */ 345 | /**************************************************************************/ 346 | 347 | char *DateTime::toString(char *buffer) { 348 | uint8_t apTag = 349 | (strstr(buffer, "ap") != nullptr) || (strstr(buffer, "AP") != nullptr); 350 | uint8_t hourReformatted, isPM; 351 | if (apTag) { // 12 Hour Mode 352 | if (hh == 0) { // midnight 353 | isPM = false; 354 | hourReformatted = 12; 355 | } else if (hh == 12) { // noon 356 | isPM = true; 357 | hourReformatted = 12; 358 | } else if (hh < 12) { // morning 359 | isPM = false; 360 | hourReformatted = hh; 361 | } else { // 1 o'clock or after 362 | isPM = true; 363 | hourReformatted = hh - 12; 364 | } 365 | } 366 | 367 | for (size_t i = 0; i < strlen(buffer) - 1; i++) { 368 | if (buffer[i] == 'h' && buffer[i + 1] == 'h') { 369 | if (!apTag) { // 24 Hour Mode 370 | buffer[i] = '0' + hh / 10; 371 | buffer[i + 1] = '0' + hh % 10; 372 | } else { // 12 Hour Mode 373 | buffer[i] = '0' + hourReformatted / 10; 374 | buffer[i + 1] = '0' + hourReformatted % 10; 375 | } 376 | } 377 | if (buffer[i] == 'm' && buffer[i + 1] == 'm') { 378 | buffer[i] = '0' + mm / 10; 379 | buffer[i + 1] = '0' + mm % 10; 380 | } 381 | if (buffer[i] == 's' && buffer[i + 1] == 's') { 382 | buffer[i] = '0' + ss / 10; 383 | buffer[i + 1] = '0' + ss % 10; 384 | } 385 | if (buffer[i] == 'D' && buffer[i + 1] == 'D' && buffer[i + 2] == 'D') { 386 | static PROGMEM const char day_names[] = "SunMonTueWedThuFriSat"; 387 | const char *p = &day_names[3 * dayOfTheWeek()]; 388 | buffer[i] = pgm_read_byte(p); 389 | buffer[i + 1] = pgm_read_byte(p + 1); 390 | buffer[i + 2] = pgm_read_byte(p + 2); 391 | } else if (buffer[i] == 'D' && buffer[i + 1] == 'D') { 392 | buffer[i] = '0' + d / 10; 393 | buffer[i + 1] = '0' + d % 10; 394 | } 395 | if (buffer[i] == 'M' && buffer[i + 1] == 'M' && buffer[i + 2] == 'M') { 396 | static PROGMEM const char month_names[] = 397 | "JanFebMarAprMayJunJulAugSepOctNovDec"; 398 | const char *p = &month_names[3 * (m - 1)]; 399 | buffer[i] = pgm_read_byte(p); 400 | buffer[i + 1] = pgm_read_byte(p + 1); 401 | buffer[i + 2] = pgm_read_byte(p + 2); 402 | } else if (buffer[i] == 'M' && buffer[i + 1] == 'M') { 403 | buffer[i] = '0' + m / 10; 404 | buffer[i + 1] = '0' + m % 10; 405 | } 406 | if (buffer[i] == 'Y' && buffer[i + 1] == 'Y' && buffer[i + 2] == 'Y' && 407 | buffer[i + 3] == 'Y') { 408 | buffer[i] = '2'; 409 | buffer[i + 1] = '0'; 410 | buffer[i + 2] = '0' + (yOff / 10) % 10; 411 | buffer[i + 3] = '0' + yOff % 10; 412 | } else if (buffer[i] == 'Y' && buffer[i + 1] == 'Y') { 413 | buffer[i] = '0' + (yOff / 10) % 10; 414 | buffer[i + 1] = '0' + yOff % 10; 415 | } 416 | if (buffer[i] == 'A' && buffer[i + 1] == 'P') { 417 | if (isPM) { 418 | buffer[i] = 'P'; 419 | buffer[i + 1] = 'M'; 420 | } else { 421 | buffer[i] = 'A'; 422 | buffer[i + 1] = 'M'; 423 | } 424 | } else if (buffer[i] == 'a' && buffer[i + 1] == 'p') { 425 | if (isPM) { 426 | buffer[i] = 'p'; 427 | buffer[i + 1] = 'm'; 428 | } else { 429 | buffer[i] = 'a'; 430 | buffer[i + 1] = 'm'; 431 | } 432 | } 433 | } 434 | return buffer; 435 | } 436 | 437 | /**************************************************************************/ 438 | /*! 439 | @brief Return the hour in 12-hour format. 440 | @return Hour (1--12). 441 | */ 442 | /**************************************************************************/ 443 | uint8_t DateTime::twelveHour() const { 444 | if (hh == 0 || hh == 12) { // midnight or noon 445 | return 12; 446 | } else if (hh > 12) { // 1 o'clock or later 447 | return hh - 12; 448 | } else { // morning 449 | return hh; 450 | } 451 | } 452 | 453 | /**************************************************************************/ 454 | /*! 455 | @brief Return the day of the week. 456 | @return Day of week as an integer from 0 (Sunday) to 6 (Saturday). 457 | */ 458 | /**************************************************************************/ 459 | uint8_t DateTime::dayOfTheWeek() const { 460 | uint16_t day = date2days(yOff, m, d); 461 | return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6 462 | } 463 | 464 | /**************************************************************************/ 465 | /*! 466 | @brief Return Unix time: seconds since 1 Jan 1970. 467 | @see The `DateTime::DateTime(uint32_t)` constructor is the converse of 468 | this method. 469 | @return Number of seconds since 1970-01-01 00:00:00. 470 | */ 471 | /**************************************************************************/ 472 | uint32_t DateTime::unixtime(void) const { 473 | uint32_t t; 474 | uint16_t days = date2days(yOff, m, d); 475 | t = time2ulong(days, hh, mm, ss); 476 | t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000 477 | 478 | return t; 479 | } 480 | 481 | /**************************************************************************/ 482 | /*! 483 | @brief Convert the DateTime to seconds since 1 Jan 2000 484 | The result can be converted back to a DateTime with: 485 | ```cpp 486 | DateTime(SECONDS_FROM_1970_TO_2000 + value) 487 | ``` 488 | @return Number of seconds since 2000-01-01 00:00:00. 489 | */ 490 | /**************************************************************************/ 491 | uint32_t DateTime::secondstime(void) const { 492 | uint32_t t; 493 | uint16_t days = date2days(yOff, m, d); 494 | t = time2ulong(days, hh, mm, ss); 495 | return t; 496 | } 497 | 498 | /**************************************************************************/ 499 | /*! 500 | @brief Add a TimeSpan to the DateTime object 501 | @param span TimeSpan object 502 | @return New DateTime object with span added to it. 503 | */ 504 | /**************************************************************************/ 505 | DateTime DateTime::operator+(const TimeSpan &span) { 506 | return DateTime(unixtime() + span.totalseconds()); 507 | } 508 | 509 | /**************************************************************************/ 510 | /*! 511 | @brief Subtract a TimeSpan from the DateTime object 512 | @param span TimeSpan object 513 | @return New DateTime object with span subtracted from it. 514 | */ 515 | /**************************************************************************/ 516 | DateTime DateTime::operator-(const TimeSpan &span) { 517 | return DateTime(unixtime() - span.totalseconds()); 518 | } 519 | 520 | /**************************************************************************/ 521 | /*! 522 | @brief Subtract one DateTime from another 523 | @note Since a TimeSpan cannot be negative, the subtracted DateTime 524 | should be less (earlier) than or equal to the one it is 525 | subtracted from. 526 | @param right The DateTime object to subtract from self (the left object) 527 | @return TimeSpan of the difference between DateTimes. 528 | */ 529 | /**************************************************************************/ 530 | TimeSpan DateTime::operator-(const DateTime &right) { 531 | return TimeSpan(unixtime() - right.unixtime()); 532 | } 533 | 534 | /**************************************************************************/ 535 | /*! 536 | @brief Test if one DateTime is less (earlier) than another. 537 | @param right Comparison DateTime object 538 | @return True if the left DateTime is earlier than the right one, 539 | false otherwise. 540 | */ 541 | /**************************************************************************/ 542 | bool DateTime::operator<(const DateTime &right) const { 543 | return unixtime() < right.unixtime(); 544 | } 545 | 546 | /**************************************************************************/ 547 | /*! 548 | @brief Test if two DateTime objects are equal. 549 | @param right Comparison DateTime object 550 | @return True if both DateTime objects are the same, false otherwise. 551 | */ 552 | /**************************************************************************/ 553 | bool DateTime::operator==(const DateTime &right) const { 554 | return unixtime() == right.unixtime(); 555 | } 556 | 557 | /**************************************************************************/ 558 | /*! 559 | @brief Return a ISO 8601 timestamp as a `String` object. 560 | The generated timestamp conforms to one of the predefined, ISO 561 | 8601-compatible formats for representing the date (if _opt_ is 562 | `TIMESTAMP_DATE`), the time (`TIMESTAMP_TIME`), or both 563 | (`TIMESTAMP_FULL`). 564 | @see The `toString()` method provides more general string formatting. 565 | @param opt Format of the timestamp 566 | @return Timestamp string, e.g. "2020-04-16T18:34:56". 567 | */ 568 | /**************************************************************************/ 569 | String DateTime::timestamp(timestampOpt opt) { 570 | char buffer[20]; 571 | 572 | // Generate timestamp according to opt 573 | switch (opt) { 574 | case TIMESTAMP_TIME: 575 | // Only time 576 | sprintf(buffer, "%02d:%02d:%02d", hh, mm, ss); 577 | break; 578 | case TIMESTAMP_DATE: 579 | // Only date 580 | sprintf(buffer, "%d-%02d-%02d", 2000 + yOff, m, d); 581 | break; 582 | default: 583 | // Full 584 | sprintf(buffer, "%d-%02d-%02dT%02d:%02d:%02d", 2000 + yOff, m, d, hh, mm, 585 | ss); 586 | } 587 | return String(buffer); 588 | } 589 | 590 | /**************************************************************************/ 591 | /*! 592 | @brief Create a new TimeSpan object in seconds 593 | @param seconds Number of seconds 594 | */ 595 | /**************************************************************************/ 596 | TimeSpan::TimeSpan(int32_t seconds) : _seconds(seconds) {} 597 | 598 | /**************************************************************************/ 599 | /*! 600 | @brief Create a new TimeSpan object using a number of 601 | days/hours/minutes/seconds e.g. Make a TimeSpan of 3 hours and 45 minutes: 602 | new TimeSpan(0, 3, 45, 0); 603 | @param days Number of days 604 | @param hours Number of hours 605 | @param minutes Number of minutes 606 | @param seconds Number of seconds 607 | */ 608 | /**************************************************************************/ 609 | TimeSpan::TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds) 610 | : _seconds((int32_t)days * 86400L + (int32_t)hours * 3600 + 611 | (int32_t)minutes * 60 + seconds) {} 612 | 613 | /**************************************************************************/ 614 | /*! 615 | @brief Copy constructor, make a new TimeSpan using an existing one 616 | @param copy The TimeSpan to copy 617 | */ 618 | /**************************************************************************/ 619 | TimeSpan::TimeSpan(const TimeSpan ©) : _seconds(copy._seconds) {} 620 | 621 | /**************************************************************************/ 622 | /*! 623 | @brief Add two TimeSpans 624 | @param right TimeSpan to add 625 | @return New TimeSpan object, sum of left and right 626 | */ 627 | /**************************************************************************/ 628 | TimeSpan TimeSpan::operator+(const TimeSpan &right) { 629 | return TimeSpan(_seconds + right._seconds); 630 | } 631 | 632 | /**************************************************************************/ 633 | /*! 634 | @brief Subtract a TimeSpan 635 | @param right TimeSpan to subtract 636 | @return New TimeSpan object, right subtracted from left 637 | */ 638 | /**************************************************************************/ 639 | TimeSpan TimeSpan::operator-(const TimeSpan &right) { 640 | return TimeSpan(_seconds - right._seconds); 641 | } -------------------------------------------------------------------------------- /src/DateTime.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file RTClib.h 4 | Original library by JeeLabs http://news.jeelabs.org/code/, released to the 5 | public domain 6 | License: MIT (see LICENSE) 7 | This is a fork of JeeLab's fantastic real time clock library for Arduino. 8 | For details on using this library with an RTC module like the DS1307, PCF8523, 9 | or DS3231, see the guide at: 10 | https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview 11 | Adafruit invests time and resources providing this open source code, 12 | please support Adafruit and open-source hardware by purchasing 13 | products from Adafruit! 14 | */ 15 | /**************************************************************************/ 16 | 17 | 18 | #ifndef __DATETIME_H__ 19 | #define __DATETIME_H__ 20 | #include "Arduino.h" 21 | #include "time.h" 22 | 23 | #define SECONDS_PER_DAY 86400L ///< 60 * 60 * 24 24 | #define SECONDS_FROM_1970_TO_2000 \ 25 | 946684800 ///< Unixtime for 2000-01-01 08:00:00, useful for initialization 26 | 27 | 28 | /**************************************************************************/ 29 | /*! 30 | @brief Timespan which can represent changes in time with seconds accuracy. 31 | */ 32 | /**************************************************************************/ 33 | class TimeSpan { 34 | public: 35 | TimeSpan(int32_t seconds = 0); 36 | TimeSpan(int16_t days, int8_t hours, int8_t minutes, int8_t seconds); 37 | TimeSpan(const TimeSpan ©); 38 | 39 | /*! 40 | @brief Number of days in the TimeSpan 41 | e.g. 4 42 | @return int16_t days 43 | */ 44 | int16_t days() const { return _seconds / 86400L; } 45 | /*! 46 | @brief Number of hours in the TimeSpan 47 | This is not the total hours, it includes the days 48 | e.g. 4 days, 3 hours - NOT 99 hours 49 | @return int8_t hours 50 | */ 51 | int8_t hours() const { return _seconds / 3600 % 24; } 52 | /*! 53 | @brief Number of minutes in the TimeSpan 54 | This is not the total minutes, it includes days/hours 55 | e.g. 4 days, 3 hours, 27 minutes 56 | @return int8_t minutes 57 | */ 58 | int8_t minutes() const { return _seconds / 60 % 60; } 59 | /*! 60 | @brief Number of seconds in the TimeSpan 61 | This is not the total seconds, it includes the days/hours/minutes 62 | e.g. 4 days, 3 hours, 27 minutes, 7 seconds 63 | @return int8_t seconds 64 | */ 65 | int8_t seconds() const { return _seconds % 60; } 66 | /*! 67 | @brief Total number of seconds in the TimeSpan, e.g. 358027 68 | @return int32_t seconds 69 | */ 70 | int32_t totalseconds() const { return _seconds; } 71 | 72 | TimeSpan operator+(const TimeSpan &right); 73 | TimeSpan operator-(const TimeSpan &right); 74 | 75 | protected: 76 | int32_t _seconds; ///< Actual TimeSpan value is stored as seconds 77 | }; 78 | 79 | class DateTime { 80 | public: 81 | 82 | DateTime(uint32_t t = SECONDS_FROM_1970_TO_2000); 83 | DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour = 0, 84 | uint8_t min = 0, uint8_t sec = 0); 85 | DateTime(const DateTime ©); 86 | DateTime(const char *date, const char *time); 87 | DateTime(const __FlashStringHelper *date, const __FlashStringHelper *time); 88 | DateTime(const char *iso8601date); 89 | bool isValid() const; 90 | char *toString(char *buffer); 91 | 92 | 93 | /*! 94 | @brief Return the year. 95 | @return Year (range: 2000--2099). 96 | */ 97 | uint16_t year() const { return 2000 + yOff; } 98 | /*! 99 | @brief Return the month. 100 | @return Month number (1--12). 101 | */ 102 | uint8_t month() const { return m; } 103 | /*! 104 | @brief Return the day of the month. 105 | @return Day of the month (1--31). 106 | */ 107 | uint8_t day() const { return d; } 108 | /*! 109 | @brief Return the hour 110 | @return Hour (0--23). 111 | */ 112 | uint8_t hour() const { return hh; } 113 | 114 | uint8_t twelveHour() const; 115 | /*! 116 | @brief Return whether the time is PM. 117 | @return 0 if the time is AM, 1 if it's PM. 118 | */ 119 | uint8_t isPM() const { return hh >= 12; } 120 | /*! 121 | @brief Return the minute. 122 | @return Minute (0--59). 123 | */ 124 | uint8_t minute() const { return mm; } 125 | /*! 126 | @brief Return the second. 127 | @return Second (0--59). 128 | */ 129 | uint8_t second() const { return ss; } 130 | 131 | uint8_t dayOfTheWeek() const; 132 | 133 | /* 32-bit times as seconds since 2000-01-01. */ 134 | uint32_t secondstime() const; 135 | 136 | /* 32-bit times as seconds since 1970-01-01. */ 137 | uint32_t unixtime(void) const; 138 | 139 | /*! 140 | Format of the ISO 8601 timestamp generated by `timestamp()`. Each 141 | option corresponds to a `toString()` format as follows: 142 | */ 143 | enum timestampOpt { 144 | TIMESTAMP_FULL, //!< `YYYY-MM-DDThh:mm:ss` 145 | TIMESTAMP_TIME, //!< `hh:mm:ss` 146 | TIMESTAMP_DATE //!< `YYYY-MM-DD` 147 | }; 148 | String timestamp(timestampOpt opt = TIMESTAMP_FULL); 149 | 150 | DateTime operator+(const TimeSpan &span); 151 | DateTime operator-(const TimeSpan &span); 152 | TimeSpan operator-(const DateTime &right); 153 | bool operator<(const DateTime &right) const; 154 | /*! 155 | @brief Test if one DateTime is greater (later) than another. 156 | @param right DateTime object to compare 157 | @return True if the left DateTime is later than the right one, 158 | false otherwise 159 | */ 160 | bool operator>(const DateTime &right) const { return right < *this; } 161 | /*! 162 | @brief Test if one DateTime is less (earlier) than or equal to another 163 | @param right DateTime object to compare 164 | @return True if the left DateTime is earlier than or equal to the 165 | right one, false otherwise 166 | */ 167 | bool operator<=(const DateTime &right) const { return !(*this > right); } 168 | /*! 169 | @brief Test if one DateTime is greater (later) than or equal to another 170 | @param right DateTime object to compare 171 | @return True if the left DateTime is later than or equal to the right 172 | one, false otherwise 173 | */ 174 | bool operator>=(const DateTime &right) const { return !(*this < right); } 175 | bool operator==(const DateTime &right) const; 176 | /*! 177 | @brief Test if two DateTime objects are not equal. 178 | @param right DateTime object to compare 179 | @return True if the two objects are not equal, false if they are 180 | */ 181 | bool operator!=(const DateTime &right) const { return !(*this == right); } 182 | 183 | protected: 184 | uint8_t yOff; ///< Year offset from 2000 185 | uint8_t m; ///< Month 1-12 186 | uint8_t d; ///< Day 1-31 187 | uint8_t hh; ///< Hours 0-23 188 | uint8_t mm; ///< Minutes 0-59 189 | uint8_t ss; ///< Seconds 0-59 190 | }; 191 | 192 | #endif // __DATETIME_H__ -------------------------------------------------------------------------------- /src/RTC_SAMD21.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | RTC library for Arduino Zero. 3 | Copyright (c) 2015 Arduino LLC. All right reserved. 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 2.1 of the License, or (at your option) any later version. 8 | This library is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | Lesser General Public License for more details. 12 | You should have received a copy of the GNU Lesser General Public 13 | License along with this library; if not, write to the Free Software 14 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #ifdef __SAMD21__ 18 | #include "RTC_SAMD21.h" 19 | 20 | rtcCallBack RTC_callBack = NULL; 21 | 22 | bool RTC_SAMD21::begin() 23 | { 24 | uint16_t tmp_reg = 0; 25 | 26 | PM->APBAMASK.reg |= PM_APBAMASK_RTC; // turn on digital interface clock 27 | config32kOSC(); 28 | 29 | // If the RTC is in clock mode and the reset was 30 | // not due to POR or BOD, preserve the clock time 31 | // POR causes a reset anyway, BOD behaviour is? 32 | bool validTime = false; 33 | RTC_MODE2_CLOCK_Type oldTime; 34 | 35 | if ((PM->RCAUSE.reg & (PM_RCAUSE_SYST | PM_RCAUSE_WDT | PM_RCAUSE_EXT))) 36 | { 37 | if (RTC->MODE2.CTRL.reg & RTC_MODE2_CTRL_MODE_CLOCK) 38 | { 39 | validTime = true; 40 | oldTime.reg = RTC->MODE2.CLOCK.reg; 41 | } 42 | } 43 | 44 | // Setup clock GCLK2 with OSC32K divided by 32 45 | configureClock(); 46 | 47 | RTCdisable(); 48 | 49 | RTCreset(); 50 | 51 | tmp_reg |= RTC_MODE2_CTRL_MODE_CLOCK; // set clock operating mode 52 | tmp_reg |= RTC_MODE2_CTRL_PRESCALER_DIV1024; // set prescaler to 1024 for MODE2 53 | tmp_reg &= ~RTC_MODE2_CTRL_MATCHCLR; // disable clear on match 54 | 55 | //According to the datasheet RTC_MODE2_CTRL_CLKREP = 0 for 24h 56 | tmp_reg &= ~RTC_MODE2_CTRL_CLKREP; // 24h time representation 57 | 58 | RTC->MODE2.READREQ.reg &= ~RTC_READREQ_RCONT; // disable continuously mode 59 | 60 | RTC->MODE2.CTRL.reg = tmp_reg; 61 | while (RTCisSyncing()) 62 | ; 63 | 64 | NVIC_EnableIRQ(RTC_IRQn); // enable RTC interrupt 65 | NVIC_SetPriority(RTC_IRQn, 0x00); 66 | 67 | RTC->MODE2.INTENSET.reg |= RTC_MODE2_INTENSET_ALARM0; // enable alarm interrupt 68 | RTC->MODE2.Mode2Alarm[0].MASK.bit.SEL = MATCH_OFF; // default alarm match is off (disabled) 69 | 70 | while (RTCisSyncing()) 71 | ; 72 | 73 | RTCenable(); 74 | RTCresetRemove(); 75 | 76 | // If desired and valid, restore the time value, else use first valid time value 77 | if ((validTime) && (oldTime.reg != 0L)) 78 | { 79 | RTC->MODE2.CLOCK.reg = oldTime.reg; 80 | } 81 | else 82 | { 83 | RTC->MODE2.CLOCK.reg = RTC_MODE2_CLOCK_YEAR(DEFAULT_YEAR - 2000) | RTC_MODE2_CLOCK_MONTH(DEFAULT_MONTH) | RTC_MODE2_CLOCK_DAY(DEFAULT_DAY) | RTC_MODE2_CLOCK_HOUR(DEFAULT_HOUR) | RTC_MODE2_CLOCK_MINUTE(DEFAULT_MINUTE) | RTC_MODE2_CLOCK_SECOND(DEFAULT_SECOND); 84 | } 85 | 86 | while (RTCisSyncing()) 87 | ; 88 | 89 | return true; 90 | } 91 | 92 | void RTC_SAMD21::adjust(const DateTime &dt) 93 | { 94 | RTC_MODE2_CLOCK_Type newTime; 95 | 96 | newTime.bit.SECOND = dt.second(); 97 | newTime.bit.MINUTE = dt.minute(); 98 | newTime.bit.HOUR = dt.hour(); 99 | newTime.bit.DAY = dt.day(); 100 | newTime.bit.MONTH = dt.month(); 101 | newTime.bit.YEAR = dt.year() - 2000; 102 | 103 | RTC->MODE2.CLOCK.reg = newTime.reg; 104 | while (RTCisSyncing()) 105 | ; 106 | } 107 | 108 | DateTime RTC_SAMD21::now() 109 | { 110 | RTCreadRequest(); 111 | uint8_t ss = RTC->MODE2.CLOCK.bit.SECOND; 112 | uint8_t mm = RTC->MODE2.CLOCK.bit.MINUTE; 113 | uint8_t hh = RTC->MODE2.CLOCK.bit.HOUR; 114 | uint8_t d = RTC->MODE2.CLOCK.bit.DAY; 115 | uint8_t m = RTC->MODE2.CLOCK.bit.MONTH; 116 | uint16_t y = RTC->MODE2.CLOCK.bit.YEAR; 117 | 118 | return DateTime(y, m, d, hh, mm, ss); 119 | } 120 | 121 | DateTime RTC_SAMD21::alarm() 122 | { 123 | 124 | uint8_t ss = RTC->MODE2.Mode2Alarm[0].ALARM.bit.SECOND; 125 | uint8_t mm = RTC->MODE2.Mode2Alarm[0].ALARM.bit.MINUTE; 126 | uint8_t hh = RTC->MODE2.Mode2Alarm[0].ALARM.bit.HOUR; 127 | uint8_t d = RTC->MODE2.Mode2Alarm[0].ALARM.bit.DAY; 128 | uint8_t m = RTC->MODE2.Mode2Alarm[0].ALARM.bit.MONTH; 129 | uint16_t y = RTC->MODE2.Mode2Alarm[0].ALARM.bit.YEAR; 130 | 131 | return DateTime(y, m, d, hh, mm, ss); 132 | } 133 | 134 | void RTC_SAMD21::setAlarm(const DateTime &dt) 135 | { 136 | RTC_MODE2_CLOCK_Type alarmTime; 137 | 138 | alarmTime.bit.SECOND = dt.second(); 139 | alarmTime.bit.MINUTE = dt.minute(); 140 | alarmTime.bit.HOUR = dt.hour(); 141 | alarmTime.bit.DAY = dt.day(); 142 | alarmTime.bit.MONTH = dt.month(); 143 | alarmTime.bit.YEAR = dt.year() - 2000; 144 | 145 | RTC->MODE2.Mode2Alarm[0].ALARM.reg = alarmTime.reg; 146 | } 147 | 148 | void RTC_SAMD21::enableAlarm(Alarm_Match match) 149 | { 150 | RTC->MODE2.Mode2Alarm[0].MASK.bit.SEL = match; 151 | while (RTCisSyncing()) 152 | ; 153 | } 154 | 155 | void RTC_SAMD21::disableAlarm() 156 | { 157 | RTC->MODE2.Mode2Alarm[0].MASK.bit.SEL = 0x00; 158 | while (RTCisSyncing()) 159 | ; 160 | } 161 | 162 | void RTC_SAMD21::attachInterrupt(rtcCallBack callback) 163 | { 164 | RTC_callBack = callback; 165 | } 166 | 167 | void RTC_SAMD21::detachInterrupt() 168 | { 169 | RTC_callBack = NULL; 170 | } 171 | 172 | void RTC_SAMD21::standbyMode() 173 | { 174 | // Entering standby mode when connected 175 | // via the native USB port causes issues. 176 | SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; 177 | __DSB(); 178 | __WFI(); 179 | } 180 | 181 | /* Attach peripheral clock to 32k oscillator */ 182 | void RTC_SAMD21::configureClock() 183 | { 184 | GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(4); 185 | while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) 186 | ; 187 | #ifdef CRYSTALLESS 188 | GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL); 189 | #else 190 | GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL); 191 | #endif 192 | while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) 193 | ; 194 | GCLK->CLKCTRL.reg = (uint32_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK2 | (RTC_GCLK_ID << GCLK_CLKCTRL_ID_Pos))); 195 | while (GCLK->STATUS.bit.SYNCBUSY) 196 | ; 197 | } 198 | 199 | /* 200 | * Private Utility Functions 201 | */ 202 | 203 | /* Configure the 32768Hz Oscillator */ 204 | void RTC_SAMD21::config32kOSC() 205 | { 206 | #ifndef CRYSTALLESS 207 | SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND | 208 | SYSCTRL_XOSC32K_RUNSTDBY | 209 | SYSCTRL_XOSC32K_EN32K | 210 | SYSCTRL_XOSC32K_XTALEN | 211 | SYSCTRL_XOSC32K_STARTUP(6) | 212 | SYSCTRL_XOSC32K_ENABLE; 213 | #endif 214 | } 215 | 216 | /* Synchronise the CLOCK register for reading*/ 217 | inline void RTC_SAMD21::RTCreadRequest() 218 | { 219 | 220 | RTC->MODE2.READREQ.reg = RTC_READREQ_RREQ; 221 | while (RTCisSyncing()) 222 | ; 223 | } 224 | 225 | /* Wait for sync in write operations */ 226 | inline bool RTC_SAMD21::RTCisSyncing() 227 | { 228 | return (RTC->MODE2.STATUS.bit.SYNCBUSY); 229 | } 230 | 231 | void RTC_SAMD21::RTCdisable() 232 | { 233 | RTC->MODE2.CTRL.reg &= ~RTC_MODE2_CTRL_ENABLE; // disable RTC 234 | while (RTCisSyncing()) 235 | ; 236 | } 237 | 238 | void RTC_SAMD21::RTCenable() 239 | { 240 | RTC->MODE2.CTRL.reg |= RTC_MODE2_CTRL_ENABLE; // enable RTC 241 | while (RTCisSyncing()) 242 | ; 243 | } 244 | 245 | void RTC_SAMD21::RTCreset() 246 | { 247 | RTC->MODE2.CTRL.reg |= RTC_MODE2_CTRL_SWRST; // software reset 248 | while (RTCisSyncing()) 249 | ; 250 | } 251 | 252 | void RTC_SAMD21::RTCresetRemove() 253 | { 254 | RTC->MODE2.CTRL.reg &= ~RTC_MODE2_CTRL_SWRST; // software reset remove 255 | while (RTCisSyncing()) 256 | ; 257 | } 258 | 259 | extern "C" 260 | { 261 | void RTC_Handler(void) 262 | { 263 | if (RTC_callBack != NULL) 264 | { 265 | RTC_callBack(); 266 | } 267 | 268 | RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0; // must clear flag at end 269 | } 270 | } 271 | #endif -------------------------------------------------------------------------------- /src/RTC_SAMD21.h: -------------------------------------------------------------------------------- 1 | /* 2 | RTC library for Arduino Zero. 3 | Copyright (c) 2015 Arduino LLC. All right reserved. 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 2.1 of the License, or (at your option) any later version. 8 | This library is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | Lesser General Public License for more details. 12 | You should have received a copy of the GNU Lesser General Public 13 | License along with this library; if not, write to the Free Software 14 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 15 | */ 16 | 17 | #ifdef __SAMD21__ 18 | #ifndef __RTC_SAMD21_H__ 19 | #define __RTC_SAMD21_H__ 20 | #include "DateTime.h" 21 | 22 | typedef voidFuncPtr rtcCallBack; 23 | 24 | // Default date & time after reset 25 | #define DEFAULT_YEAR 2000 // 2000..2063 26 | #define DEFAULT_MONTH 1 // 1..12 27 | #define DEFAULT_DAY 1 // 1..31 28 | #define DEFAULT_HOUR 0 // 1..23 29 | #define DEFAULT_MINUTE 0 // 0..59 30 | #define DEFAULT_SECOND 0 // 0..59 31 | 32 | class RTC_SAMD21 33 | { 34 | public: 35 | enum Alarm_Match : uint8_t // Should we have this enum or just use the identifiers from /component/rtc.h ? 36 | { 37 | MATCH_OFF = RTC_MODE2_MASK_SEL_OFF_Val, // Never 38 | MATCH_SS = RTC_MODE2_MASK_SEL_SS_Val, // Every Minute 39 | MATCH_MMSS = RTC_MODE2_MASK_SEL_MMSS_Val, // Every Hour 40 | MATCH_HHMMSS = RTC_MODE2_MASK_SEL_HHMMSS_Val, // Every Day 41 | MATCH_DHHMMSS = RTC_MODE2_MASK_SEL_DDHHMMSS_Val, // Every Month 42 | MATCH_MMDDHHMMSS = RTC_MODE2_MASK_SEL_MMDDHHMMSS_Val, // Every Year 43 | MATCH_YYMMDDHHMMSS = RTC_MODE2_MASK_SEL_YYMMDDHHMMSS_Val // Once, on a specific date and a specific time 44 | }; 45 | 46 | boolean begin(); 47 | void adjust(const DateTime &dt); 48 | DateTime now(); 49 | void setAlarm(const DateTime &dt); 50 | DateTime alarm(); 51 | void enableAlarm(Alarm_Match match); 52 | void disableAlarm(); 53 | void attachInterrupt(rtcCallBack callback); 54 | void detachInterrupt(); 55 | void standbyMode(); 56 | 57 | private: 58 | void config32kOSC(void); 59 | void configureClock(void); 60 | void RTCreadRequest(); 61 | bool RTCisSyncing(void); 62 | void RTCdisable(); 63 | void RTCenable(); 64 | void RTCreset(); 65 | void RTCresetRemove(); 66 | }; 67 | #endif 68 | #endif -------------------------------------------------------------------------------- /src/RTC_SAMD51.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | Author: Hongtai Liu (lht856@foxmail.com) 4 | Copyright (C) 2020 Seeed Technology Co.,Ltd. 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 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | */ 21 | 22 | #ifdef __SAMD51__ 23 | #include "RTC_SAMD51.h" 24 | 25 | rtcCallBack RTC_callBack = NULL; 26 | 27 | bool RTC_SAMD51::begin() 28 | { 29 | config32kOSC(); 30 | 31 | uint16_t tmp_reg_a = 0; 32 | 33 | // If the RTC is in clock mode and the reset was 34 | // not due to POR or BOD, preserve the clock time 35 | // POR causes a reset anyway, BOD behaviour is? 36 | bool validTime = false; 37 | RTC_MODE2_CLOCK_Type oldTime; 38 | 39 | if (RTC->MODE2.CTRLA.reg & RTC_MODE2_CTRLA_MODE_CLOCK) 40 | { 41 | validTime = true; 42 | oldTime.reg = RTC->MODE2.CLOCK.reg; 43 | } 44 | 45 | configureClock(); 46 | 47 | RTCdisable(); 48 | 49 | RTCreset(); 50 | 51 | tmp_reg_a |= RTC_MODE2_CTRLA_MODE_CLOCK; // set clock operating mode 52 | tmp_reg_a |= RTC_MODE2_CTRLA_PRESCALER_DIV1024; // set prescaler to 1024 for MODE2 so that f = GCLK_RTC / 1024 = 1.024K / 1024 = 1Hz 53 | tmp_reg_a &= ~RTC_MODE2_CTRLA_MATCHCLR; // disable clear on match 54 | 55 | //According to the datasheet RTC_MODE2_CTRL_CLKREP = 0 for 24h 56 | tmp_reg_a &= ~RTC_MODE2_CTRLA_CLKREP; // 24h time representation 57 | 58 | RTC->MODE2.CTRLA.reg = tmp_reg_a; 59 | while (RTCisSyncing()) 60 | ; 61 | 62 | NVIC_EnableIRQ(RTC_IRQn); // enable RTC interrupt 63 | NVIC_SetPriority(RTC_IRQn, 0x00); 64 | 65 | RTC->MODE2.INTENSET.reg |= RTC_MODE2_INTENSET_ALARM0; // enable alarm0 interrupt 66 | RTC->MODE2.Mode2Alarm[0].MASK.bit.SEL = MATCH_OFF; // default alarm0 match is off (disabled) 67 | 68 | RTC->MODE2.INTENSET.reg |= RTC_MODE2_INTENSET_ALARM1; // enable alarm1 interrupt 69 | RTC->MODE2.Mode2Alarm[1].MASK.bit.SEL = MATCH_OFF; // default alarm1 match is off (disabled) 70 | 71 | while (RTCisSyncing()) 72 | ; 73 | 74 | RTCenable(); 75 | RTCresetRemove(); 76 | 77 | // If desired and valid, restore the time value, else use first valid time value 78 | if ((validTime) && (oldTime.reg != 0L)) 79 | { 80 | RTC->MODE2.CLOCK.reg = oldTime.reg; 81 | } 82 | else 83 | { 84 | RTC->MODE2.CLOCK.reg = RTC_MODE2_CLOCK_YEAR(DEFAULT_YEAR - 2000) | RTC_MODE2_CLOCK_MONTH(DEFAULT_MONTH) | RTC_MODE2_CLOCK_DAY(DEFAULT_DAY) | RTC_MODE2_CLOCK_HOUR(DEFAULT_HOUR) | RTC_MODE2_CLOCK_MINUTE(DEFAULT_MINUTE) | RTC_MODE2_CLOCK_SECOND(DEFAULT_SECOND); 85 | } 86 | 87 | while (RTCisSyncing()) 88 | ; 89 | 90 | return true; 91 | } 92 | 93 | void RTC_SAMD51::adjust(const DateTime &dt) 94 | { 95 | RTC_MODE2_CLOCK_Type newTime; 96 | 97 | newTime.bit.SECOND = dt.second(); 98 | newTime.bit.MINUTE = dt.minute(); 99 | newTime.bit.HOUR = dt.hour(); 100 | newTime.bit.DAY = dt.day(); 101 | newTime.bit.MONTH = dt.month(); 102 | newTime.bit.YEAR = dt.year() - 2000; 103 | 104 | RTC->MODE2.CLOCK.reg = newTime.reg; 105 | while (RTCisSyncing()) 106 | ; 107 | } 108 | 109 | DateTime RTC_SAMD51::now() 110 | { 111 | RTCreadRequest(); 112 | uint8_t ss = RTC->MODE2.CLOCK.bit.SECOND; 113 | uint8_t mm = RTC->MODE2.CLOCK.bit.MINUTE; 114 | uint8_t hh = RTC->MODE2.CLOCK.bit.HOUR; 115 | uint8_t d = RTC->MODE2.CLOCK.bit.DAY; 116 | uint8_t m = RTC->MODE2.CLOCK.bit.MONTH; 117 | uint16_t y = RTC->MODE2.CLOCK.bit.YEAR; 118 | 119 | return DateTime(y, m, d, hh, mm, ss); 120 | } 121 | 122 | DateTime RTC_SAMD51::alarm(uint8_t id) 123 | { 124 | if (id >= 2) 125 | return DateTime(); 126 | uint8_t ss = RTC->MODE2.Mode2Alarm[id].ALARM.bit.SECOND; 127 | uint8_t mm = RTC->MODE2.Mode2Alarm[id].ALARM.bit.MINUTE; 128 | uint8_t hh = RTC->MODE2.Mode2Alarm[id].ALARM.bit.HOUR; 129 | uint8_t d = RTC->MODE2.Mode2Alarm[id].ALARM.bit.DAY; 130 | uint8_t m = RTC->MODE2.Mode2Alarm[id].ALARM.bit.MONTH; 131 | uint16_t y = RTC->MODE2.Mode2Alarm[id].ALARM.bit.YEAR; 132 | 133 | return DateTime(y, m, d, hh, mm, ss); 134 | } 135 | 136 | void RTC_SAMD51::setAlarm(uint8_t id, const DateTime &dt) 137 | { 138 | if (id >= 2) 139 | return; 140 | RTC_MODE2_CLOCK_Type alarmTime; 141 | 142 | alarmTime.bit.SECOND = dt.second(); 143 | alarmTime.bit.MINUTE = dt.minute(); 144 | alarmTime.bit.HOUR = dt.hour(); 145 | alarmTime.bit.DAY = dt.day(); 146 | alarmTime.bit.MONTH = dt.month(); 147 | alarmTime.bit.YEAR = dt.year() - 2000; 148 | 149 | RTC->MODE2.Mode2Alarm[id].ALARM.reg = alarmTime.reg; 150 | if (id == 0) 151 | { 152 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_ALARM0)) 153 | ; 154 | } 155 | else 156 | { 157 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_ALARM1)) 158 | ; 159 | } 160 | } 161 | 162 | void RTC_SAMD51::enableAlarm(uint8_t id, Alarm_Match match) 163 | { 164 | if (id >= 2) 165 | return; 166 | RTC->MODE2.Mode2Alarm[id].MASK.bit.SEL = match; 167 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_ALARM_Msk)) 168 | ; 169 | } 170 | 171 | void RTC_SAMD51::disableAlarm(uint8_t id) 172 | { 173 | if (id >= 2) 174 | return; 175 | RTC->MODE2.Mode2Alarm[id].MASK.bit.SEL = 0x00; 176 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_ALARM_Msk)) 177 | ; 178 | } 179 | 180 | void RTC_SAMD51::attachInterrupt(rtcCallBack callback) 181 | { 182 | RTC_callBack = callback; 183 | } 184 | 185 | void RTC_SAMD51::detachInterrupt() 186 | { 187 | RTC_callBack = NULL; 188 | } 189 | 190 | void RTC_SAMD51::standbyMode() 191 | { 192 | // Entering standby mode when connected 193 | // via the native USB port causes issues. 194 | SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; 195 | __DSB(); 196 | __WFI(); 197 | } 198 | 199 | /* Attach peripheral clock to 32k oscillator and RTC*/ 200 | void RTC_SAMD51::configureClock() 201 | { 202 | MCLK->APBAMASK.reg |= MCLK_APBAMASK_RTC | MCLK_APBAMASK_OSC32KCTRL; 203 | } 204 | 205 | /* 206 | * Private Utility Functions 207 | */ 208 | 209 | /* Configure the 32768Hz Oscillator */ 210 | void RTC_SAMD51::config32kOSC() 211 | { 212 | #ifdef CRYSTALLESS 213 | // This platform does not have external crystal. 214 | // Thus, we have to enable OSCULP32K to generate RTC clock. 215 | void *hw = (void *)OSC32KCTRL; 216 | uint16_t calib = 0; 217 | 218 | calib = ((Osc32kctrl *)hw)->OSCULP32K.reg; 219 | calib = (calib & OSC32KCTRL_OSCULP32K_CALIB_Msk) >> OSC32KCTRL_OSCULP32K_CALIB_Pos; 220 | //re-write calibrate 221 | ((Osc32kctrl *)hw)->OSCULP32K.reg &= ~OSC32KCTRL_OSCULP32K_WRTLOCK; 222 | 223 | ((Osc32kctrl *)hw)->OSCULP32K.reg |= calib; 224 | ((Osc32kctrl *)hw)->OSCULP32K.reg &= ~(OSC32KCTRL_OSCULP32K_EN32K); 225 | ((Osc32kctrl *)hw)->OSCULP32K.reg |= OSC32KCTRL_OSCULP32K_EN1K; //enable 1.024KHz OUPUT 226 | 227 | ((Osc32kctrl *)hw)->OSCULP32K.reg |= OSC32KCTRL_OSCULP32K_WRTLOCK; 228 | 229 | //Use 1.024KHz for RTC 230 | ((Osc32kctrl *)hw)->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL(OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K_Val); 231 | #else 232 | // This platform has external crystal and Arduino core has already enabled the XOSC32K oscillator. 233 | // But the Arduino core does not enable 1.024[kHz] output. 234 | // Thus all we have to do is just enable 1.024[kHz] output by setting XOSC32K.EN1k to 1. 235 | OSC32KCTRL->XOSC32K.bit.EN1K = 1; 236 | // Use 1.024[kHz] output for RTC. 237 | OSC32KCTRL->RTCCTRL.bit.RTCSEL = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K_Val; 238 | #endif 239 | } 240 | 241 | /* Synchronise the CLOCK register for reading*/ 242 | inline void RTC_SAMD51::RTCreadRequest() 243 | { 244 | RTC->MODE2.CTRLA.reg |= RTC_MODE2_CTRLA_CLOCKSYNC; 245 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_SWRST | RTC_MODE2_SYNCBUSY_ENABLE | RTC_MODE2_SYNCBUSY_CLOCKSYNC)) 246 | ; 247 | } 248 | 249 | /* Wait for sync in write operations */ 250 | inline bool RTC_SAMD51::RTCisSyncing(uint32_t flag) 251 | { 252 | return (RTC->MODE2.SYNCBUSY.reg & flag); 253 | } 254 | 255 | void RTC_SAMD51::RTCdisable() 256 | { 257 | RTC->MODE2.CTRLA.reg &= ~RTC_MODE2_CTRLA_ENABLE; // disable RTC 258 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_SWRST | RTC_MODE2_SYNCBUSY_ENABLE | RTC_MODE2_SYNCBUSY_CLOCKSYNC)) 259 | ; 260 | } 261 | 262 | void RTC_SAMD51::RTCenable() 263 | { 264 | RTC->MODE2.CTRLA.reg |= RTC_MODE2_CTRLA_ENABLE; // enable RTC 265 | while (RTCisSyncing(RTC_MODE2_SYNCBUSY_SWRST | RTC_MODE2_SYNCBUSY_ENABLE | RTC_MODE2_SYNCBUSY_CLOCKSYNC)) 266 | ; 267 | } 268 | 269 | void RTC_SAMD51::RTCreset() 270 | { 271 | RTC->MODE2.CTRLA.reg |= RTC_MODE2_CTRLA_SWRST; // software reset 272 | while (RTCisSyncing(RTC_MODE2_CTRLA_SWRST)) 273 | ; 274 | } 275 | 276 | void RTC_SAMD51::RTCresetRemove() 277 | { 278 | RTC->MODE2.CTRLA.reg &= ~RTC_MODE2_CTRLA_SWRST; // software reset remove 279 | while (RTCisSyncing(RTC_MODE2_CTRLA_SWRST)) 280 | ; 281 | } 282 | 283 | extern "C" 284 | { 285 | void RTC_Handler(void) 286 | { 287 | uint32_t flag = 0; 288 | 289 | if (RTC_callBack != NULL) 290 | { 291 | 292 | if (RTC->MODE2.INTFLAG.reg & RTC_MODE2_INTFLAG_ALARM0) 293 | flag |= 1; 294 | if (RTC->MODE2.INTFLAG.reg & RTC_MODE2_INTFLAG_ALARM1) 295 | flag |= 2; 296 | RTC_callBack(flag); 297 | } 298 | if (flag & 1) 299 | { 300 | RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM0; 301 | } 302 | if (flag & 2) 303 | { 304 | RTC->MODE2.INTFLAG.reg = RTC_MODE2_INTFLAG_ALARM1; 305 | } 306 | } 307 | } 308 | #endif -------------------------------------------------------------------------------- /src/RTC_SAMD51.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | Author: Hongtai Liu (lht856@foxmail.com) 4 | Copyright (C) 2020 Seeed Technology Co.,Ltd. 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 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | */ 21 | 22 | #ifdef __SAMD51__ 23 | #ifndef __RTC_SAMD51_H__ 24 | #define __RTC_SAMD51_H__ 25 | #include "DateTime.h" 26 | 27 | 28 | typedef void (*rtcCallBack)(uint32_t flag); 29 | 30 | // Default date & time after reset 31 | #define DEFAULT_YEAR 2000 // 2000..2063 32 | #define DEFAULT_MONTH 1 // 1..12 33 | #define DEFAULT_DAY 1 // 1..31 34 | #define DEFAULT_HOUR 0 // 1..23 35 | #define DEFAULT_MINUTE 0 // 0..59 36 | #define DEFAULT_SECOND 0 // 0..59 37 | 38 | class RTC_SAMD51 39 | { 40 | public: 41 | enum Alarm_Match : uint8_t // Should we have this enum or just use the identifiers from /component/rtc.h ? 42 | { 43 | MATCH_OFF = RTC_MODE2_MASK_SEL_OFF_Val, // Never 44 | MATCH_SS = RTC_MODE2_MASK_SEL_SS_Val, // Every Minute 45 | MATCH_MMSS = RTC_MODE2_MASK_SEL_MMSS_Val, // Every Hour 46 | MATCH_HHMMSS = RTC_MODE2_MASK_SEL_HHMMSS_Val, // Every Day 47 | MATCH_DHHMMSS = RTC_MODE2_MASK_SEL_DDHHMMSS_Val, // Every Month 48 | MATCH_MMDDHHMMSS = RTC_MODE2_MASK_SEL_MMDDHHMMSS_Val, // Every Year 49 | MATCH_YYMMDDHHMMSS = RTC_MODE2_MASK_SEL_YYMMDDHHMMSS_Val // Once, on a specific date and a specific time 50 | }; 51 | 52 | boolean begin(); 53 | void adjust(const DateTime &dt); 54 | DateTime now(); 55 | void setAlarm(uint8_t id, const DateTime &dt); 56 | DateTime alarm(uint8_t id); 57 | void enableAlarm(uint8_t id, Alarm_Match match); 58 | void disableAlarm(uint8_t id); 59 | void attachInterrupt(rtcCallBack callback); 60 | void detachInterrupt(); 61 | void standbyMode(); 62 | 63 | private: 64 | void config32kOSC(void); 65 | void configureClock(void); 66 | void RTCreadRequest(); 67 | bool RTCisSyncing(uint32_t flag = RTC_MODE2_SYNCBUSY_MASK_); 68 | void RTCdisable(); 69 | void RTCenable(); 70 | void RTCreset(); 71 | void RTCresetRemove(); 72 | }; 73 | #endif 74 | #endif --------------------------------------------------------------------------------