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.
SignalGenerator.cpp
- Committer:
- taylorza
- Date:
- 2014-09-14
- Revision:
- 4:64d2d834341b
- Parent:
- 3:f30dcc6e8e70
File content as of revision 4:64d2d834341b:
/////////////////////////////////////////////////////////////////////////////// // Signal Generator // Author: Chris Taylor (taylorza) #include "mbed.h" #include "SignalGenerator.h" 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; } void SignalGenerator::set( 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; if (carrierFrequency > 0) { int timingIndex = 0; bool pinState = initialState; bool carrierState = true; uint32_t carrierHalfPeriod = (500000 / carrierFrequency); uint32_t compare = timingBuffer[timingIndex++]; uint32_t carrierCompare = carrierHalfPeriod; transitionTimer.start(); while(true) { bool stateChange = false; if (transitionTimer.read_us() >= compare) { pinState = !pinState; stateChange = true; if (timingIndex == lastTiming) break; compare += timingBuffer[timingIndex++]; } if (transitionTimer.read_us() >= carrierCompare) { carrierState = !carrierState; carrierCompare += carrierHalfPeriod; stateChange = true; } if (stateChange) _pin = pinState & carrierState ? 1 : 0; } if (lastStateHoldTime > 0) { compare += lastStateHoldTime; while (transitionTimer.read_us() < compare) { if (transitionTimer.read_us() >= carrierCompare) { carrierState = !carrierState; carrierCompare += carrierHalfPeriod; _pin = pinState & carrierState ? 1 : 0; } } } } else { int timingIndex = 0; uint32_t compare = timingBuffer[timingIndex++]; transitionTimer.start(); _pin = initialState ? 1 : 0; while(true) { if (transitionTimer.read_us() >= compare) { _pin = !_pin; if (timingIndex == lastTiming) break; compare += timingBuffer[timingIndex++]; } } if (lastStateHoldTime > 0) { compare += lastStateHoldTime; while (transitionTimer.read_us() < compare) { ; } } } 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; } }