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.
Revision 4:64d2d834341b, committed 2014-09-14
- Comitter:
- taylorza
- Date:
- Sun Sep 14 05:36:57 2014 +0000
- Parent:
- 3:f30dcc6e8e70
- Commit message:
- Added support for asynchronous signal generation
Changed in this revision
SignalGenerator.cpp | Show annotated file Show diff for this revision Revisions of this file |
SignalGenerator.h | Show annotated file Show diff for this revision Revisions of this file |
--- 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
--- a/SignalGenerator.h Sat Sep 13 21:40:16 2014 +0000 +++ b/SignalGenerator.h Sun Sep 14 05:36:57 2014 +0000 @@ -12,13 +12,17 @@ /** Create a SignalGenerator tied to the specified pin. */ SignalGenerator(PinName pin); + /** Clean up the SignalGenerator data. */ + ~SignalGenerator(); + /** Set the state of the pin associated with the SignalGenerator. */ void set(bool pinState); - /** Set parameter and generate the corresponding signal on the pin associated with the SignalGenerator. + /** Generates the square wave signal on the pin associated with the SignalGenerator. * @param initialState Defines the initial state of the signal pin * @param timingBuffer Specificies the wime periods in microseconds before the signal pin changes state * @param bufferCount The count of transition times passed in the timingBuffer + * @param disableInterrupts If true disables interrupts during the generation of the signal * @param lastStateHoldTime The time in microseconds that the last state is held * @param carrierFrequency The carrier frequency in Hz */ @@ -26,10 +30,33 @@ bool initialState, uint32_t timingBuffer[], uint16_t bufferCount, + bool disableInterrupts, uint32_t lastStateHoldTime = 0, int32_t carrierFrequency = -1); + + /** Asynchronously generates the square wave signal on the pin associated with the SignalGenerator. + * @param initialState Defines the initial state of the signal pin + * @param timingBuffer Specificies the wime periods in microseconds before the signal pin changes state + * @param bufferCount The count of transition times passed in the timingBuffer + * @param repeat If true the signal generation will wrap around to the begining of the timingBuffer after each iteration through the buffer completes. + * @note To stop the asynchronous signal you can call any of the non-async set commands to set the pin to a final state. + */ + void setAsync( + bool initialState, + uint32_t timingBuffer[], + uint16_t bufferCount, + bool repeat); private: - DigitalOut _pin; + void asyncStep(); + void stopAsync(); + + private: + DigitalOut _pin; + Timeout *_pTicker; + uint32_t *_pInternalTimingBuffer; + uint16_t _bufferCount; + uint16_t _bufferIndex; + bool _repeat; }; #endif //__SIGNALGENERATOR_H__ \ No newline at end of file