Provides a simple way to generate complex square wave signals on any available pin. In addition the SignalGenerator can generate a carrier wave which is useful when generating IR signals to control electronic devices like a TV etc. The signal generation can be carried out either synchronously or asynchronously. In the case of synchronous signal generation all interrupts can optionally be disabled to improve timing accuracy.
Diff: SignalGenerator.cpp
- Revision:
- 4:64d2d834341b
- Parent:
- 3:f30dcc6e8e70
--- a/SignalGenerator.cpp Sat Sep 13 21:40:16 2014 +0000 +++ b/SignalGenerator.cpp Sun Sep 14 05:36:57 2014 +0000 @@ -4,13 +4,27 @@ #include "mbed.h" #include "SignalGenerator.h" -SignalGenerator::SignalGenerator(PinName pin) : _pin(pin) +SignalGenerator::SignalGenerator(PinName pin) + : _pin(pin), + _pTicker(NULL), + _pInternalTimingBuffer(NULL) { } + +SignalGenerator::~SignalGenerator() +{ + stopAsync(); + + if (_pTicker != NULL) + { + delete _pTicker; + } +} void SignalGenerator::set(bool pinState) { + stopAsync(); _pin = pinState ? 1 : 0; } @@ -18,17 +32,26 @@ bool initialState, uint32_t timingBuffer[], uint16_t bufferCount, + bool disableInterrupts, uint32_t lastStateHoldTime, int32_t carrierFrequency) { + stopAsync(); + if (timingBuffer == NULL || bufferCount == 0) { return; } - + + int alreadyDisabledIrq = 1; + if (disableInterrupts) + { + alreadyDisabledIrq = __disable_irq(); + } + + Timer transitionTimer; uint16_t lastTiming = bufferCount - 1; - Timer transitionTimer; if (carrierFrequency > 0) { int timingIndex = 0; @@ -37,7 +60,7 @@ uint32_t carrierHalfPeriod = (500000 / carrierFrequency); uint32_t compare = timingBuffer[timingIndex++]; uint32_t carrierCompare = carrierHalfPeriod; - + transitionTimer.start(); while(true) { @@ -78,8 +101,9 @@ { int timingIndex = 0; uint32_t compare = timingBuffer[timingIndex++]; - transitionTimer.start(); - set(initialState); + + transitionTimer.start(); + _pin = initialState ? 1 : 0; while(true) { if (transitionTimer.read_us() >= compare) @@ -98,4 +122,66 @@ } } } + + if (!alreadyDisabledIrq) __enable_irq(); +} + +void SignalGenerator::asyncStep() +{ + _pin = !_pin; + + _bufferIndex++; + if (_bufferIndex < _bufferCount) + { + _pTicker->attach_us(this, &SignalGenerator::asyncStep, _pInternalTimingBuffer[_bufferIndex]); + } + else if (_repeat) + { + _bufferIndex = 0; + _pTicker->attach_us(this, &SignalGenerator::asyncStep, _pInternalTimingBuffer[_bufferIndex]); + } + else + { + stopAsync(); + } +} + +void SignalGenerator::setAsync( + bool initialState, + uint32_t timingBuffer[], + uint16_t bufferCount, + bool repeat) +{ + stopAsync(); + + if (_pTicker == NULL) + { + _pTicker = new Timeout; + } + + _pInternalTimingBuffer = new uint32_t[bufferCount]; + _bufferCount = bufferCount; + _repeat = repeat; + _bufferIndex = 0; + + for(int i = 0; i < bufferCount; ++i) + { + _pInternalTimingBuffer[i] = timingBuffer[i] > 15 ? timingBuffer[i] - 10 : 5; + } + + _pin = initialState ? 1 : 0; + _pTicker->attach_us(this, &SignalGenerator::asyncStep, _pInternalTimingBuffer[_bufferIndex]); +} + +void SignalGenerator::stopAsync() +{ + if (_pTicker != NULL) + { + _pTicker->detach(); + } + + if (_pInternalTimingBuffer != NULL) + { + delete[] _pInternalTimingBuffer; + } } \ No newline at end of file