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

Committer:
taylorza
Date:
2014-09-13
Revision:
3:f30dcc6e8e70
Parent:
2:b2a449bd787f
Child:
4:64d2d834341b

File content as of revision 3:f30dcc6e8e70:

///////////////////////////////////////////////////////////////////////////////
// Signal Generator
// Author: Chris Taylor (taylorza)
#include "mbed.h"
#include "SignalGenerator.h"

SignalGenerator::SignalGenerator(PinName pin) : _pin(pin)
{
    
}
          
void SignalGenerator::set(bool pinState)
{
    _pin = pinState ? 1 : 0;
}

void SignalGenerator::set(
    bool initialState, 
    uint32_t timingBuffer[], 
    uint16_t bufferCount, 
    uint32_t lastStateHoldTime, 
    int32_t carrierFrequency)
{
    if (timingBuffer == NULL || bufferCount == 0)
    {
        return;
    }

    uint16_t lastTiming = bufferCount - 1;
    
    Timer transitionTimer;
    if (carrierFrequency > 0)
    {        
        int timingIndex = 0;                     
        bool pinState = initialState;
        bool carrierState = true;        
        uint32_t carrierHalfPeriod = (500000 / carrierFrequency);
        uint32_t compare = timingBuffer[timingIndex++];
        uint32_t carrierCompare = carrierHalfPeriod;       
        
        transitionTimer.start();
        while(true)
        {    
            bool stateChange = false;
            if (transitionTimer.read_us() >= compare)
            {                
                pinState = !pinState;                  
                stateChange = true;                                              
                if (timingIndex == lastTiming) break;
                compare += timingBuffer[timingIndex++];                
            }
            
            if (transitionTimer.read_us() >= carrierCompare)
            {
                carrierState = !carrierState;                
                carrierCompare += carrierHalfPeriod;                
                stateChange = true;
            }
            
            if (stateChange) _pin = pinState & carrierState ? 1 : 0;
        }

        if (lastStateHoldTime > 0)
        {
            compare += lastStateHoldTime;
            while (transitionTimer.read_us() < compare)
            {
                if (transitionTimer.read_us() >= carrierCompare)
                {
                    carrierState = !carrierState;
                    carrierCompare += carrierHalfPeriod;
                    _pin = pinState & carrierState ? 1 : 0;
                }                    
            }
        }                            
    }
    else
    {   
        int timingIndex = 0;                     
        uint32_t compare = timingBuffer[timingIndex++];
        transitionTimer.start();        
        set(initialState);                
        while(true)
        {                     
            if (transitionTimer.read_us() >= compare)
            {   
                _pin = !_pin;                                                             
                if (timingIndex == lastTiming) break;
                compare += timingBuffer[timingIndex++];
            }
        }
        if (lastStateHoldTime > 0)
        {
            compare += lastStateHoldTime;
            while (transitionTimer.read_us() < compare)
            {
                ;
            }
        }        
    }  
}