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
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