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@4:64d2d834341b, 2014-09-14 (annotated)
- Committer:
- taylorza
- Date:
- Sun Sep 14 05:36:57 2014 +0000
- Revision:
- 4:64d2d834341b
- Parent:
- 3:f30dcc6e8e70
Added support for asynchronous signal generation
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
taylorza | 1:4a1bcc41c473 | 1 | /////////////////////////////////////////////////////////////////////////////// |
taylorza | 1:4a1bcc41c473 | 2 | // Signal Generator |
taylorza | 1:4a1bcc41c473 | 3 | // Author: Chris Taylor (taylorza) |
taylorza | 0:b7c65c0d82d3 | 4 | #include "mbed.h" |
taylorza | 0:b7c65c0d82d3 | 5 | #include "SignalGenerator.h" |
taylorza | 0:b7c65c0d82d3 | 6 | |
taylorza | 4:64d2d834341b | 7 | SignalGenerator::SignalGenerator(PinName pin) |
taylorza | 4:64d2d834341b | 8 | : _pin(pin), |
taylorza | 4:64d2d834341b | 9 | _pTicker(NULL), |
taylorza | 4:64d2d834341b | 10 | _pInternalTimingBuffer(NULL) |
taylorza | 0:b7c65c0d82d3 | 11 | { |
taylorza | 3:f30dcc6e8e70 | 12 | |
taylorza | 0:b7c65c0d82d3 | 13 | } |
taylorza | 4:64d2d834341b | 14 | |
taylorza | 4:64d2d834341b | 15 | SignalGenerator::~SignalGenerator() |
taylorza | 4:64d2d834341b | 16 | { |
taylorza | 4:64d2d834341b | 17 | stopAsync(); |
taylorza | 4:64d2d834341b | 18 | |
taylorza | 4:64d2d834341b | 19 | if (_pTicker != NULL) |
taylorza | 4:64d2d834341b | 20 | { |
taylorza | 4:64d2d834341b | 21 | delete _pTicker; |
taylorza | 4:64d2d834341b | 22 | } |
taylorza | 4:64d2d834341b | 23 | } |
taylorza | 0:b7c65c0d82d3 | 24 | |
taylorza | 0:b7c65c0d82d3 | 25 | void SignalGenerator::set(bool pinState) |
taylorza | 0:b7c65c0d82d3 | 26 | { |
taylorza | 4:64d2d834341b | 27 | stopAsync(); |
taylorza | 0:b7c65c0d82d3 | 28 | _pin = pinState ? 1 : 0; |
taylorza | 0:b7c65c0d82d3 | 29 | } |
taylorza | 0:b7c65c0d82d3 | 30 | |
taylorza | 1:4a1bcc41c473 | 31 | void SignalGenerator::set( |
taylorza | 1:4a1bcc41c473 | 32 | bool initialState, |
taylorza | 1:4a1bcc41c473 | 33 | uint32_t timingBuffer[], |
taylorza | 1:4a1bcc41c473 | 34 | uint16_t bufferCount, |
taylorza | 4:64d2d834341b | 35 | bool disableInterrupts, |
taylorza | 1:4a1bcc41c473 | 36 | uint32_t lastStateHoldTime, |
taylorza | 2:b2a449bd787f | 37 | int32_t carrierFrequency) |
taylorza | 0:b7c65c0d82d3 | 38 | { |
taylorza | 4:64d2d834341b | 39 | stopAsync(); |
taylorza | 4:64d2d834341b | 40 | |
taylorza | 2:b2a449bd787f | 41 | if (timingBuffer == NULL || bufferCount == 0) |
taylorza | 2:b2a449bd787f | 42 | { |
taylorza | 2:b2a449bd787f | 43 | return; |
taylorza | 2:b2a449bd787f | 44 | } |
taylorza | 4:64d2d834341b | 45 | |
taylorza | 4:64d2d834341b | 46 | int alreadyDisabledIrq = 1; |
taylorza | 4:64d2d834341b | 47 | if (disableInterrupts) |
taylorza | 4:64d2d834341b | 48 | { |
taylorza | 4:64d2d834341b | 49 | alreadyDisabledIrq = __disable_irq(); |
taylorza | 4:64d2d834341b | 50 | } |
taylorza | 4:64d2d834341b | 51 | |
taylorza | 4:64d2d834341b | 52 | Timer transitionTimer; |
taylorza | 3:f30dcc6e8e70 | 53 | uint16_t lastTiming = bufferCount - 1; |
taylorza | 3:f30dcc6e8e70 | 54 | |
taylorza | 0:b7c65c0d82d3 | 55 | if (carrierFrequency > 0) |
taylorza | 3:f30dcc6e8e70 | 56 | { |
taylorza | 3:f30dcc6e8e70 | 57 | int timingIndex = 0; |
taylorza | 3:f30dcc6e8e70 | 58 | bool pinState = initialState; |
taylorza | 3:f30dcc6e8e70 | 59 | bool carrierState = true; |
taylorza | 3:f30dcc6e8e70 | 60 | uint32_t carrierHalfPeriod = (500000 / carrierFrequency); |
taylorza | 3:f30dcc6e8e70 | 61 | uint32_t compare = timingBuffer[timingIndex++]; |
taylorza | 3:f30dcc6e8e70 | 62 | uint32_t carrierCompare = carrierHalfPeriod; |
taylorza | 4:64d2d834341b | 63 | |
taylorza | 3:f30dcc6e8e70 | 64 | transitionTimer.start(); |
taylorza | 3:f30dcc6e8e70 | 65 | while(true) |
taylorza | 3:f30dcc6e8e70 | 66 | { |
taylorza | 3:f30dcc6e8e70 | 67 | bool stateChange = false; |
taylorza | 3:f30dcc6e8e70 | 68 | if (transitionTimer.read_us() >= compare) |
taylorza | 3:f30dcc6e8e70 | 69 | { |
taylorza | 3:f30dcc6e8e70 | 70 | pinState = !pinState; |
taylorza | 3:f30dcc6e8e70 | 71 | stateChange = true; |
taylorza | 3:f30dcc6e8e70 | 72 | if (timingIndex == lastTiming) break; |
taylorza | 3:f30dcc6e8e70 | 73 | compare += timingBuffer[timingIndex++]; |
taylorza | 0:b7c65c0d82d3 | 74 | } |
taylorza | 3:f30dcc6e8e70 | 75 | |
taylorza | 3:f30dcc6e8e70 | 76 | if (transitionTimer.read_us() >= carrierCompare) |
taylorza | 0:b7c65c0d82d3 | 77 | { |
taylorza | 3:f30dcc6e8e70 | 78 | carrierState = !carrierState; |
taylorza | 3:f30dcc6e8e70 | 79 | carrierCompare += carrierHalfPeriod; |
taylorza | 3:f30dcc6e8e70 | 80 | stateChange = true; |
taylorza | 0:b7c65c0d82d3 | 81 | } |
taylorza | 3:f30dcc6e8e70 | 82 | |
taylorza | 3:f30dcc6e8e70 | 83 | if (stateChange) _pin = pinState & carrierState ? 1 : 0; |
taylorza | 0:b7c65c0d82d3 | 84 | } |
taylorza | 3:f30dcc6e8e70 | 85 | |
taylorza | 0:b7c65c0d82d3 | 86 | if (lastStateHoldTime > 0) |
taylorza | 0:b7c65c0d82d3 | 87 | { |
taylorza | 3:f30dcc6e8e70 | 88 | compare += lastStateHoldTime; |
taylorza | 3:f30dcc6e8e70 | 89 | while (transitionTimer.read_us() < compare) |
taylorza | 0:b7c65c0d82d3 | 90 | { |
taylorza | 3:f30dcc6e8e70 | 91 | if (transitionTimer.read_us() >= carrierCompare) |
taylorza | 0:b7c65c0d82d3 | 92 | { |
taylorza | 3:f30dcc6e8e70 | 93 | carrierState = !carrierState; |
taylorza | 3:f30dcc6e8e70 | 94 | carrierCompare += carrierHalfPeriod; |
taylorza | 3:f30dcc6e8e70 | 95 | _pin = pinState & carrierState ? 1 : 0; |
taylorza | 3:f30dcc6e8e70 | 96 | } |
taylorza | 0:b7c65c0d82d3 | 97 | } |
taylorza | 3:f30dcc6e8e70 | 98 | } |
taylorza | 0:b7c65c0d82d3 | 99 | } |
taylorza | 0:b7c65c0d82d3 | 100 | else |
taylorza | 3:f30dcc6e8e70 | 101 | { |
taylorza | 3:f30dcc6e8e70 | 102 | int timingIndex = 0; |
taylorza | 3:f30dcc6e8e70 | 103 | uint32_t compare = timingBuffer[timingIndex++]; |
taylorza | 4:64d2d834341b | 104 | |
taylorza | 4:64d2d834341b | 105 | transitionTimer.start(); |
taylorza | 4:64d2d834341b | 106 | _pin = initialState ? 1 : 0; |
taylorza | 3:f30dcc6e8e70 | 107 | while(true) |
taylorza | 3:f30dcc6e8e70 | 108 | { |
taylorza | 3:f30dcc6e8e70 | 109 | if (transitionTimer.read_us() >= compare) |
taylorza | 3:f30dcc6e8e70 | 110 | { |
taylorza | 3:f30dcc6e8e70 | 111 | _pin = !_pin; |
taylorza | 3:f30dcc6e8e70 | 112 | if (timingIndex == lastTiming) break; |
taylorza | 3:f30dcc6e8e70 | 113 | compare += timingBuffer[timingIndex++]; |
taylorza | 3:f30dcc6e8e70 | 114 | } |
taylorza | 0:b7c65c0d82d3 | 115 | } |
taylorza | 0:b7c65c0d82d3 | 116 | if (lastStateHoldTime > 0) |
taylorza | 0:b7c65c0d82d3 | 117 | { |
taylorza | 3:f30dcc6e8e70 | 118 | compare += lastStateHoldTime; |
taylorza | 3:f30dcc6e8e70 | 119 | while (transitionTimer.read_us() < compare) |
taylorza | 3:f30dcc6e8e70 | 120 | { |
taylorza | 3:f30dcc6e8e70 | 121 | ; |
taylorza | 3:f30dcc6e8e70 | 122 | } |
taylorza | 3:f30dcc6e8e70 | 123 | } |
taylorza | 0:b7c65c0d82d3 | 124 | } |
taylorza | 4:64d2d834341b | 125 | |
taylorza | 4:64d2d834341b | 126 | if (!alreadyDisabledIrq) __enable_irq(); |
taylorza | 4:64d2d834341b | 127 | } |
taylorza | 4:64d2d834341b | 128 | |
taylorza | 4:64d2d834341b | 129 | void SignalGenerator::asyncStep() |
taylorza | 4:64d2d834341b | 130 | { |
taylorza | 4:64d2d834341b | 131 | _pin = !_pin; |
taylorza | 4:64d2d834341b | 132 | |
taylorza | 4:64d2d834341b | 133 | _bufferIndex++; |
taylorza | 4:64d2d834341b | 134 | if (_bufferIndex < _bufferCount) |
taylorza | 4:64d2d834341b | 135 | { |
taylorza | 4:64d2d834341b | 136 | _pTicker->attach_us(this, &SignalGenerator::asyncStep, _pInternalTimingBuffer[_bufferIndex]); |
taylorza | 4:64d2d834341b | 137 | } |
taylorza | 4:64d2d834341b | 138 | else if (_repeat) |
taylorza | 4:64d2d834341b | 139 | { |
taylorza | 4:64d2d834341b | 140 | _bufferIndex = 0; |
taylorza | 4:64d2d834341b | 141 | _pTicker->attach_us(this, &SignalGenerator::asyncStep, _pInternalTimingBuffer[_bufferIndex]); |
taylorza | 4:64d2d834341b | 142 | } |
taylorza | 4:64d2d834341b | 143 | else |
taylorza | 4:64d2d834341b | 144 | { |
taylorza | 4:64d2d834341b | 145 | stopAsync(); |
taylorza | 4:64d2d834341b | 146 | } |
taylorza | 4:64d2d834341b | 147 | } |
taylorza | 4:64d2d834341b | 148 | |
taylorza | 4:64d2d834341b | 149 | void SignalGenerator::setAsync( |
taylorza | 4:64d2d834341b | 150 | bool initialState, |
taylorza | 4:64d2d834341b | 151 | uint32_t timingBuffer[], |
taylorza | 4:64d2d834341b | 152 | uint16_t bufferCount, |
taylorza | 4:64d2d834341b | 153 | bool repeat) |
taylorza | 4:64d2d834341b | 154 | { |
taylorza | 4:64d2d834341b | 155 | stopAsync(); |
taylorza | 4:64d2d834341b | 156 | |
taylorza | 4:64d2d834341b | 157 | if (_pTicker == NULL) |
taylorza | 4:64d2d834341b | 158 | { |
taylorza | 4:64d2d834341b | 159 | _pTicker = new Timeout; |
taylorza | 4:64d2d834341b | 160 | } |
taylorza | 4:64d2d834341b | 161 | |
taylorza | 4:64d2d834341b | 162 | _pInternalTimingBuffer = new uint32_t[bufferCount]; |
taylorza | 4:64d2d834341b | 163 | _bufferCount = bufferCount; |
taylorza | 4:64d2d834341b | 164 | _repeat = repeat; |
taylorza | 4:64d2d834341b | 165 | _bufferIndex = 0; |
taylorza | 4:64d2d834341b | 166 | |
taylorza | 4:64d2d834341b | 167 | for(int i = 0; i < bufferCount; ++i) |
taylorza | 4:64d2d834341b | 168 | { |
taylorza | 4:64d2d834341b | 169 | _pInternalTimingBuffer[i] = timingBuffer[i] > 15 ? timingBuffer[i] - 10 : 5; |
taylorza | 4:64d2d834341b | 170 | } |
taylorza | 4:64d2d834341b | 171 | |
taylorza | 4:64d2d834341b | 172 | _pin = initialState ? 1 : 0; |
taylorza | 4:64d2d834341b | 173 | _pTicker->attach_us(this, &SignalGenerator::asyncStep, _pInternalTimingBuffer[_bufferIndex]); |
taylorza | 4:64d2d834341b | 174 | } |
taylorza | 4:64d2d834341b | 175 | |
taylorza | 4:64d2d834341b | 176 | void SignalGenerator::stopAsync() |
taylorza | 4:64d2d834341b | 177 | { |
taylorza | 4:64d2d834341b | 178 | if (_pTicker != NULL) |
taylorza | 4:64d2d834341b | 179 | { |
taylorza | 4:64d2d834341b | 180 | _pTicker->detach(); |
taylorza | 4:64d2d834341b | 181 | } |
taylorza | 4:64d2d834341b | 182 | |
taylorza | 4:64d2d834341b | 183 | if (_pInternalTimingBuffer != NULL) |
taylorza | 4:64d2d834341b | 184 | { |
taylorza | 4:64d2d834341b | 185 | delete[] _pInternalTimingBuffer; |
taylorza | 4:64d2d834341b | 186 | } |
taylorza | 2:b2a449bd787f | 187 | } |