Browse Source

refactoring (wip)

timer1
Youen Toupin 10 years ago
parent
commit
22e5d690a0
  1. 31
      LowLevel.h
  2. 8
      OneWireIO.ino
  3. 3
      OneWireIO.sln
  4. 37
      OneWireIO.vcxproj
  5. 2
      OneWireIO.vcxproj.filters
  6. 196
      OneWireSlave.cpp
  7. 35
      OneWireSlave.h

31
LowLevel.h

@ -71,23 +71,34 @@
class Pin class Pin
{ {
private: private:
IO_REG_TYPE mask; IO_REG_TYPE mask_;
volatile IO_REG_TYPE *reg; volatile IO_REG_TYPE *reg_;
byte interruptNumber_;
public: public:
inline Pin(uint8_t pin) Pin(uint8_t pin)
{ {
mask = PIN_TO_BITMASK(pin); mask_ = PIN_TO_BITMASK(pin);
reg = PIN_TO_BASEREG(pin); reg_ = PIN_TO_BASEREG(pin);
switch (pin)
{
case 2: interruptNumber_ = 0; break;
case 3: interruptNumber_ = 1; break;
default: interruptNumber_ = (byte)-1;
}
} }
inline void inputMode() { DIRECT_MODE_INPUT(reg, mask); } inline void inputMode() { DIRECT_MODE_INPUT(reg_, mask_); }
inline void outputMode() { DIRECT_MODE_OUTPUT(reg, mask); } inline void outputMode() { DIRECT_MODE_OUTPUT(reg_, mask_); }
inline bool read() { return DIRECT_READ(reg, mask); } inline bool read() { return DIRECT_READ(reg_, mask_) == 1; }
inline void writeLow() { DIRECT_WRITE_LOW(reg, mask); } inline void writeLow() { DIRECT_WRITE_LOW(reg_, mask_); }
inline void writeHigh() { DIRECT_WRITE_HIGH(reg, mask); } inline void writeHigh() { DIRECT_WRITE_HIGH(reg_, mask_); }
inline void write(bool value) { if (value) writeHigh(); else writeLow(); } inline void write(bool value) { if (value) writeHigh(); else writeLow(); }
inline void attachInterrupt(void (*handler)(), int mode) { ::attachInterrupt(interruptNumber_, handler, mode); }
inline void detachInterrupt() { ::detachInterrupt(interruptNumber_); }
}; };
#endif #endif

8
OneWireIO.ino

@ -16,7 +16,6 @@ OneWireSlave oneWire(owROM, OWPin);
void setup() void setup()
{ {
led.outputMode(); led.outputMode();
led.writeLow(); led.writeLow();
oneWire.enable(); oneWire.enable();
@ -24,14 +23,15 @@ void setup()
Serial.begin(9600); Serial.begin(9600);
} }
//int count = 0; int count = 0;
void loop() void loop()
{ {
/*if (count++ == 10000) delay(1);
if (count++ == 1000)
{ {
led.write(!led.read()); led.write(!led.read());
count = 0; count = 0;
}*/ }
cli();//disable interrupts cli();//disable interrupts
SerialChannel::swap(); SerialChannel::swap();

3
OneWireIO.sln

@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OneWireIO", "OneWireIO.vcxproj", "{3B500971-1570-460F-81C3-22AC3B7764B9}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OneWireIO", "OneWireIO.vcxproj", "{3B500971-1570-460F-81C3-22AC3B7764B9}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerialMonitor", "SerialMonitor\SerialMonitor\SerialMonitor.csproj", "{97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerialMonitor", "SerialMonitor\SerialMonitor\SerialMonitor.csproj", "{97704F53-6CA1-4155-9E8F-AEBFEEC20A8B}"
ProjectSection(ProjectDependencies) = postProject
{3B500971-1570-460F-81C3-22AC3B7764B9} = {3B500971-1570-460F-81C3-22AC3B7764B9}
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

37
OneWireIO.vcxproj

@ -50,6 +50,23 @@
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
<PostBuildEvent>
<Command>if exist $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf (
echo Elf generated
) else (
echo no output
exit /B 1
)</Command>
</PostBuildEvent>
<PostBuildEvent />
<CustomBuild>
<Command>if exist $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf (
echo Elf generated
) else (
echo no output
exit /B 1
)</Command>
</CustomBuild>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
@ -66,13 +83,25 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<None Include="OneWireIO.ino"> <CustomBuild Include="OneWireIO.ino">
<FileType>Document</FileType> <FileType>Document</FileType>
</None> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">if exist $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf del $(ProjectDir)$(IntDir)$(ProjectName).cpp.elf
D:\Outils\Arduino\arduino.exe --pref build.path=$(ProjectDir)$(IntDir) --upload %(FullPath)
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">always_build_$(ProjectConfiguration).dummy</Outputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Building and uploading sketch...</Message>
</CustomBuild>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="OneWireSlave.cpp" /> <ClCompile Include="OneWireSlave.cpp">
<ClCompile Include="SerialChannel.cpp" /> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="SerialChannel.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="LowLevel.h" /> <ClInclude Include="LowLevel.h" />

2
OneWireIO.vcxproj.filters

@ -10,6 +10,6 @@
<ClInclude Include="OneWireSlave.h" /> <ClInclude Include="OneWireSlave.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="OneWireIO.ino" /> <CustomBuild Include="OneWireIO.ino" />
</ItemGroup> </ItemGroup>
</Project> </Project>

196
OneWireSlave.cpp

@ -1,18 +1,77 @@
#include "OneWireSlave.h" #include "OneWireSlave.h"
OneWireSlave::OneWireSlave(byte* rom, byte pinNumber) #define DEBUG_LOG
#ifdef DEBUG_LOG
#include "SerialChannel.h"
extern SerialChannel debug;
Pin dbgOutput(3);
#endif
namespace
{
const unsigned long ResetMinDuration = 480;
const unsigned long ResetMaxDuration = 900;
const unsigned long PresenceWaitDuration = 30;
const unsigned long PresenceDuration = 300;
//const unsigned long ReadBitSamplingTime = 30;
const unsigned long SendBitDuration = 35;
void(*timerEvent)() = 0;
}
OneWireSlave* OneWireSlave::inst_ = 0;
ISR(TIMER1_COMPA_vect) // timer1 interrupt
{ {
TCCR1B = 0; // disable clock
void(*event)() = timerEvent;
timerEvent = 0;
event();
}
OneWireSlave::OneWireSlave(byte* rom, byte pinNumber)
: pin_(pinNumber)
, resetStart_((unsigned long)-1)
, lastReset_(0)
{
inst_ = this; // we can have only one instance in the current implementation
memcpy(rom_, rom, 7);
rom_[7] = crc8_(rom_, 7);
} }
void OneWireSlave::enable() void OneWireSlave::enable()
{ {
#ifdef DEBUG_LOG
debug.append("Enabling 1-wire library");
#endif
cli(); // disable interrupts
pin_.inputMode();
// prepare hardware timer
TCCR1A = 0;
TCCR1B = 0;
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
tccr1bEnable_ = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler
beginWaitReset_();
sei(); // enable interrupts
} }
void OneWireSlave::disable() void OneWireSlave::disable()
{ {
#ifdef DEBUG_LOG
debug.append("Disabling 1-wire library");
#endif
cli();
disableTimer_();
pin_.detachInterrupt();
releaseBus_();
sei();
} }
bool OneWireSlave::read(byte& b) bool OneWireSlave::read(byte& b)
@ -29,3 +88,138 @@ void OneWireSlave::write(byte* bytes, short numBytes, void(*complete)(bool error
{ {
} }
byte OneWireSlave::crc8_(byte* data, short numBytes)
{
byte crc = 0;
while (numBytes--) {
byte inbyte = *data++;
for (byte i = 8; i; i--) {
byte mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
void OneWireSlave::setTimerEvent_(short delayMicroSeconds, void(*handler)())
{
delayMicroSeconds -= 10; // remove overhead (tuned on Arduino Uno)
short skipTicks = (delayMicroSeconds - 3) / 4; // round the micro seconds delay to a number of ticks to skip (4us per tick, so 4us must skip 0 tick, 8us must skip 1 tick, etc.)
if (skipTicks < 1) skipTicks = 1;
TCNT1 = 0;
OCR1A = skipTicks;
timerEvent = handler;
TCCR1B = tccr1bEnable_;
}
void OneWireSlave::disableTimer_()
{
TCCR1B = 0;
}
void OneWireSlave::onEnterInterrupt_()
{
dbgOutput.outputMode();
dbgOutput.writeLow();
}
void OneWireSlave::onLeaveInterrupt_()
{
dbgOutput.writeHigh();
}
void OneWireSlave::error_(const char* message)
{
#ifdef DEBUG_LOG
debug.append(message);
#endif
beginWaitReset_();
}
void OneWireSlave::pullLow_()
{
pin_.outputMode();
pin_.writeLow();
}
void OneWireSlave::releaseBus_()
{
pin_.inputMode();
}
void OneWireSlave::beginWaitReset_()
{
disableTimer_();
pin_.attachInterrupt(&OneWireSlave::waitResetHandler_, CHANGE);
resetStart_ = (unsigned int)-1;
}
void OneWireSlave::waitReset_()
{
onEnterInterrupt_();
bool state = pin_.read();
unsigned long now = micros();
if (state)
{
if (resetStart_ == (unsigned int)-1)
{
onLeaveInterrupt_();
return;
}
unsigned long resetDuration = now - resetStart_;
resetStart_ = (unsigned int)-1;
if (resetDuration >= ResetMinDuration)
{
if (resetDuration > ResetMaxDuration)
{
error_("Reset too long");
onLeaveInterrupt_();
return;
}
lastReset_ = now;
setTimerEvent_(PresenceWaitDuration - (micros() - now), &OneWireSlave::beginPresenceHandler_);
}
}
else
{
resetStart_ = now;
}
onLeaveInterrupt_();
}
void OneWireSlave::beginPresence_()
{
unsigned long now = micros();
pullLow_();
setTimerEvent_(PresenceDuration, &OneWireSlave::endPresenceHandler_);
#ifdef DEBUG_LOG
debug.SC_APPEND_STR_TIME("reset", lastReset_);
debug.SC_APPEND_STR_TIME("beginPresence", now);
#endif
}
void OneWireSlave::endPresence_()
{
unsigned long now = micros();
releaseBus_();
#ifdef DEBUG_LOG
debug.SC_APPEND_STR_TIME("endPresence", now);
#endif
beginWaitCommand_();
}
void OneWireSlave::beginWaitCommand_()
{
/*pin_.attachInterrupt(&OneWireSlave::waitCommand_, FALLING);
receivingByte = 0;
receivingBitPos = 0;
bitStart = (unsigned long)-1;*/
}

35
OneWireSlave.h

@ -2,6 +2,7 @@
#define _OneWireSlave_h_ #define _OneWireSlave_h_
#include "Arduino.h" #include "Arduino.h"
#include "LowLevel.h"
class OneWireSlave class OneWireSlave
{ {
@ -23,6 +24,40 @@ public:
///! Enqueues the specified bytes in the send buffer. They will be sent in the background. The optional callback is used to notify when the bytes are sent, or if an error occured. Callbacks are executed from interrupts and should be as short as possible. ///! Enqueues the specified bytes in the send buffer. They will be sent in the background. The optional callback is used to notify when the bytes are sent, or if an error occured. Callbacks are executed from interrupts and should be as short as possible.
void write(byte* bytes, short numBytes, void(*complete)(bool error)); void write(byte* bytes, short numBytes, void(*complete)(bool error));
private:
byte crc8_(byte* data, short numBytes);
void setTimerEvent_(short delayMicroSeconds, void(*handler)());
void disableTimer_();
void onEnterInterrupt_();
void onLeaveInterrupt_();
void error_(const char* message);
void pullLow_();
void releaseBus_();
void beginWaitReset_();
void beginWaitCommand_();
// interrupt handlers
inline static void waitResetHandler_() { inst_->waitReset_(); }
void waitReset_();
inline static void beginPresenceHandler_() { inst_->beginPresence_(); }
void beginPresence_();
inline static void endPresenceHandler_() { inst_->endPresence_(); }
void endPresence_();
private:
static OneWireSlave* inst_;
byte rom_[8];
Pin pin_;
byte tccr1bEnable_;
unsigned long resetStart_;
unsigned long lastReset_;
}; };
#endif #endif

Loading…
Cancel
Save