Showing posts with label low pass filter. Show all posts
Showing posts with label low pass filter. Show all posts

Wednesday, March 6, 2019

Tutorial on Digital to Analog Converters (DAC) and Example Using the MCP4728 Part 2

Two part tutorial on digital to analog converters (DAC). In part 2 we take a look at the capabilities of the MCP4728 which is a four channel DAC controlled via I2C. See the links below to access the code and get the PCB design from the video at PCBWay.



Link for PCB board at PCBWay: https://www.pcbway.com/project/shareproject/W08904ASW106_DAC_Example_Gerber.html

//**********Arduino Code with MCP4728 examples from video***************
/*
 * This code was written to demonstrate functions on the MCP4728 4 channel DAC for a video on the ForceTronics YouTube channel
 * This sketch leverages a library from GitHub made by Hideakitai, link to library: https://github.com/hideakitai/MCP4728
 * This code is public domain and free to anyone to use and modify with no restrictions at your own risk
 */

#include <Wire.h>
#include "MCP4728.h"

MCP4728 dac; //create object to library
//variables for wavform
int const sampleCount = 24; //samples to read to have a buffer
int signalSamples[sampleCount]; //create array to hold signal or waveform
float pi2 = 6.283; //value of pi times 2
const long clkFrequency = 400000; //I2C clock frequency
const uint8_t t1 = 3; //pin to setup test 1 fast sinewave
const uint8_t t2 = 4; //pin to setup test 2 sync'd sinewaves
const uint8_t LDAC = 5; //Output pin on MCU to control LDAC(not) pin on DAC

void setup() {
 //Create sinewave
 float in;
 float hBit = 2047.5;
 for (int i=0;i<sampleCount;i++)
 {
   in = pi2*(1/(float)sampleCount)*(float)i;
   signalSamples[i] = (int)(sin(in)*hBit + hBit);
 }

 pinMode(t1,INPUT_PULLUP); //configure test check pins
 pinMode(t2,INPUT_PULLUP); //configure test check pins
 pinMode(LDAC,OUTPUT); //configure test check pins
 digitalWrite(LDAC,HIGH); //turn DAC outputs off
 Wire.begin(); //start up I2C library
 Wire.setClock(clkFrequency); //set clock frequency for I2C comm
 dac.attatch(Wire, 13); //second argument is Arduino pin connected to LDAC(not), we are controlling LDAC manually so just entered pin we are not using
 dac.readRegisters(); //Used to read current settings from MCP4728
 dac.selectVref(MCP4728::VREF::VDD, MCP4728::VREF::VDD, MCP4728::VREF::VDD, MCP4728::VREF::VDD); //setup voltage ref for each DAC channel
 dac.selectPowerDown(MCP4728::PWR_DOWN::NORMAL, MCP4728::PWR_DOWN::NORMAL, MCP4728::PWR_DOWN::NORMAL, MCP4728::PWR_DOWN::NORMAL); //set power down mode, used for saving power
 dac.selectGain(MCP4728::GAIN::X1, MCP4728::GAIN::X1, MCP4728::GAIN::X1, MCP4728::GAIN::X1); //set gain on output amp
 //dac.enable(true); //enables the DAC outputs by controlling LDAC pin, but we are controlling LDAC manually in this example

  //perform test one
  if(!digitalRead(t1)) {
    digitalWrite(LDAC,LOW);
    //output sinewave as fast as we can
    for(;;) { //run test for infinitity 
      for(int j=0;j<sampleCount;j++) {
        dac.analogWrite(MCP4728::DAC_CH::A,signalSamples[j]);
      }
    }
  }
  else { //perform test 2 
    for(;;) {  //run test for infinitity 
      for(int j=0;j<sampleCount;j++) {
        int temp = j;
        digitalWrite(LDAC,HIGH); //turn outputs off
       // delay(1);
        dac.analogWrite(MCP4728::DAC_CH::A,signalSamples[temp]);
        temp += 8; //shift sigal 90 degrees
        if(temp > 23) temp -= sampleCount;
        dac.analogWrite(MCP4728::DAC_CH::B,signalSamples[temp]);
        temp += 8; //shift sigal 90 degrees
        if(temp > 23) temp -= sampleCount;
        dac.analogWrite(MCP4728::DAC_CH::C,signalSamples[temp]);
        temp += 8; //shift sigal 90 degrees
        if(temp > 23) temp -= sampleCount;
        dac.analogWrite(MCP4728::DAC_CH::D,signalSamples[temp]);
        digitalWrite(LDAC,LOW); //turn outputs on all four outputs at same time
       // delay(1);
      }
    }
  }
}

void loop() {
}


Sunday, February 11, 2018

Converting an Arduino PWM Output to a DAC Output

In this video we look at how to convert a PWM output or signal to a analog or DAC signal.



To access the low pass filter tutorial mentioned in the video got to: https://youtu.be/gW5oF8vcYb8


//*************Arduino code from video***************************
/*This code was made for a vidoe tutorial on the ForceTronics YouTube Channel called
 * Converting an Arduino PWM Output to a DAC Output. This code is free to use and 
 * modify at your own risk
 */

uint8_t pVal = 127; //PWM value 
const float pi2 = 6.28; //Pie times 2, for building sinewave
const int samples = 100; //number of samples for Sinewave. This value also affects frequency
int WavSamples[samples]; //Array for storing sine wave points
int count = 0; //tracks where we are in sine wave array

void setup() {
// Serial.begin(115200); //for debugging
  pinMode(10, OUTPUT); //pin used for analog voltage value
  pinMode(4,OUTPUT); //pin used to fake PWM for sinewave
  setPwmFrequency(10,1); //function for setting PWM frequency
  analogWrite(10,127); //set duty cycle for PWM

  float in, out; //used for building sine wave
  
  for (int i=0;i<samples;i++) //loop to build sinewave
  {
    in = pi2*(1/(float)samples)*(float)i; //calculate value for sine function
    WavSamples[i] = (int)(sin(in)*127.5 + 127.5); //get sinewave value and store in array
   // Serial.println(WavSamples[i]); //for debugging
  }
}

void loop() {
  if(count > samples) count = 0; //reset the count once we are through array
  bitBangPWM(WavSamples[count],4); //function for turning sinewave into "fake" PWM signal
  count++; //increment position in array
}

//Function to bit bang a PWM signal (we are using it for the sinewave)
//input are PWM high value for one cycle and digital pin for Arduino
//period variable determines frequency along with number of signal samples
//For this example a period of 1000 (which is 1 millisecond) times 100 samples is 100 milli second period so 10Hz
void bitBangPWM(unsigned long on, int pin) {
  int period = 1000; //period in micro seconds
  on = map(on, 0, 255, 0, period); //map function that converts from 8 bits to range of period in micro sec
 // Serial.println(on); //debug check
  unsigned long start = micros(); //get current value of micro second timer as start time
  digitalWrite(pin,HIGH); //set digital pin to high
  while((start+on) > micros()); //wait for a time based on PWM duty cycle
  start = micros(); 
  digitalWrite(pin,LOW); //set digital pin to low
  while((start+(period - on)) > micros()); //wait for a time based on PWM duty cycle
}

/**
 * https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
 * Divides a given PWM pin frequency by a divisor.
 * 
 * The resulting frequency is equal to the base frequency divided by
 * the given divisor:
 *   - Base frequencies:
 *      o The base frequency for pins 3, 9, 10, and 11 is 31250 Hz.
 *      o The base frequency for pins 5 and 6 is 62500 Hz.
 *   - Divisors:
 *      o The divisors available on pins 5, 6, 9 and 10 are: 1, 8, 64,
 *        256, and 1024.
 *      o The divisors available on pins 3 and 11 are: 1, 8, 32, 64,
 *        128, 256, and 1024.
 * 
 * PWM frequencies are tied together in pairs of pins. If one in a
 * pair is changed, the other is also changed to match:
 *   - Pins 5 and 6 are paired on timer0
 *   - Pins 9 and 10 are paired on timer1
 *   - Pins 3 and 11 are paired on timer2
 * 
 * Note that this function will have side effects on anything else
 * that uses timers:
 *   - Changes on pins 3, 5, 6, or 11 may cause the delay() and
 *     millis() functions to stop working. Other timing-related
 *     functions may also be affected.
 *   - Changes on pins 9 or 10 will cause the Servo library to function
 *     incorrectly.
 * 
 * Thanks to macegr of the Arduino forums for his documentation of the
 * PWM frequency divisors. His post can be viewed at:
 *   http://forum.arduino.cc/index.php?topic=16612#msg121031
 */
void setPwmFrequency(int pin, int divisor) {
  byte mode;
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x07; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }
}

Wednesday, March 22, 2017

Reduce Noise in Your Sensor Measurements with an Active Low Pass Filter Part 3

In this three part series we look at how to design a signal conditioning circuit to increase the accuracy and resolution of your ADC sensor measurements. The signal conditioning circuit consists of a double pole active Sallen Key Low Pass Filter and a non-inverting op amp. The filter portion is meant to attenuate high frequency noise from your sensor signal to increase measurement accuracy. The amplifier portion scales the signal up to the full range of the ADC to ensure you are getting max resolution. In part 3 we test our finished LPF + Amp circuit. 




If you are interested in purchasing the circuit from the video go to forcetronics.com

You can access the Eagle files on Github at: https://github.com/ForceTronics/Salle...


Sunday, March 5, 2017

Reduce Noise in Your Sensor Measurements with an Active Low Pass Filter Part 2

In this three part series we look at how to design a signal conditioning circuit to increase the accuracy and resolution of your ADC measurements. The signal conditioning circuit consists of a double pole active Sallen Key Low Pass Filter and a non-inverting op amp. The filter portion is meant to attenuate high frequency noise from your sensor signal to increase measurement accuracy. The amplifier portion scales the signal up to the full range of the ADC to ensure you are getting max resolution. In part 2 we do the PCB layout of our circuit using Eagle CAD software.





You can access the Eagle files on Github at: https://github.com/ForceTronics/Sallen-Key-Low-Pass-Filter-Design/tree/master


Monday, February 27, 2017

Reduce Noise in Your Sensor Measurements with an Active Low Pass Filter Part 1

In this three part series we look at how to design a signal conditioning circuit to increase the accuracy and resolution of your ADC measurements. The signal conditioning circuit consists of a double pole active Sallen Key Low Pass Filter and a non-inverting op amp. The filter portion is meant to attenuate high frequency noise from your sensor signal to increase measurement accuracy. The amplifier portion scales the signal up to the full range of the ADC to ensure you are getting max resolution.




You can find the online filter calculator used in part one at this link: http://sim.okawa-denshi.jp/en/OPseikiLowkeisan.htmk

You can access the LTspice file on Github at: https://github.com/ForceTronics/Sallen-Key-Low-Pass-Filter-Design/tree/master

Sallen-Key Low Pass Filter Circuit with Amplifier Stage in LTspice