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-12
Revision:
2:b2a449bd787f
Parent:
1:4a1bcc41c473
Child:
3:f30dcc6e8e70

File content as of revision 2:b2a449bd787f:

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

int32_t SignalGenerator::_latency = -1;

SignalGenerator::SignalGenerator(PinName pin) : _pin(pin)
{
    if (_latency == -1)
    {
        Timer t;
        
        t.start();
        _pin = 0;
        _pin = 0;
        _pin = 0;
        _pin = 0;
        _pin = 0;
        _pin = 0;
        _pin = 0;
        _pin = 0;
        _pin = 0;
        _pin = 0;            
        t.stop();
        int pinLatency = (t.read_us() + 0.5) / 10;
        
        t.reset();
        t.start();
        wait_us(100);
        wait_us(100);
        wait_us(100);
        wait_us(100);
        wait_us(100);
        wait_us(100);
        wait_us(100);
        wait_us(100);
        wait_us(100);
        wait_us(100);
        wait_us(100);
        t.stop();
        int waitLatency = (t.read_us() + 0.5) / 1000;
        
        t.reset();
        t.start();
        for (int i = 0; i < 20; i += 2)
        {
            wait_us(100);
        }
        t.stop();
        
        int loopLatency = ((t.read_us() - (1000 + (10 * waitLatency))) + 0.5) / 10;
        
        _latency = pinLatency + waitLatency + loopLatency;
    }
}
          
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)
{
    uint32_t carrierHalfPeriod = 0;
    
    if (timingBuffer == NULL || bufferCount == 0)
    {
        return;
    }

    if (carrierFrequency > 0)
    {
        carrierHalfPeriod = (uint32_t)(500000 / carrierFrequency);
        
        bool state = initialState;
        for(uint16_t i = 0; i < bufferCount; i++)
        {
            int c = (int)(timingBuffer[i] / (carrierHalfPeriod + _latency));
            if (!state)
            {
                wait_us(timingBuffer[i]);
            }
            else
            {
                for(int j = 0; j < c; j += 2)
                {
                    _pin = 1;
                    wait_us(carrierHalfPeriod);
                    _pin = 0;
                    wait_us(carrierHalfPeriod);
                }
            }
            state = !state;          
        }
         
        if (lastStateHoldTime > 0)
        {
            int c = (int)((double)lastStateHoldTime / carrierHalfPeriod);
            if (!state)
            {
                wait_us(lastStateHoldTime);
            }
            else
            {
                for(int j = 0; j < c; j += 2)
                {
                    _pin = 1;
                    wait_us(carrierHalfPeriod);
                    _pin = 0;
                    wait_us(carrierHalfPeriod);
                }
            }
        }                
    }
    else
    {
        set(initialState);
        for(uint16_t i = 0; i < bufferCount; ++i)
        {
            wait_us(timingBuffer[i]);
            _pin = !_pin;
        }
        
        if (lastStateHoldTime > 0)
        {
            wait_us(lastStateHoldTime);
        }
    }  
}