Compare commits

..

24 Commits

Author SHA1 Message Date
2147637385 Update submodule 2020-05-17 20:11:51 +02:00
966af1d5cf Add ability to read alarm times 2020-05-17 20:07:13 +02:00
a83671bda5 Add alarms to example 2020-05-17 19:56:11 +02:00
7e8a6b0dad Add power control for RTC 2020-05-17 15:40:29 +02:00
a897b7d9be Move comparison operator into library 2020-05-17 15:40:15 +02:00
f8ee536829 Only pass i2c backend to rtc class 2020-05-16 19:52:49 +02:00
2fd64c8611 Implement setting time through serial 2020-05-16 19:48:37 +02:00
97bb522189 Remove old rtc lib and systime 2020-05-16 19:20:32 +02:00
b8c7c9ec5c Adapt to moved type submodule 2020-05-16 17:44:16 +02:00
5d77cad8d7 Add setting date-time example with new rtc lib 2020-05-16 17:26:56 +02:00
4b3dd99ebc Add usage for new C++ driver 2020-05-15 19:48:22 +02:00
f00a154e59 Change i2c library 2020-05-15 11:51:51 +02:00
e9d3a95239 Move C time API glue from driver to user space 2020-05-15 10:21:34 +02:00
b2065b987a Switch from old usart to new uart library 2020-05-15 09:43:06 +02:00
85e37de950 Ran clang-format 2020-05-15 09:29:26 +02:00
7310eb2c9a Remove bootloader support 2020-05-15 09:28:05 +02:00
b02454c45b Update submodule 2020-05-15 09:26:08 +02:00
af4f2ed0e5 Update project file to C++17 config with gcc 9 2020-05-15 09:24:24 +02:00
7a8d31718f Add gitignore and clang-format file 2020-05-15 09:21:08 +02:00
05e8b1b53f Change to 16 MHz crystal 2020-05-15 09:14:31 +02:00
a340cb04d3 Actually use ds3231 submodule instead of duplicating code 2020-05-15 09:06:34 +02:00
4cffd8f56b Fix submodule path 2020-05-15 09:01:11 +02:00
6072c34eef Fixed setting time bug, because of uninitialized tm struct 2018-01-02 17:21:04 +01:00
4bc59d1a33 Changed wrong CPU FREQ define to central correct one 2017-12-17 10:53:38 +01:00
20 changed files with 523 additions and 1669 deletions

18
.gitmodules vendored Normal file
View File

@@ -0,0 +1,18 @@
[submodule "ds3231/ds3231"]
path = ds3231/ds3231
url = git@git.blackmark.me:avr/ds3231.git
[submodule "ds3231/uart"]
path = ds3231/uart
url = git@git.blackmark.me:avr/uart.git
[submodule "ds3231/io"]
path = ds3231/io
url = git@git.blackmark.me:avr/io.git
[submodule "ds3231/flash"]
path = ds3231/flash
url = git@git.blackmark.me:avr/flash.git
[submodule "ds3231/i2c"]
path = ds3231/i2c
url = git@git.blackmark.me:avr/i2c.git
[submodule "ds3231/util"]
path = ds3231/util
url = git@git.blackmark.me:avr/util.git

21
LICENSE
View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 BlackMark
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

22
ds3231.atsln Normal file
View File

@@ -0,0 +1,22 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Atmel Studio Solution File, Format Version 11.00
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "ds3231", "ds3231\ds3231.cppproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|AVR = Debug|AVR
Release|AVR = Release|AVR
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.ActiveCfg = Debug|AVR
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.Build.0 = Debug|AVR
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.ActiveCfg = Release|AVR
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.Build.0 = Release|AVR
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

4
ds3231/clock.hpp Normal file
View File

@@ -0,0 +1,4 @@
#pragma once
#define F_CPU 16'000'000
#include <util/delay.h>

1
ds3231/ds3231 Submodule

Submodule ds3231/ds3231 added at 8a6170cb10

285
ds3231/ds3231.cppproj Normal file
View File

@@ -0,0 +1,285 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0">
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<ProjectVersion>7.0</ProjectVersion>
<ToolchainName>com.Atmel.AVRGCC8.CPP</ToolchainName>
<ProjectGuid>dce6c7e3-ee26-4d79-826b-08594b9ad897</ProjectGuid>
<avrdevice>ATmega328P</avrdevice>
<avrdeviceseries>none</avrdeviceseries>
<OutputType>Executable</OutputType>
<Language>CPP</Language>
<OutputFileName>$(MSBuildProjectName)</OutputFileName>
<OutputFileExtension>.elf</OutputFileExtension>
<OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
<AssemblyName>DailySafe</AssemblyName>
<Name>DailySafe</Name>
<RootNamespace>DailySafe</RootNamespace>
<ToolchainFlavour>avr-g++-9.1.0</ToolchainFlavour>
<KeepTimersRunning>true</KeepTimersRunning>
<OverrideVtor>false</OverrideVtor>
<CacheFlash>true</CacheFlash>
<ProgFlashFromRam>true</ProgFlashFromRam>
<RamSnippetAddress>0x20000000</RamSnippetAddress>
<UncachedRange />
<preserveEEPROM>true</preserveEEPROM>
<OverrideVtorValue>exception_table</OverrideVtorValue>
<BootSegment>2</BootSegment>
<ResetRule>0</ResetRule>
<eraseonlaunchrule>0</eraseonlaunchrule>
<EraseKey />
<avrtool>com.atmel.avrdbg.tool.atmelice</avrtool>
<avrtoolserialnumber>J41800099437</avrtoolserialnumber>
<avrdeviceexpectedsignature>0x1E950F</avrdeviceexpectedsignature>
<com_atmel_avrdbg_tool_stk500>
<ToolOptions>
<InterfaceProperties>
<IspClock>125000</IspClock>
</InterfaceProperties>
<InterfaceName>ISP</InterfaceName>
</ToolOptions>
<ToolType>com.atmel.avrdbg.tool.stk500</ToolType>
<ToolNumber>
</ToolNumber>
<ToolName>STK500</ToolName>
</com_atmel_avrdbg_tool_stk500>
<avrtoolinterface>ISP</avrtoolinterface>
<avrtoolinterfaceclock>125000</avrtoolinterfaceclock>
<AsfFrameworkConfig>
<framework-data xmlns="">
<options />
<configurations />
<files />
<documentation help="" />
<offline-documentation help="" />
<dependencies>
<content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.47.0" />
</dependencies>
</framework-data>
</AsfFrameworkConfig>
<com_atmel_avrdbg_tool_atmelice>
<ToolOptions>
<InterfaceProperties>
<IspClock>125000</IspClock>
</InterfaceProperties>
<InterfaceName>ISP</InterfaceName>
</ToolOptions>
<ToolType>com.atmel.avrdbg.tool.atmelice</ToolType>
<ToolNumber>J41800099437</ToolNumber>
<ToolName>Atmel-ICE</ToolName>
</com_atmel_avrdbg_tool_atmelice>
<custom>
<ToolOptions>
<InterfaceProperties>
<IspClock>125000</IspClock>
</InterfaceProperties>
<InterfaceName>
</InterfaceName>
</ToolOptions>
<ToolType>custom</ToolType>
<ToolNumber>
</ToolNumber>
<ToolName>Custom Programming Tool</ToolName>
</custom>
<AAFDebugger>
<AAFDebugFiles>
<DebugFile>
<path>\Debug\ds3231.lss</path>
<AAFSetting>
<Label>Lss Files</Label>
<Extention>.lss</Extention>
<Regex>^\s*(?&lt;address&gt;[a-f0-9]*):\s*.*$</Regex>
<DebugEnabled>true</DebugEnabled>
<RegexGroups>address</RegexGroups>
<DebuggerExpression>$pc</DebuggerExpression>
</AAFSetting>
</DebugFile>
</AAFDebugFiles>
</AAFDebugger>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<ToolchainSettings>
<AvrGccCpp>
<avrgcc.common.Device>-mmcu=atmega328p</avrgcc.common.Device>
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>NDEBUG</Value>
</ListValues>
</avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
</ListValues>
</avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.compiler.warnings.ExtraWarnings>True</avrgcc.compiler.warnings.ExtraWarnings>
<avrgcc.compiler.warnings.Pedantic>True</avrgcc.compiler.warnings.Pedantic>
<avrgcc.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -std=c11</avrgcc.compiler.miscellaneous.OtherFlags>
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>NDEBUG</Value>
</ListValues>
</avrgcccpp.compiler.symbols.DefSymbols>
<avrgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
</ListValues>
</avrgcccpp.compiler.directories.IncludePaths>
<avrgcccpp.compiler.optimization.level>Optimize for size (-Os)</avrgcccpp.compiler.optimization.level>
<avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcccpp.compiler.warnings.AllWarnings>True</avrgcccpp.compiler.warnings.AllWarnings>
<avrgcccpp.compiler.warnings.Pedantic>True</avrgcccpp.compiler.warnings.Pedantic>
<avrgcccpp.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -Wextra -std=c++17</avrgcccpp.compiler.miscellaneous.OtherFlags>
<avrgcccpp.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</avrgcccpp.linker.libraries.Libraries>
<avrgcccpp.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
</ListValues>
</avrgcccpp.assembler.general.IncludePaths>
</AvrGccCpp>
</ToolchainSettings>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<ToolchainSettings>
<AvrGccCpp>
<avrgcc.common.Device>-mmcu=atmega328p</avrgcc.common.Device>
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
</ListValues>
</avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.optimization.DebugLevel>Maximum (-g3)</avrgcc.compiler.optimization.DebugLevel>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.compiler.warnings.ExtraWarnings>True</avrgcc.compiler.warnings.ExtraWarnings>
<avrgcc.compiler.warnings.Pedantic>True</avrgcc.compiler.warnings.Pedantic>
<avrgcc.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -std=c11</avrgcc.compiler.miscellaneous.OtherFlags>
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</avrgcccpp.compiler.symbols.DefSymbols>
<avrgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
</ListValues>
</avrgcccpp.compiler.directories.IncludePaths>
<avrgcccpp.compiler.optimization.level>Optimize debugging experience (-Og)</avrgcccpp.compiler.optimization.level>
<avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcccpp.compiler.optimization.DebugLevel>Maximum (-g3)</avrgcccpp.compiler.optimization.DebugLevel>
<avrgcccpp.compiler.warnings.AllWarnings>True</avrgcccpp.compiler.warnings.AllWarnings>
<avrgcccpp.compiler.warnings.Pedantic>True</avrgcccpp.compiler.warnings.Pedantic>
<avrgcccpp.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -Wextra -std=c++17</avrgcccpp.compiler.miscellaneous.OtherFlags>
<avrgcccpp.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</avrgcccpp.linker.libraries.Libraries>
<avrgcccpp.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
</ListValues>
</avrgcccpp.assembler.general.IncludePaths>
<avrgcccpp.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcccpp.assembler.debugging.DebugLevel>
</AvrGccCpp>
</ToolchainSettings>
</PropertyGroup>
<ItemGroup>
<Compile Include="clock.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="ds3231\alarms.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="ds3231\ds3231.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="ds3231\flags.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="ds3231\registers.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="flash\flash.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="i2c\hardware.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="i2c\i2c.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="io\io.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="main.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\config.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\hardware.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\hardware0.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\hardware1.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\software.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\uart.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="util\func.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="util\type.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="util\util.hpp">
<SubType>compile</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="ds3231" />
<Folder Include="io" />
<Folder Include="flash" />
<Folder Include="i2c" />
<Folder Include="util" />
<Folder Include="uart" />
</ItemGroup>
<Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" />
</Project>

1
ds3231/flash Submodule

Submodule ds3231/flash added at 6edb2e5a21

1
ds3231/i2c Submodule

Submodule ds3231/i2c added at 8af5afd00d

1
ds3231/io Submodule

Submodule ds3231/io added at 80de36ee7e

188
ds3231/main.cpp Normal file
View File

@@ -0,0 +1,188 @@
#include "clock.hpp"
#include <stdlib.h>
#include "ds3231/ds3231.hpp"
#include "uart/uart.hpp"
using uart_t = uart::Uart0<>;
REGISTER_UART0_INT_VECTORS(uart_t);
static inline bool isEuDst(const rtc::DateTime &dateTime)
{
constexpr auto calcDstBegin = [](const auto &year) {
const auto beginDay = (31 - ((((5 * year) / 4) + 4) % 7));
return beginDay;
};
constexpr auto calcDstEnd = [](const auto &year) {
const auto endDay = (31 - ((((5 * year) / 4) + 1) % 7));
return endDay;
};
if (dateTime.month > 10 || dateTime.month < 3)
return false;
else if (dateTime.month > 3 && dateTime.month < 10)
return true;
else if (dateTime.month == 3) {
if (dateTime.day > calcDstBegin(dateTime.year)) {
return true;
} else if (dateTime.day == calcDstBegin(dateTime.year) && dateTime.hour >= 1)
return true;
return false;
}
// month == 10
if (dateTime.day < calcDstEnd(dateTime.year)) {
return true;
} else if (dateTime.day == calcDstEnd(dateTime.year) && dateTime.hour < 1)
return true;
return false;
}
inline uart_t &operator<<(uart_t &serial, const rtc::DateTime &dateTime)
{
serial.txNumber<uint16_t, 10, 4>(dateTime.year);
serial << '-';
serial.txNumber<uint8_t, 10, 2>(dateTime.month);
serial << '-';
serial.txNumber<uint8_t, 10, 2>(dateTime.day);
serial << ' ';
serial.txNumber<uint8_t, 10, 2>(dateTime.hour);
serial << ':';
serial.txNumber<uint8_t, 10, 2>(dateTime.minute);
serial << ':';
serial.txNumber<uint8_t, 10, 2>(dateTime.second);
return serial;
}
static inline void printLocalTime(const rtc::DateTime &dateTime)
{
const auto dst = isEuDst(dateTime);
uart_t serial;
serial << dateTime << (dst ? F(" +2") : F(" +1")) << F("\r\n");
}
static inline size_t receiveLine(char *buffer, const size_t maxLength)
{
uart_t serial;
size_t received = 0;
while (received < maxLength) {
if (serial.rxByte(*reinterpret_cast<uint8_t *>(&buffer[received]))) {
++received;
if (buffer[received - 1] == '\r' || buffer[received - 1] == '\n')
break;
}
}
return received;
}
static inline rtc::DateTime receiveTime()
{
uart_t serial;
rtc::DateTime dateTime;
constexpr auto BUF_LEN = 8;
char receiveBuffer[BUF_LEN];
serial << F("Enter year: ");
auto receivedLen = receiveLine(receiveBuffer, BUF_LEN);
receiveBuffer[receivedLen] = '\0';
dateTime.year = atoi(receiveBuffer);
serial << F("\r\nEnter month: ");
receivedLen = receiveLine(receiveBuffer, BUF_LEN);
receiveBuffer[receivedLen] = '\0';
dateTime.month = atoi(receiveBuffer);
serial << F("\r\nEnter date: ");
receivedLen = receiveLine(receiveBuffer, BUF_LEN);
receiveBuffer[receivedLen] = '\0';
dateTime.day = atoi(receiveBuffer);
serial << F("\r\nEnter hour: ");
receivedLen = receiveLine(receiveBuffer, BUF_LEN);
receiveBuffer[receivedLen] = '\0';
dateTime.hour = atoi(receiveBuffer);
serial << F("\r\nEnter minute: ");
receivedLen = receiveLine(receiveBuffer, BUF_LEN);
receiveBuffer[receivedLen] = '\0';
dateTime.minute = atoi(receiveBuffer);
serial << F("\r\nEnter second: ");
receivedLen = receiveLine(receiveBuffer, BUF_LEN);
receiveBuffer[receivedLen] = '\0';
dateTime.second = atoi(receiveBuffer);
serial << F("\r\n");
return dateTime;
}
int main()
{
uart_t serial;
rtc::DS3231<i2c::Hardware<100'000>, false> ds3231;
io::Pin<io::P::C3> rtcPwr;
rtcPwr = false;
rtcPwr.dir(io::Dir::OUT);
rtcPwr = true;
_delay_ms(1000);
ds3231.init();
serial.init();
ds3231.clearAlarm1();
ds3231.clearAlarm2();
rtc::DateTime alarmTime;
alarmTime.second = 17;
alarmTime.minute = 54;
ds3231.setAlarm1(alarmTime, rtc::Alarm1Rate::WHEN_S_MATCH);
ds3231.setAlarm2(alarmTime, rtc::Alarm2Rate::WHEN_M_MATCH);
auto oldDate = ds3231.getDateTime();
while (true) {
const auto date = ds3231.getDateTime();
if (oldDate != date) {
oldDate = date;
printLocalTime(date);
}
if (ds3231.checkAlarm1()) {
serial << F("Alarm1!\r\n");
ds3231.clearAlarm1();
}
if (ds3231.checkAlarm2()) {
serial << F("Alarm2!\r\n");
ds3231.clearAlarm2();
}
uint8_t receivedByte;
if (serial.rxByte(receivedByte)) {
if (receivedByte == 's') {
const auto newDate = receiveTime();
ds3231.setDateTime(newDate);
} else if (receivedByte == '1') {
const auto alarm = ds3231.getAlarm1();
serial << F("Alarm1: ") << alarm << F("\r\n");
} else if (receivedByte == '2') {
const auto alarm = ds3231.getAlarm2();
serial << F("Alarm2: ") << alarm << F("\r\n");
} else
serial << F("Invalid input: ") << static_cast<char>(receivedByte) << F("\r\n");
}
}
return 0;
}

1
ds3231/uart Submodule

Submodule ds3231/uart added at 119de32445

1
ds3231/util Submodule

Submodule ds3231/util added at 81b3ae244c

608
rtc.cpp
View File

@@ -1,608 +0,0 @@
/*
* DS RTC Library: DS1307 and DS3231 driver library
* (C) 2011 Akafugu Corporation
*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
*/
/*
* DS1307 register map
*
* 00h-06h: seconds, minutes, hours, day-of-week, date, month, year (all in BCD)
* bit 7 of seconds enables/disables clock
* bit 6 of hours toggles 12/24h mode (1 for 12h, 0 for 24h)
* when 12h mode is selected bit 5 is high for PM, low for AM
* 07h: control
* bit7: OUT
* bit6: 0
* bit5: 0
* bit4: SQWE
* bit3: 0
* bit2: 0
* bit1: RS0
* bit0: RS1
* 08h-3fh: 56 bytes of SRAM
*
* DS3231 register map
*
* 00h-06h: seconds, minutes, hours, day-of-week, date, month, year (all in BCD)
* bit 7 should be set to zero: The DS3231 clock is always running
* 07h: A1M1 Alarm 1 seconds
* 08h: A1M2 Alarm 1 minutes
* 09h: A1M3 Alarm 1 hour (bit6 is am/pm flag in 12h mode)
* 0ah: A1M4 Alarm 1 day/date (bit6: 1 for day, 0 for date)
* 0bh: A2M2 Alarm 2 minutes
* 0ch: A2M3 Alarm 2 hour (bit6 is am/pm flag in 12h mode)
* 0dh: A2M4 Alarm 2 day/data (bit6: 1 for day, 0 for date)
* <see data sheet page12 for Alarm register mask bit tables:
* for alarm when hours, minutes and seconds match set 1000 for alarm 1>
* 0eh: control
* bit7: !EOSC
* bit6: BBSQW
* bit5: CONV
* bit4: RS2
* bit3: RS1
* bit2: INTCN
* bit1: A2IE
* bit0: A1IE
* 0fh: control/status
* bit7: OSF
* bit6: 0
* bit5: 0
* bit4: 0
* bit3: EN32kHz
* bit2: BSY
* bit1: A2F alarm 2 flag
* bit0: A1F alarm 1 flag
* 10h: aging offset (signed)
* 11h: MSB of temp (signed)
* 12h: LSB of temp in bits 7 and 6 (0.25 degrees for each 00, 01, 10, 11)
*
*/
#include <avr/io.h>
#define TRUE 1
#define FALSE 0
#include "rtc.h"
#define RTC_ADDR 0x68 // I2C address
#define CH_BIT 7 // clock halt bit
// statically allocated structure for time value
struct rtc_tm _rtc_tm;
uint8_t dec2bcd(uint8_t d)
{
return ((d/10 * 16) + (d % 10));
}
uint8_t bcd2dec(uint8_t b)
{
return ((b/16 * 10) + (b % 16));
}
uint8_t rtc_read_byte(uint8_t offset)
{
twi_begin_transmission(RTC_ADDR);
twi_send_byte(offset);
twi_end_transmission();
twi_request_from(RTC_ADDR, 1);
return twi_receive();
}
void rtc_write_byte(uint8_t b, uint8_t offset)
{
twi_begin_transmission(RTC_ADDR);
twi_send_byte(offset);
twi_send_byte(b);
twi_end_transmission();
}
static bool s_is_ds1307 = false;
static bool s_is_ds3231 = false;
void rtc_init(void)
{
// Attempt autodetection:
// 1) Read and save temperature register
// 2) Write a value to temperature register
// 3) Read back the value
// equal to the one written: DS1307, write back saved value and return
// different from written: DS3231
uint8_t temp1 = rtc_read_byte(0x11);
uint8_t temp2 = rtc_read_byte(0x12);
rtc_write_byte(0xee, 0x11);
rtc_write_byte(0xdd, 0x12);
if (rtc_read_byte(0x11) == 0xee && rtc_read_byte(0x12) == 0xdd) {
s_is_ds1307 = true;
// restore values
rtc_write_byte(temp1, 0x11);
rtc_write_byte(temp2, 0x12);
}
else {
s_is_ds3231 = true;
}
}
// Autodetection
bool rtc_is_ds1307(void) { return s_is_ds1307; }
bool rtc_is_ds3231(void) { return s_is_ds3231; }
// Autodetection override
void rtc_set_ds1307(void) { s_is_ds1307 = true; s_is_ds3231 = false; }
void rtc_set_ds3231(void) { s_is_ds1307 = false; s_is_ds3231 = true; }
struct rtc_tm* rtc_get_time(void)
{
uint8_t rtc[9];
uint8_t century = 0;
// read 7 bytes starting from register 0
// sec, min, hour, day-of-week, date, month, year
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0);
twi_end_transmission();
twi_request_from(RTC_ADDR, 7);
for (uint8_t i = 0; i < 7; i++) {
rtc[i] = twi_receive();
}
twi_end_transmission();
// Clear clock halt bit from read data
// This starts the clock for a DS1307, and has no effect for a DS3231
rtc[0] &= ~(_BV(CH_BIT)); // clear bit
_rtc_tm.sec = bcd2dec(rtc[0]);
_rtc_tm.min = bcd2dec(rtc[1]);
_rtc_tm.hour = bcd2dec(rtc[2]);
_rtc_tm.mday = bcd2dec(rtc[4]);
_rtc_tm.mon = bcd2dec(rtc[5] & 0x1F); // returns 1-12
century = (rtc[5] & 0x80) >> 7;
_rtc_tm.year = century == 1 ? 2000 + bcd2dec(rtc[6]) : 1900 + bcd2dec(rtc[6]); // year 0-99
_rtc_tm.wday = bcd2dec(rtc[3]); // returns 1-7
if (_rtc_tm.hour == 0) {
_rtc_tm.twelveHour = 0;
_rtc_tm.am = 1;
} else if (_rtc_tm.hour < 12) {
_rtc_tm.twelveHour = _rtc_tm.hour;
_rtc_tm.am = 1;
} else {
_rtc_tm.twelveHour = _rtc_tm.hour - 12;
_rtc_tm.am = 0;
}
return &_rtc_tm;
}
void rtc_get_time_s(uint8_t* hour, uint8_t* min, uint8_t* sec)
{
uint8_t rtc[9];
// read 7 bytes starting from register 0
// sec, min, hour, day-of-week, date, month, year
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0);
twi_end_transmission();
twi_request_from(RTC_ADDR, 7);
for(uint8_t i=0; i<7; i++) {
rtc[i] = twi_receive();
}
twi_end_transmission();
if (sec) *sec = bcd2dec(rtc[0]);
if (min) *min = bcd2dec(rtc[1]);
if (hour) *hour = bcd2dec(rtc[2]);
}
// fixme: support 12-hour mode for setting time
void rtc_set_time(struct rtc_tm* tm_)
{
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0);
uint8_t century;
if (tm_->year > 2000) {
century = 0x80;
tm_->year = tm_->year - 2000;
} else {
century = 0;
tm_->year = tm_->year - 1900;
}
// clock halt bit is 7th bit of seconds: this is always cleared to start the clock
twi_send_byte(dec2bcd(tm_->sec)); // seconds
twi_send_byte(dec2bcd(tm_->min)); // minutes
twi_send_byte(dec2bcd(tm_->hour)); // hours
twi_send_byte(dec2bcd(tm_->wday)); // day of week
twi_send_byte(dec2bcd(tm_->mday)); // day
twi_send_byte(dec2bcd(tm_->mon) + century); // month
twi_send_byte(dec2bcd(tm_->year)); // year
twi_end_transmission();
}
void rtc_set_time_s(uint8_t hour, uint8_t min, uint8_t sec)
{
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0);
// clock halt bit is 7th bit of seconds: this is always cleared to start the clock
twi_send_byte(dec2bcd(sec)); // seconds
twi_send_byte(dec2bcd(min)); // minutes
twi_send_byte(dec2bcd(hour)); // hours
twi_end_transmission();
}
// DS1307 only (has no effect when run on DS3231)
// halt/start the clock
// 7th bit of register 0 (second register)
// 0 = clock is running
// 1 = clock is not running
void rtc_run_clock(bool run)
{
if (s_is_ds3231) return;
uint8_t b = rtc_read_byte(0x0);
if (run)
b &= ~(_BV(CH_BIT)); // clear bit
else
b |= _BV(CH_BIT); // set bit
rtc_write_byte(b, 0x0);
}
// DS1307 only
// Returns true if the clock is running, false otherwise
// For DS3231, it always returns true
bool rtc_is_clock_running(void)
{
if (s_is_ds3231) return true;
uint8_t b = rtc_read_byte(0x0);
if (b & _BV(CH_BIT)) return false;
return true;
}
void ds3231_get_temp_int(int8_t* i, uint8_t* f)
{
uint8_t msb, lsb;
*i = 0;
*f = 0;
if (s_is_ds1307) return; // only valid on DS3231
twi_begin_transmission(RTC_ADDR);
// temp registers 0x11 and 0x12
twi_send_byte(0x11);
twi_end_transmission();
twi_request_from(RTC_ADDR, 2);
if (twi_available()) {
msb = twi_receive(); // integer part (in twos complement)
lsb = twi_receive(); // fraction part
// integer part in entire byte
*i = msb;
// fractional part in top two bits (increments of 0.25)
*f = (lsb >> 6) * 25;
// float value can be read like so:
// float temp = ((((short)msb << 8) | (short)lsb) >> 6) / 4.0f;
}
}
void rtc_force_temp_conversion(uint8_t block)
{
if (s_is_ds1307) return; // only valid on DS3231
// read control register (0x0E)
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0E);
twi_end_transmission();
twi_request_from(RTC_ADDR, 1);
uint8_t ctrl = twi_receive();
ctrl |= 0b00100000; // Set CONV bit
// write new control register value
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0E);
twi_send_byte(ctrl);
twi_end_transmission();
if (!block) return;
// Temp conversion is ready when control register becomes 0
do {
// Block until CONV is 0
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0E);
twi_end_transmission();
twi_request_from(RTC_ADDR, 1);
} while ((twi_receive() & 0b00100000) != 0);
}
#define DS1307_SRAM_ADDR 0x08
// SRAM: 56 bytes from address 0x08 to 0x3f (DS1307-only)
void rtc_get_sram(uint8_t* data)
{
// cannot receive 56 bytes in one go, because of the TWI library buffer limit
// so just receive one at a time for simplicity
for(int i=0;i<56;i++)
data[i] = rtc_get_sram_byte(i);
}
void rtc_set_sram(uint8_t *data)
{
// cannot send 56 bytes in one go, because of the TWI library buffer limit
// so just send one at a time for simplicity
for(int i=0;i<56;i++)
rtc_set_sram_byte(data[i], i);
}
uint8_t rtc_get_sram_byte(uint8_t offset)
{
twi_begin_transmission(RTC_ADDR);
twi_send_byte(DS1307_SRAM_ADDR + offset);
twi_end_transmission();
twi_request_from(RTC_ADDR, 1);
return twi_receive();
}
void rtc_set_sram_byte(uint8_t b, uint8_t offset)
{
twi_begin_transmission(RTC_ADDR);
twi_send_byte(DS1307_SRAM_ADDR + offset);
twi_send_byte(b);
twi_end_transmission();
}
void rtc_SQW_enable(bool enable)
{
if (s_is_ds1307) {
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x07);
twi_end_transmission();
// read control
twi_request_from(RTC_ADDR, 1);
uint8_t control = twi_receive();
if (enable)
control |= 0b00010000; // set SQWE to 1
else
control &= ~0b00010000; // set SQWE to 0
// write control back
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x07);
twi_send_byte(control);
twi_end_transmission();
}
else { // DS3231
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0E);
twi_end_transmission();
// read control
twi_request_from(RTC_ADDR, 1);
uint8_t control = twi_receive();
if (enable) {
control |= 0b01000000; // set BBSQW to 1
control &= ~0b00000100; // set INTCN to 0
}
else {
control &= ~0b01000000; // set BBSQW to 0
}
// write control back
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0E);
twi_send_byte(control);
twi_end_transmission();
}
}
void rtc_SQW_set_freq(enum RTC_SQW_FREQ freq)
{
if (s_is_ds1307) {
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x07);
twi_end_transmission();
// read control (uses bits 0 and 1)
twi_request_from(RTC_ADDR, 1);
uint8_t control = twi_receive();
control &= ~0b00000011; // Set to 0
control |= freq; // Set freq bitmask
// write control back
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x07);
twi_send_byte(control);
twi_end_transmission();
}
else { // DS3231
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0E);
twi_end_transmission();
// read control (uses bits 3 and 4)
twi_request_from(RTC_ADDR, 1);
uint8_t control = twi_receive();
control &= ~0b00011000; // Set to 0
control |= (freq << 4); // Set freq bitmask
// write control back
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0E);
twi_send_byte(control);
twi_end_transmission();
}
}
void rtc_osc32kHz_enable(bool enable)
{
if (!s_is_ds3231) return;
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0F);
twi_end_transmission();
// read status
twi_request_from(RTC_ADDR, 1);
uint8_t status = twi_receive();
if (enable)
status |= 0b00001000; // set to 1
else
status &= ~0b00001000; // Set to 0
// write status back
twi_begin_transmission(RTC_ADDR);
twi_send_byte(0x0F);
twi_send_byte(status);
twi_end_transmission();
}
// Alarm functionality
// fixme: should decide if "alarm disabled" mode should be available, or if alarm should always be enabled
// at 00:00:00. Currently, "alarm disabled" only works for ds3231
void rtc_reset_alarm(void)
{
if (s_is_ds1307) {
rtc_set_sram_byte(0, 0); // hour
rtc_set_sram_byte(0, 1); // minute
rtc_set_sram_byte(0, 2); // second
}
else {
// writing 0 to bit 7 of all four alarm 1 registers disables alarm
rtc_write_byte(0, 0x07); // second
rtc_write_byte(0, 0x08); // minute
rtc_write_byte(0, 0x09); // hour
rtc_write_byte(0, 0x0a); // day
}
}
// fixme: add an option to set whether or not the INTCN and Interrupt Enable flag is set when setting the alarm
void rtc_set_alarm_s(uint8_t hour, uint8_t min, uint8_t sec)
{
if (hour > 23) return;
if (min > 59) return;
if (sec > 59) return;
if (s_is_ds1307) {
rtc_set_sram_byte(hour, 0); // hour
rtc_set_sram_byte(min, 1); // minute
rtc_set_sram_byte(sec, 2); // second
}
else {
/*
* 07h: A1M1:0 Alarm 1 seconds
* 08h: A1M2:0 Alarm 1 minutes
* 09h: A1M3:0 Alarm 1 hour (bit6 is am/pm flag in 12h mode)
* 0ah: A1M4:1 Alarm 1 day/date (bit6: 1 for day, 0 for date)
* Sets alarm to fire when hour, minute and second matches
*/
rtc_write_byte(dec2bcd(sec), 0x07); // second
rtc_write_byte(dec2bcd(min), 0x08); // minute
rtc_write_byte(dec2bcd(hour), 0x09); // hour
rtc_write_byte(0b10000001, 0x0a); // day (upper bit must be set)
// clear alarm flag
uint8_t val = rtc_read_byte(0x0f);
rtc_write_byte(val & ~0b00000001, 0x0f);
}
}
void rtc_set_alarm(struct rtc_tm* tm_)
{
if (!tm_) return;
rtc_set_alarm_s(tm_->hour, tm_->min, tm_->sec);
}
void rtc_get_alarm_s(uint8_t* hour, uint8_t* min, uint8_t* sec)
{
if (s_is_ds1307) {
if (hour) *hour = rtc_get_sram_byte(0);
if (min) *min = rtc_get_sram_byte(1);
if (sec) *sec = rtc_get_sram_byte(2);
}
else {
*sec = bcd2dec(rtc_read_byte(0x07) & ~0b10000000);
*min = bcd2dec(rtc_read_byte(0x08) & ~0b10000000);
*hour = bcd2dec(rtc_read_byte(0x09) & ~0b10000000);
}
}
struct rtc_tm* rtc_get_alarm(void)
{
uint8_t hour, min, sec;
rtc_get_alarm_s(&hour, &min, &sec);
_rtc_tm.hour = hour;
_rtc_tm.min = min;
_rtc_tm.sec = sec;
return &_rtc_tm;
}
bool rtc_check_alarm(void)
{
if (s_is_ds1307) {
uint8_t hour = rtc_get_sram_byte(0);
uint8_t min = rtc_get_sram_byte(1);
uint8_t sec = rtc_get_sram_byte(2);
uint8_t cur_hour, cur_min, cur_sec;
rtc_get_time_s(&cur_hour, &cur_min, &cur_sec);
if (cur_hour == hour && cur_min == min && cur_sec == sec)
return true;
return false;
}
else {
// Alarm 1 flag (A1F) in bit 0
uint8_t val = rtc_read_byte(0x0f);
// clear flag when set
if (val & 1)
rtc_write_byte(val & ~0b00000001, 0x0f);
return val & 1 ? 1 : 0;
}
}

107
rtc.h
View File

@@ -1,107 +0,0 @@
/*
* DS RTC Library: DS1307 and DS3231 driver library
* (C) 2011 Akafugu Corporation
*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
*/
#ifndef DS1307_H
#define DS1307_H
#include <stdbool.h>
#include <avr/io.h>
#include "twi.h"
#define DS1307_SLAVE_ADDR 0b11010000
/** Time structure
*
* Both 24-hour and 12-hour time is stored, and is always updated when rtc_get_time is called.
*
* When setting time and alarm, 24-hour mode is always used.
*
* If you run your clock in 12-hour mode:
* - set time hour to store in twelveHour and set am to true or false.
* - call rtc_12h_translate (this will put the correct value in hour, so you don't have to
* calculate it yourself.
* - call rtc_set_alarm or rtc_set_clock
*
* Note that rtc_set_clock_s, rtc_set_alarm_s, rtc_get_time_s, rtc_set_alarm_s always operate in 24-hour mode
* and translation has to be done manually (you can call rtc_24h_to_12h to perform the calculation)
*
*/
struct rtc_tm {
int sec; // 0 to 59
int min; // 0 to 59
int hour; // 0 to 23
int mday; // 1 to 31
int mon; // 1 to 12
int year; // year-99
int wday; // 1-7
// 12-hour clock data
bool am; // true for AM, false for PM
int twelveHour; // 12 hour clock time
};
// statically allocated
extern struct rtc_tm _rtc_tm;
// Initialize the RTC and autodetect type (DS1307 or DS3231)
void rtc_init(void);
// Autodetection
bool rtc_is_ds1307(void);
bool rtc_is_ds3231(void);
void rtc_set_ds1307(void);
void rtc_set_ds3231(void);
// Get/set time
// Gets the time: Supports both 24-hour and 12-hour mode
struct rtc_tm* rtc_get_time(void);
// Gets the time: 24-hour mode only
void rtc_get_time_s(uint8_t* hour, uint8_t* min, uint8_t* sec);
// Sets the time: Supports both 24-hour and 12-hour mode
void rtc_set_time(struct rtc_tm* tm_);
// Sets the time: Supports 12-hour mode only
void rtc_set_time_s(uint8_t hour, uint8_t min, uint8_t sec);
// start/stop clock running (DS1307 only)
void rtc_run_clock(bool run);
bool rtc_is_clock_running(void);
// Read Temperature (DS3231 only)
void ds3231_get_temp_int(int8_t* i, uint8_t* f);
void rtc_force_temp_conversion(uint8_t block);
// SRAM read/write DS1307 only
void rtc_get_sram(uint8_t* data);
void rtc_set_sram(uint8_t *data);
uint8_t rtc_get_sram_byte(uint8_t offset);
void rtc_set_sram_byte(uint8_t b, uint8_t offset);
// Auxillary functions
enum RTC_SQW_FREQ { FREQ_1 = 0, FREQ_1024, FREQ_4096, FREQ_8192 };
void rtc_SQW_enable(bool enable);
void rtc_SQW_set_freq(enum RTC_SQW_FREQ freq);
void rtc_osc32kHz_enable(bool enable);
// Alarm functionality
void rtc_reset_alarm(void);
void rtc_set_alarm(struct rtc_tm* tm_);
void rtc_set_alarm_s(uint8_t hour, uint8_t min, uint8_t sec);
struct rtc_tm* rtc_get_alarm(void);
void rtc_get_alarm_s(uint8_t* hour, uint8_t* min, uint8_t* sec);
bool rtc_check_alarm(void);
#endif

View File

@@ -1,107 +0,0 @@
#include "systime.h"
//////////////////////////////////////////////////////////////////////////
// DST magic by Edgar Bonet
int SysTime::euDST( const time_t *pTime, int32_t *pZ )
{
static_cast<void>( pZ );
uint32_t t = *pTime;
if( static_cast<uint8_t>( t >> 24 ) >= 194 )
t -= 3029443200U;
t = ( t + 655513200 ) / 604800 * 28;
if( static_cast<uint16_t>( t % 1461 ) < 856 )
return ONE_HOUR;
return 0;
}
//////////////////////////////////////////////////////////////////////////
bool SysTime::init()
{
twi_init_master();
rtc_init();
if( !rtc_is_ds3231() )
return false;
set_zone( 1 * ONE_HOUR );
set_dst( euDST );
syncSysTime();
return true;
}
//////////////////////////////////////////////////////////////////////////
void SysTime::syncSysTime()
{
tm sTime = getTime();
set_system_time( mk_gmtime( &sTime ) );
}
//////////////////////////////////////////////////////////////////////////
bool SysTime::checkSync()
{
time_t timeNow = time( nullptr );
tm *ptmUTC = gmtime( &timeNow );
rtc_tm *ptmRtcTime = rtc_get_time();
if( ptmUTC->tm_sec != ptmRtcTime->sec || ptmUTC->tm_min != ptmRtcTime->min || ptmUTC->tm_hour != ptmRtcTime->hour )
return false;
if( ptmUTC->tm_mday != ptmRtcTime->mday || ( ptmUTC->tm_mon + 1 ) != ptmRtcTime->mon || ( ptmUTC->tm_year + 1900 ) != ptmRtcTime->year )
return false;
return true;
}
//////////////////////////////////////////////////////////////////////////
void SysTime::tick()
{
system_tick();
}
//////////////////////////////////////////////////////////////////////////
tm SysTime::getTime()
{
tm sTime;
rtc_tm *ptmTime = rtc_get_time();
sTime.tm_sec = ptmTime->sec;
sTime.tm_min = ptmTime->min;
sTime.tm_hour = ptmTime->hour;
sTime.tm_mday = ptmTime->mday;
sTime.tm_mon = ptmTime->mon - 1;
sTime.tm_year = ptmTime->year - 1900;
sTime.tm_isdst = 0;
time_t timeUTC = mk_gmtime( &sTime );
sTime = *( gmtime( &timeUTC ) );
return sTime;
}
//////////////////////////////////////////////////////////////////////////
void SysTime::setTime( const tm &sTime )
{
rtc_tm *pRtcTime = rtc_get_time();
pRtcTime->sec = sTime.tm_sec;
pRtcTime->min = sTime.tm_min;
pRtcTime->hour = sTime.tm_hour;
pRtcTime->mday = sTime.tm_mday;
pRtcTime->mon = sTime.tm_mon + 1;
pRtcTime->year = sTime.tm_year + 1900;
pRtcTime->wday = sTime.tm_wday + 1;
pRtcTime->am = ( sTime.tm_hour < 12 ) ? true : false;
pRtcTime->twelveHour = ( sTime.tm_hour == 0 ) ? 12 : ( ( sTime.tm_hour > 12 ) ? ( sTime.tm_hour - 12 ) : sTime.tm_hour );
rtc_set_time( pRtcTime );
syncSysTime();
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright (c) by BlackMark 2017
* Date 17/12/2016
* Version 1.0
*/
#ifndef SYSTIME_H
#define SYSTIME_H
#include <time.h>
#include "twi.h"
#include "rtc.h"
class SysTime
{
private:
static int euDST( const time_t *pTime, int32_t *pZ );
public:
static bool init();
static void syncSysTime();
static bool checkSync();
static void tick();
static tm getTime();
static void setTime( const tm &sTime );
};
#endif

View File

@@ -1,476 +0,0 @@
/*
twi.c - TWI/I2C library for Wiring & Arduino
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <math.h>
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <compat/twi.h>
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#include "twi-lowlevel.h"
static volatile uint8_t twi_state;
static uint8_t twi_slarw;
static void (*twi_onSlaveTransmit)(void);
static void (*twi_onSlaveReceive)(uint8_t*, int);
static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
static volatile uint8_t twi_masterBufferIndex;
static uint8_t twi_masterBufferLength;
static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
static volatile uint8_t twi_txBufferIndex;
static volatile uint8_t twi_txBufferLength;
static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
static volatile uint8_t twi_rxBufferIndex;
static volatile uint8_t twi_error;
/*
* Function twi_init
* Desc readys twi pins and sets twi bitrate
* Input none
* Output none
*/
void twi_init(void)
{
// initialize state
twi_state = TWI_READY;
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__)
// activate internal pull-ups for twi
// as per note from atmega8 manual pg167
sbi(PORTC, 4);
sbi(PORTC, 5);
#else
// activate internal pull-ups for twi
// as per note from atmega128 manual pg204
sbi(PORTD, 0);
sbi(PORTD, 1);
#endif
// initialize twi prescaler and bit rate
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
/* twi bit rate formula from atmega128 manual pg 204
SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
note: TWBR should be 10 or higher for master mode
It is 72 for a 16mhz Wiring board with 100kHz TWI */
// enable twi module, acks, and twi interrupt
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
}
/*
* Function twi_slaveInit
* Desc sets slave address and enables interrupt
* Input none
* Output none
*/
void twi_setAddress(uint8_t address)
{
// set twi slave address (skip over TWGCE bit)
TWAR = address << 1;
}
/*
* Function twi_readFrom
* Desc attempts to become twi bus master and read a
* series of bytes from a device on the bus
* Input address: 7bit i2c device address
* data: pointer to byte array
* length: number of bytes to read into array
* Output number of bytes read
*/
uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
{
uint8_t i;
// ensure data will fit into buffer
if(TWI_BUFFER_LENGTH < length){
return 0;
}
// wait until twi is ready, become master receiver
while(TWI_READY != twi_state){
continue;
}
twi_state = TWI_MRX;
// reset error state (0xFF.. no error occured)
twi_error = 0xFF;
// initialize buffer iteration vars
twi_masterBufferIndex = 0;
twi_masterBufferLength = length-1; // This is not intuitive, read on...
// On receive, the previously configured ACK/NACK setting is transmitted in
// response to the received byte before the interrupt is signalled.
// Therefor we must actually set NACK when the _next_ to last byte is
// received, causing that NACK to be sent in response to receiving the last
// expected byte of data.
// build sla+w, slave device address + w bit
twi_slarw = TW_READ;
twi_slarw |= address << 1;
// send start condition
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
// wait for read operation to complete
while(TWI_MRX == twi_state){
continue;
}
if (twi_masterBufferIndex < length)
length = twi_masterBufferIndex;
// copy twi buffer to data
for(i = 0; i < length; ++i){
data[i] = twi_masterBuffer[i];
}
return length;
}
/*
* Function twi_writeTo
* Desc attempts to become twi bus master and write a
* series of bytes to a device on the bus
* Input address: 7bit i2c device address
* data: pointer to byte array
* length: number of bytes in array
* wait: boolean indicating to wait for write or not
* Output 0 .. success
* 1 .. length to long for buffer
* 2 .. address send, NACK received
* 3 .. data send, NACK received
* 4 .. other twi error (lost bus arbitration, bus error, ..)
*/
uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait)
{
uint8_t i;
// ensure data will fit into buffer
if(TWI_BUFFER_LENGTH < length){
return 1;
}
// wait until twi is ready, become master transmitter
while(TWI_READY != twi_state){
continue;
}
twi_state = TWI_MTX;
// reset error state (0xFF.. no error occured)
twi_error = 0xFF;
// initialize buffer iteration vars
twi_masterBufferIndex = 0;
twi_masterBufferLength = length;
// copy data to twi buffer
for(i = 0; i < length; ++i){
twi_masterBuffer[i] = data[i];
}
// build sla+w, slave device address + w bit
twi_slarw = TW_WRITE;
twi_slarw |= address << 1;
// send start condition
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
// wait for write operation to complete
while(wait && (TWI_MTX == twi_state)){
continue;
}
if (twi_error == 0xFF)
return 0; // success
else if (twi_error == TW_MT_SLA_NACK)
return 2; // error: address send, nack received
else if (twi_error == TW_MT_DATA_NACK)
return 3; // error: data send, nack received
else
return 4; // other twi error
}
/*
* Function twi_transmit
* Desc fills slave tx buffer with data
* must be called in slave tx event callback
* Input data: pointer to byte array
* length: number of bytes in array
* Output 1 length too long for buffer
* 2 not slave transmitter
* 0 ok
*/
uint8_t twi_transmit(uint8_t* data, uint8_t length)
{
uint8_t i;
// ensure data will fit into buffer
if(TWI_BUFFER_LENGTH < length){
return 1;
}
// ensure we are currently a slave transmitter
if(TWI_STX != twi_state){
return 2;
}
// set length and copy data into tx buffer
twi_txBufferLength = length;
for(i = 0; i < length; ++i){
twi_txBuffer[i] = data[i];
}
return 0;
}
/*
* Function twi_attachSlaveRxEvent
* Desc sets function called before a slave read operation
* Input function: callback function to use
* Output none
*/
void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) )
{
twi_onSlaveReceive = function;
}
/*
* Function twi_attachSlaveTxEvent
* Desc sets function called before a slave write operation
* Input function: callback function to use
* Output none
*/
void twi_attachSlaveTxEvent( void (*function)(void) )
{
twi_onSlaveTransmit = function;
}
/*
* Function twi_reply
* Desc sends byte or readys receive line
* Input ack: byte indicating to ack or to nack
* Output none
*/
void twi_reply(uint8_t ack)
{
// transmit master read ready signal, with or without ack
if(ack){
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
}else{
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
}
}
/*
* Function twi_stop
* Desc relinquishes bus master status
* Input none
* Output none
*/
void twi_stop(void)
{
// send stop condition
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
// wait for stop condition to be exectued on bus
// TWINT is not set after a stop condition!
while(TWCR & _BV(TWSTO)){
continue;
}
// update twi state
twi_state = TWI_READY;
}
/*
* Function twi_releaseBus
* Desc releases bus control
* Input none
* Output none
*/
void twi_releaseBus(void)
{
// release bus
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
// update twi state
twi_state = TWI_READY;
}
SIGNAL(TWI_vect)
{
switch(TW_STATUS){
// All Master
case TW_START: // sent start condition
case TW_REP_START: // sent repeated start condition
// copy device address and r/w bit to output register and ack
TWDR = twi_slarw;
twi_reply(1);
break;
// Master Transmitter
case TW_MT_SLA_ACK: // slave receiver acked address
case TW_MT_DATA_ACK: // slave receiver acked data
// if there is data to send, send it, otherwise stop
if(twi_masterBufferIndex < twi_masterBufferLength){
// copy data to output register and ack
TWDR = twi_masterBuffer[twi_masterBufferIndex++];
twi_reply(1);
}else{
twi_stop();
}
break;
case TW_MT_SLA_NACK: // address sent, nack received
twi_error = TW_MT_SLA_NACK;
twi_stop();
break;
case TW_MT_DATA_NACK: // data sent, nack received
twi_error = TW_MT_DATA_NACK;
twi_stop();
break;
case TW_MT_ARB_LOST: // lost bus arbitration
twi_error = TW_MT_ARB_LOST;
twi_releaseBus();
break;
// Master Receiver
case TW_MR_DATA_ACK: // data received, ack sent
// put byte into buffer
twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
case TW_MR_SLA_ACK: // address sent, ack received
// ack if more bytes are expected, otherwise nack
if(twi_masterBufferIndex < twi_masterBufferLength){
twi_reply(1);
}else{
twi_reply(0);
}
break;
case TW_MR_DATA_NACK: // data received, nack sent
// put final byte into buffer
twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
case TW_MR_SLA_NACK: // address sent, nack received
twi_stop();
break;
// TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case
// Slave Receiver
case TW_SR_SLA_ACK: // addressed, returned ack
case TW_SR_GCALL_ACK: // addressed generally, returned ack
case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack
case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack
// enter slave receiver mode
twi_state = TWI_SRX;
// indicate that rx buffer can be overwritten and ack
twi_rxBufferIndex = 0;
twi_reply(1);
break;
case TW_SR_DATA_ACK: // data received, returned ack
case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
// if there is still room in the rx buffer
if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
// put byte in buffer and ack
twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
twi_reply(1);
}else{
// otherwise nack
twi_reply(0);
}
break;
case TW_SR_STOP: // stop or repeated start condition received
// put a null char after data if there's room
if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
twi_rxBuffer[twi_rxBufferIndex] = '\0';
}
// sends ack and stops interface for clock stretching
twi_stop();
// callback to user defined callback
twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
// since we submit rx buffer to "wire" library, we can reset it
twi_rxBufferIndex = 0;
// ack future responses and leave slave receiver state
twi_releaseBus();
break;
case TW_SR_DATA_NACK: // data received, returned nack
case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack
// nack back at master
twi_reply(0);
break;
// Slave Transmitter
case TW_ST_SLA_ACK: // addressed, returned ack
case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
// enter slave transmitter mode
twi_state = TWI_STX;
// ready the tx buffer index for iteration
twi_txBufferIndex = 0;
// set tx buffer length to be zero, to verify if user changes it
twi_txBufferLength = 0;
// request for txBuffer to be filled and length to be set
// note: user must call twi_transmit(bytes, length) to do this
twi_onSlaveTransmit();
// if they didn't change buffer & length, initialize it
if(0 == twi_txBufferLength){
twi_txBufferLength = 1;
twi_txBuffer[0] = 0x00;
}
// transmit first byte from buffer, fall
case TW_ST_DATA_ACK: // byte sent, ack returned
// copy data to output register
TWDR = twi_txBuffer[twi_txBufferIndex++];
// if there is more to send, ack, otherwise nack
if(twi_txBufferIndex < twi_txBufferLength){
twi_reply(1);
}else{
twi_reply(0);
}
break;
case TW_ST_DATA_NACK: // received nack, we are done
case TW_ST_LAST_DATA: // received ack, but we are done already!
// ack future responses
twi_reply(1);
// leave slave receiver state
twi_state = TWI_READY;
break;
// All
case TW_NO_INFO: // no state information
break;
case TW_BUS_ERROR: // bus error, illegal stop/start
twi_error = TW_BUS_ERROR;
twi_stop();
break;
}
}

View File

@@ -1,55 +0,0 @@
/*
twi.h - TWI/I2C library for Wiring & Arduino
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef twi_h
#define twi_h
#include <inttypes.h>
#include "../clock.h"
//#define ATMEGA8
#ifndef TWI_FREQ
#define TWI_FREQ 100000L
#endif
#ifndef TWI_BUFFER_LENGTH
#define TWI_BUFFER_LENGTH 32
#endif
#define TWI_READY 0
#define TWI_MRX 1
#define TWI_MTX 2
#define TWI_SRX 3
#define TWI_STX 4
void twi_init(void);
void twi_setAddress(uint8_t);
uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t);
uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t);
uint8_t twi_transmit(uint8_t*, uint8_t);
void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
void twi_attachSlaveTxEvent( void (*)(void) );
void twi_reply(uint8_t);
void twi_stop(void);
void twi_releaseBus(void);
#endif

226
twi.cpp
View File

@@ -1,226 +0,0 @@
/*
TwoWire.cpp - TWI/I2C library for Wiring & Arduino
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "twi-lowlevel.h"
#include "twi.h"
// local variables
uint8_t rxBuffer[BUFFER_LENGTH];
uint8_t rxBufferIndex = 0;
uint8_t rxBufferLength = 0;
uint8_t txAddress = 0;
uint8_t txBuffer[BUFFER_LENGTH];
uint8_t txBufferIndex = 0;
uint8_t txBufferLength = 0;
uint8_t transmitting = 0;
void (*user_onRequest)(void);
void (*user_onReceive)(int);
void onRequestService(void);
void onReceiveService(uint8_t*, int);
void twi_init_master(void)
{
rxBufferIndex = 0;
rxBufferLength = 0;
txBufferIndex = 0;
txBufferLength = 0;
twi_init();
}
void twi_init_slave(uint8_t address)
{
twi_setAddress(address);
twi_attachSlaveTxEvent(onRequestService);
twi_attachSlaveRxEvent(onReceiveService);
twi_init_master();
}
uint8_t twi_request_from(uint8_t address, uint8_t quantity)
{
// clamp to buffer length
if(quantity > BUFFER_LENGTH){
quantity = BUFFER_LENGTH;
}
// perform blocking read into buffer
uint8_t read = twi_readFrom(address, rxBuffer, quantity);
// set rx buffer iterator vars
rxBufferIndex = 0;
rxBufferLength = read;
return read;
}
void twi_begin_transmission(uint8_t address)
{
// indicate that we are transmitting
transmitting = 1;
// set address of targeted slave
txAddress = address;
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
}
uint8_t twi_end_transmission(void)
{
// transmit buffer (blocking)
int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1);
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
// indicate that we are done transmitting
transmitting = 0;
return ret;
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
void twi_send_byte(uint8_t data)
{
if(transmitting){
// in master transmitter mode
// don't bother if buffer is full
if(txBufferLength >= BUFFER_LENGTH){
return;
}
// put byte in tx buffer
txBuffer[txBufferIndex] = data;
++txBufferIndex;
// update amount in buffer
txBufferLength = txBufferIndex;
}else{
// in slave send mode
// reply to master
twi_transmit(&data, 1);
}
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
void twi_send(uint8_t* data, uint8_t quantity)
{
if(transmitting){
// in master transmitter mode
for(uint8_t i = 0; i < quantity; ++i){
twi_send_byte(data[i]);
}
}else{
// in slave send mode
// reply to master
twi_transmit(data, quantity);
}
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
void twi_send_char(char* data)
{
twi_send((uint8_t*)data, strlen(data));
}
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
uint8_t twi_available(void)
{
return rxBufferLength - rxBufferIndex;
}
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
uint8_t twi_receive(void)
{
// default to returning null char
// for people using with char strings
uint8_t value = '\0';
// get each successive byte on each call
if(rxBufferIndex < rxBufferLength){
value = rxBuffer[rxBufferIndex];
++rxBufferIndex;
}
return value;
}
// behind the scenes function that is called when data is received
void onReceiveService(uint8_t* inBytes, int numBytes)
{
// don't bother if user hasn't registered a callback
if(!user_onReceive){
return;
}
// don't bother if rx buffer is in use by a master requestFrom() op
// i know this drops data, but it allows for slight stupidity
// meaning, they may not have read all the master requestFrom() data yet
if(rxBufferIndex < rxBufferLength){
return;
}
// copy twi rx buffer into local read buffer
// this enables new reads to happen in parallel
for(uint8_t i = 0; i < numBytes; ++i){
rxBuffer[i] = inBytes[i];
}
// set rx iterator vars
rxBufferIndex = 0;
rxBufferLength = numBytes;
// alert user program
user_onReceive(numBytes);
}
// behind the scenes function that is called when data is requested
void onRequestService(void)
{
// don't bother if user hasn't registered a callback
if(!user_onRequest){
return;
}
// reset tx buffer iterator vars
// !!! this will kill any pending pre-master sendTo() activity
txBufferIndex = 0;
txBufferLength = 0;
// alert user program
user_onRequest();
}
// sets function called on slave write
void twi_set_on_receive( void (*function)(int) )
{
user_onReceive = function;
}
// sets function called on slave read
void twi_set_on_request( void (*function)(void) )
{
user_onRequest = function;
}

40
twi.h
View File

@@ -1,40 +0,0 @@
/*
TwoWire.h - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef TwoWire_h
#define TwoWire_h
#include <inttypes.h>
#define BUFFER_LENGTH 32
void twi_init_master(void);
void twi_init_slave(uint8_t);
void twi_begin_transmission(uint8_t);
uint8_t twi_end_transmission(void);
uint8_t twi_request_from(uint8_t, uint8_t);
void twi_send_byte(uint8_t);
void twi_send(uint8_t*, uint8_t);
void twi_send_char(char*);
uint8_t twi_available(void);
uint8_t twi_receive(void);
void twi_set_on_receive( void (*)(int) );
void twi_set_on_request( void (*)(void) );
#endif