element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Members
    Members
    • Achievement Levels
    • Benefits of Membership
    • Feedback and Support
    • Members Area
    • Personal Blogs
    • What's New on element14
  • Learn
    Learn
    • eBooks
    • Learning Center
    • Learning Groups
    • STEM Academy
    • Webinars, Training and Events
  • Technologies
    Technologies
    • 3D Printing
    • Experts & Guidance
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Arduino Projects
    • Design Challenges
    • element14 presents
    • Project14
    • Project Groups
    • Raspberry Pi Projects
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Or choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
Personal Blogs
  • Members
  • More
Personal Blogs
Legacy Personal Blogs Arduino: R-2R: Setting the Output Frequency
  • Blog
  • Documents
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Blog Post Actions
  • Subscribe by email
  • More
  • Cancel
  • Share
  • Subscribe by email
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: jc2048
  • Date Created: 25 Apr 2018 2:23 PM Date Created
  • Views 2882 views
  • Likes 7 likes
  • Comments 15 comments
  • r2r
  • arduino uno project
Related
Recommended

Arduino: R-2R: Setting the Output Frequency

jc2048
jc2048
25 Apr 2018

I've made a bit more progress. I now have my test code connected to the SCPI parser. That was very easy to do: I simply copied their generator example, took out the lines specific to the chip they were using, and adapted it slightly to calculate the table step. Much to my amazement it works and I can now program the output frequency.

 

Here's the sketch. The two includes that the highlighting wipes out are:

 

#include <scpiparser.h>
#include <Arduino.h>

 

#include 
#include 
struct scpi_parser_context ctx;
float frequency;
scpi_error_t identify(struct scpi_parser_context* context, struct scpi_token* command);
scpi_error_t get_frequency(struct scpi_parser_context* context, struct scpi_token* command);
scpi_error_t set_frequency(struct scpi_parser_context* context, struct scpi_token* command);
unsigned int tableOffset = 0;             // output count
unsigned int tableStep = 5120;
//
//  --- Sine table - generated by sineTable.exe 
//
unsigned int sineTable[512] = {
   0x8000,0x8192,0x8324,0x84b6,0x8647,0x87d9,0x896a,0x8afb,0x8c8b,0x8e1b,0x8fab,0x9139,0x92c8,0x9455,0x95e2,0x976d,
   0x98f8,0x9a82,0x9c0b,0x9d93,0x9f19,0xa09f,0xa223,0xa3a6,0xa528,0xa6a8,0xa826,0xa9a3,0xab1f,0xac98,0xae11,0xaf87,
   0xb0fb,0xb26e,0xb3de,0xb54d,0xb6ba,0xb824,0xb98c,0xbaf2,0xbc56,0xbdb8,0xbf17,0xc073,0xc1ce,0xc325,0xc47a,0xc5cd,
   0xc71c,0xc869,0xc9b4,0xcafb,0xcc3f,0xcd81,0xcebf,0xcffb,0xd133,0xd269,0xd39b,0xd4ca,0xd5f5,0xd71d,0xd842,0xd964,
   0xda82,0xdb9d,0xdcb4,0xddc7,0xded7,0xdfe3,0xe0ec,0xe1f1,0xe2f2,0xe3ef,0xe4e8,0xe5dd,0xe6cf,0xe7bd,0xe8a6,0xe98c,
   0xea6d,0xeb4a,0xec24,0xecf9,0xedca,0xee96,0xef5f,0xf023,0xf0e2,0xf19e,0xf255,0xf307,0xf3b5,0xf45f,0xf504,0xf5a5,
   0xf641,0xf6d9,0xf76c,0xf7fa,0xf884,0xf909,0xf98a,0xfa05,0xfa7d,0xfaef,0xfb5d,0xfbc5,0xfc29,0xfc89,0xfce3,0xfd39,
   0xfd8a,0xfdd6,0xfe1d,0xfe5f,0xfe9d,0xfed5,0xff09,0xff38,0xff62,0xff87,0xffa7,0xffc2,0xffd8,0xffe9,0xfff6,0xfffd,
   0xffff,0xfffd,0xfff6,0xffe9,0xffd8,0xffc2,0xffa7,0xff87,0xff62,0xff38,0xff09,0xfed5,0xfe9d,0xfe5f,0xfe1d,0xfdd6,
   0xfd8a,0xfd39,0xfce3,0xfc89,0xfc29,0xfbc5,0xfb5d,0xfaef,0xfa7d,0xfa05,0xf98a,0xf909,0xf884,0xf7fa,0xf76c,0xf6d9,
   0xf641,0xf5a5,0xf504,0xf45f,0xf3b5,0xf307,0xf255,0xf19e,0xf0e2,0xf023,0xef5f,0xee96,0xedca,0xecf9,0xec24,0xeb4a,
   0xea6d,0xe98c,0xe8a6,0xe7bd,0xe6cf,0xe5dd,0xe4e8,0xe3ef,0xe2f2,0xe1f1,0xe0ec,0xdfe3,0xded7,0xddc7,0xdcb4,0xdb9d,
   0xda82,0xd964,0xd842,0xd71d,0xd5f5,0xd4ca,0xd39b,0xd269,0xd133,0xcffb,0xcebf,0xcd81,0xcc3f,0xcafb,0xc9b4,0xc869,
   0xc71c,0xc5cd,0xc47a,0xc325,0xc1ce,0xc073,0xbf17,0xbdb8,0xbc56,0xbaf2,0xb98c,0xb824,0xb6ba,0xb54d,0xb3de,0xb26e,
   0xb0fb,0xaf87,0xae11,0xac98,0xab1f,0xa9a3,0xa826,0xa6a8,0xa528,0xa3a6,0xa223,0xa09f,0x9f19,0x9d93,0x9c0b,0x9a82,
   0x98f8,0x976d,0x95e2,0x9455,0x92c8,0x9139,0x8fab,0x8e1b,0x8c8b,0x8afb,0x896a,0x87d9,0x8647,0x84b6,0x8324,0x8192,
   0x8000,0x7e6d,0x7cdb,0x7b49,0x79b8,0x7826,0x7695,0x7504,0x7374,0x71e4,0x7054,0x6ec6,0x6d37,0x6baa,0x6a1d,0x6892,
   0x6707,0x657d,0x63f4,0x626c,0x60e6,0x5f60,0x5ddc,0x5c59,0x5ad7,0x5957,0x57d9,0x565c,0x54e0,0x5367,0x51ee,0x5078,
   0x4f04,0x4d91,0x4c21,0x4ab2,0x4945,0x47db,0x4673,0x450d,0x43a9,0x4247,0x40e8,0x3f8c,0x3e31,0x3cda,0x3b85,0x3a32,
   0x38e3,0x3796,0x364b,0x3504,0x33c0,0x327e,0x3140,0x3004,0x2ecc,0x2d96,0x2c64,0x2b35,0x2a0a,0x28e2,0x27bd,0x269b,
   0x257d,0x2462,0x234b,0x2238,0x2128,0x201c,0x1f13,0x1e0f,0x1d0d,0x1c10,0x1b17,0x1a22,0x1930,0x1842,0x1759,0x1673,
   0x1592,0x14b5,0x13db,0x1306,0x1235,0x1169,0x10a0,0x0fdc,0x0f1d,0x0e61,0x0daa,0x0cf8,0x0c4a,0x0ba0,0x0afb,0x0a5a,
   0x09be,0x0926,0x0893,0x0805,0x077b,0x06f6,0x0675,0x05fa,0x0582,0x0510,0x04a2,0x043a,0x03d6,0x0376,0x031c,0x02c6,
   0x0275,0x0229,0x01e2,0x01a0,0x0162,0x012a,0x00f6,0x00c7,0x009d,0x0078,0x0058,0x003d,0x0027,0x0016,0x0009,0x0002,
   0x0000,0x0002,0x0009,0x0016,0x0027,0x003d,0x0058,0x0078,0x009d,0x00c7,0x00f6,0x012a,0x0162,0x01a0,0x01e2,0x0229,
   0x0275,0x02c6,0x031c,0x0376,0x03d6,0x043a,0x04a2,0x0510,0x0582,0x05fa,0x0675,0x06f6,0x077b,0x0805,0x0893,0x0926,
   0x09be,0x0a5a,0x0afb,0x0ba0,0x0c4a,0x0cf8,0x0daa,0x0e61,0x0f1d,0x0fdc,0x10a0,0x1169,0x1235,0x1306,0x13db,0x14b5,
   0x1592,0x1673,0x1759,0x1842,0x1930,0x1a22,0x1b17,0x1c10,0x1d0d,0x1e0e,0x1f13,0x201c,0x2128,0x2238,0x234b,0x2462,
   0x257d,0x269b,0x27bd,0x28e2,0x2a0a,0x2b35,0x2c64,0x2d96,0x2ecc,0x3004,0x3140,0x327e,0x33c0,0x3504,0x364b,0x3796,
   0x38e3,0x3a32,0x3b85,0x3cda,0x3e31,0x3f8c,0x40e8,0x4247,0x43a9,0x450d,0x4673,0x47db,0x4945,0x4ab2,0x4c21,0x4d91,
   0x4f04,0x5078,0x51ee,0x5367,0x54e0,0x565c,0x57d9,0x5957,0x5ad7,0x5c59,0x5ddc,0x5f60,0x60e6,0x626c,0x63f4,0x657d,
   0x6707,0x6892,0x6a1d,0x6baa,0x6d37,0x6ec6,0x7054,0x71e4,0x7374,0x7504,0x7695,0x7826,0x79b8,0x7b49,0x7cdb,0x7e6d};

void setup()
{
  struct scpi_command* source;
  struct scpi_command* measure;

  /* First, initialise the parser. */
  scpi_init(&ctx);
  /*
   * After initialising the parser, we set up the command tree.  Ours is
   *
   *  *IDN?         -> identify
   *  :SOURCE
   *    :FREQuency  -> set_frequency
   *    :FREQuency? -> get_frequency
   */
  scpi_register_command(ctx.command_tree, SCPI_CL_SAMELEVEL, "*IDN?", 5, "*IDN?", 5, identify);
  source = scpi_register_command(ctx.command_tree, SCPI_CL_CHILD, "SOURCE", 6, "SOUR", 4, NULL);
  scpi_register_command(source, SCPI_CL_CHILD, "FREQUENCY", 9, "FREQ", 4, set_frequency);
  scpi_register_command(source, SCPI_CL_CHILD, "FREQUENCY?", 10, "FREQ?", 5, get_frequency);
  
  frequency = 1e3;
  // set the pins used as outputs:
  
  PORTD = 0;
  
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);
  pinMode(A2, OUTPUT);
  pinMode(A3, OUTPUT);
  digitalWrite(A0, HIGH);   
  digitalWrite(A1, HIGH);   
  digitalWrite(A2, HIGH);   
  digitalWrite(A3, LOW);   
  // timer 2 set up
  cli();                  // disable interrupts
  TCCR2A = 0;             // control register all 0
  TCCR2B = 0;             // control register all 0
  TCNT2 = 0;              // set count to 0
  OCR2A = 159;            // period = 160 x 1/16MHz = 10uS
  TCCR2A |= (1 << WGM21); // mode is clear on match
  TCCR2B |= (1 << CS20);  // no prescaler   
  TIMSK2 |= (1 << OCIE2A);  // enable interrupt on match
  sei();                  // enable interrupts
  Serial.begin(9600);
}
// timer 2 interrupt routine
ISR(TIMER2_COMPA_vect) {
  tableOffset = tableOffset + tableStep;
  PORTD = (sineTable[tableOffset >> 7]) >> 8;
}
// main loop
void loop()
{
  char line_buffer[256];
  unsigned char read_length;
  
  while(1)
  {
    /* Read in a line and execute it. */
    read_length = Serial.readBytesUntil('\n', line_buffer, 256);
    if(read_length > 0)
    {
      scpi_execute_command(&ctx, line_buffer, read_length);
    }
  }
}
/*
 * Respond to *IDN?
 */
scpi_error_t identify(struct scpi_parser_context* context, struct scpi_token* command)
{
  scpi_free_tokens(command);
  Serial.println("E14,Arduino Audio Signal Generator,1,10");
  return SCPI_SUCCESS;
}
/**
 * Read the current frequency setting.
 */
scpi_error_t get_frequency(struct scpi_parser_context* context, struct scpi_token* command)
{
//  float voltage;
  Serial.println(frequency,4);
  scpi_free_tokens(command);
  return SCPI_SUCCESS;
}
/**
 * Set the audio output frequency.
 */
scpi_error_t set_frequency(struct scpi_parser_context* context, struct scpi_token* command)
{
  struct scpi_token* args;
  struct scpi_numeric output_numeric;
//  unsigned char output_value;
  args = command;
  while(args != NULL && args->type == 0)
  {
    args = args->next;
  }
  output_numeric = scpi_parse_numeric(args->value, args->length, 1e3, 20, 2e4);
  if(output_numeric.length == 0 ||
    (output_numeric.length == 2 && output_numeric.unit[0] == 'H' && output_numeric.unit[1] == 'z'))
  {
    tableStep = (unsigned int)(65536.0 * output_numeric.value / 100000.0);
    frequency = (unsigned long)constrain(output_numeric.value, 20, 2e4);
  }
  else
  {
    scpi_error error;
    error.id = -200;
    error.description = "Command error;Invalid unit";
    error.length = 26;
    
    scpi_queue_error(&ctx, error);
    scpi_free_tokens(command);
    return SCPI_SUCCESS;
  }
  scpi_free_tokens(command);
  return SCPI_SUCCESS;
}

 

Here are the results for the following SCPI messages

 

:SOUR:FREQ 20Hz

 

image

 

:SOUR:FREQ 1234Hz

 

image

 

:SOUR:FREQ 2e4Hz

 

image

 

The frequencies are fairly accurate, being within a few Hertz of those requested.

 

This is the line that does the real work (line 158)

 

    tableStep = (unsigned int)(65536.0 * output_numeric.value / 100000.0);

 

it takes the frequency from the parser (a float in Hertz) and calculates the table step necessary to generate it. The 100k is the sample rate, the 65536 is the number of intervals one complete cycle is divided into.

 

There are a couple of issues I've identified from doing this:

 

1/ The amplitude dimishes at high frequencies. That means that either I've got my filter values wrong or that the variable gain section is a mess. To look at that I'm going to go back to my test code and rework it to do a frequency sweep - then I'll be able to see directly the frequency response on the 'scope. It also looks like there might be other problems with the 20kHz one.

 

2/ The serial side seems a bit fragile. I can't seem to talk to it with PuTTY (probably just me not being able to get the settings right), but have also once got it into a state where it wouldn't talk to the Arduino serial tool either, so maybe the error recovery isn't very good.

 

However, it's looking quite promising as a very low cost way to generate waveforms.

 

The original blog by Jan, where he introduced us to the SCPI library that he'd found, is here: Arduino in Test Instrumentation - Part 1: SCPI Lib

 

This is the SCPI parser library on GitHub: https://github.com/LachlanGunn/oic

 

 

Part one: Arduino: R-2R Experiment

Part two: Arduino: R-2R: Sine On You Crazy Diamond

Part three: Arduino: R-2R: Buffer, Attenuate, and Filter

Part four: Arduino: R-2R: "We Interrupt This Programme..."

Part five: Arduino: R-2R: "Resistance is..."?

Part six: Arduino: R-2R: Setting the Output Frequency

Part seven: Arduino: R-2R; "A Sweep is as Lucky, as Lucky Can Be..."

Part eight: Arduino: R-2R: Setting the Signal Amplitude

  • Sign in to reply

Top Comments

  • fmilburn
    fmilburn over 5 years ago +3
    A nice well documented series - I have enjoyed following along.
  • Jan Cumps
    Jan Cumps over 5 years ago +3
    for the PuTTY settings, you may have to turn on local echo, so that you see what you type, and maybe CR + LF. it works reliable with the Arduino Serial Monitor if you have the speed setting correct.
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to jc2048 +3
    I’ll check tomorrow, when I’m back in the country. it may also be related with the cpu reset that happens on an Arduino UNO when you start up a serial communication over the USB.
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to Jan Cumps

    also works on ubuntu

    image

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to jc2048

    jc2048  wrote:

     

    I've just tried stripping off the return if it's there and it works fine with PuTTY now

    That's nice. That works in PuTTY, Arduino monitor and my LabVIEW lib. image

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • jc2048
    jc2048 over 5 years ago in reply to Jan Cumps

    I've just tried stripping off the return if it's there and it works fine with PuTTY now

     

    image

     

     

    /* Read in a line and execute it. */
        read_length = Serial.readBytesUntil('\n', line_buffer, 256);
        if(read_length >0)
          if(line_buffer[read_length-1]=='\r')
            read_length = read_length - 1;
        if(read_length > 0)
        {
          scpi_execute_command(&ctx, line_buffer, read_length);
        }

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to Jan Cumps

    This one works with putty (carriage return instead of newline):

    void loop() {
      char line_buffer[256];
      unsigned char read_length;
    
    
      while(1)   {
        /* Read in a line and execute it. */
    //    read_length = Serial.readBytesUntil('\n', line_buffer, 256);
        read_length = Serial.readBytesUntil('\r', line_buffer, 256);
        if(read_length > 0)     {
          scpi_execute_command(&ctx, line_buffer, read_length);
        }
      }
    }

     

    It doesn't work with my LabVIEW driver (because I'm using '\n' in all my SCPI commands image ). Not hard to change though ...

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to jc2048

    It's actually the way we read the serial string, not the lib itself. I stole it from the example that came with the lib:

     

      while(1)   {
        /* Read in a line and execute it. */
        read_length = Serial.readBytesUntil('\n', line_buffer, 256);
        if(read_length > 0)     {
          scpi_execute_command(&ctx, line_buffer, read_length);
        }
      }

     

    I'll check if I can fix it and still have it working with  LabVIEW lib.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2023 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube