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.

Files at this revision

API Documentation at this revision

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