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.

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?

UserRevisionLine numberNew 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 }