{"id":5423,"date":"2018-12-26T09:13:16","date_gmt":"2018-12-26T09:13:16","guid":{"rendered":"http:\/\/41j.com\/blog\/?p=5423"},"modified":"2019-01-02T13:16:38","modified_gmt":"2019-01-02T13:16:38","slug":"multislope-adc-bring-up-dual-slope","status":"publish","type":"post","link":"https:\/\/41j.com\/blog\/2018\/12\/multislope-adc-bring-up-dual-slope\/","title":{"rendered":"Multislope ADC Bring up (Dual slope)"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2018\/12\/IMG_0963.jpg\" alt=\"\" class=\"wp-image-5424\" width=\"542\" height=\"451\"\/><\/figure><\/div>\n\n\n\n<p>I&#8217;ve been playing with a multislope ADC design. Multislope ADC are often used in high end multimeters, and as I have a <a href=\"https:\/\/hackaday.com\/2015\/12\/03\/nuts-about-volts\/\">mild obsession with 8.5 digit multimeters<\/a>, I wanted to try making a multislope ADC. The current design, such as it is was developed with significant input from EEVBlog users <a href=\"https:\/\/www.eevblog.com\/forum\/projects\/multislope-design\/\">(see this thread)<\/a>.\n\nThis post documents initial bring up and tests of the first revision of the PCB. Links to Kicad files, and data used in plots can be found at the end of this post.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2018\/12\/multislope_r1f.png\" alt=\"\" class=\"wp-image-5433\" width=\"538\" height=\"300\"\/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Components used in this test<\/h2>\n\n\n\n<p>\nAll resistors are standard, cheap 1\/4 Watt metal film resistors. The large slopes are 47K. Small slopes 4.7M. The input resistor (R200) is also 47K.\n\nThe design uses a 2 opamp integrator. Notionally this allows you to combine an opamp with good low frequency response with one with good high frequency response. A voltage divider sits between the two opamps. R9 is 47Ohm, R8 1K.\n\nOn the output amplifier R3 is 1K and R7 is 470Ohm to give a gain of ~0.5. This allows the Arduino Mega which I&#8217;m using to control the amplifier to read almost the full positive range of the integrator output (12V).\n\nThe integrator capacitor is an NP0 10nF, Murata GRM3195C1E103JA01D.\n\nThe switches are all DG419s. This includes the part marked DG417 on the schematic, which resets the integrator. All the DG419s are Vishay DG419Bs MSOP8s, except for the integrator which uses an Analog ADG1419BRMZ (I ran out of Vishay DG419s). Update: I attempted to rebuild this circuit using only ADG1419BRMZ, it did not work well. My guess is that there is too much charge injection&#8230; charge injection is not listed in the datasheets&#8230;\n\nI&#8217;m using a LTZ1000 reference to supply the slopes. This sits on an 3458A A9 PCB. I&#8217;m using a A9 clone from <a href=\"https:\/\/github.com\/pepaslabs\/hp-03458-66509-clone\">here<\/a>.\n\nAll opamps are socketed. In this test I used a NE5534 on the output. An OPA177 and AD711 for the integrator, an AD711 on the input, and an LT1013 to buffer\/invert the reference voltage.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Build Issues<\/h2>\n\n\n\n<p>There were a few errors in the schematic and layout. These include: <\/p>\n\n<ul>\n<li>The banana plug holes are too small for the sockets.<\/li>\n<li>The output opamp connected incorrectly (power swapped) <\/li>\n<li>The input opamp was connected incorrectly (I forget the exact issue). <\/li>\n<li>The reference voltage buffer\/inverter was wired incorrectly. <\/li>\n<li>The reference PCB covers the banana plugs when installed. <\/li>\n<\/ul>\n\n<p>These should be resolved in the schematic, but I&#8217;ve not fixed the layout yet. In the build you&#8217;ll also notice that I&#8217;ve hacked around with other parts of the PCB too. This was when I was cutting traces to try and figure out where leakage current was coming from and charging the integration capacitor. In the end this seemed to be coming from flux I couldn&#8217;t clean from under the DG419 switches. I removed, cleaned and replaced these, being more conservative with my usage of flux when re-soldering them. This removed most of the leakage current. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Initial tests<\/h2>\n\n\n\n<p> When I first brought up the design there was a lot of charge accumulating on the integrator after reset without any of the slopes or the input connected. After about 3 seconds the integrator would rise to the rail voltage (12v). After some investigation, this seemed to be caused by excess flux remaining under the DG419s. After cleaning this out, it takes ~60 seconds for the integrator to charge to the rail voltage. The following plot shows the output as recorded by an Arduino analog input:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2018\/12\/capstart.png\" alt=\"\" class=\"wp-image-5430\" width=\"540\" height=\"405\"\/><\/figure><\/div>\n\n\n\n<p>I&#8217;ve written code to drive the ADC board in a basic dual slope configuration. This works for bother the large and small slopes. In the tests below however I&#8217;m using the small slopes only. Arduino code is provided in the notes at the end of this post.<\/p>\n\n\n\n<p>The tests use a DP832 to supply rail voltages (+\/- 12 and 5V). A 33220A function generator is used to generate the input (this is probably not particularly low noise\/accurate).<\/p>\n\n\n\n<p>The following plot shows a histogram of ADC counts when the input is zero:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2018\/12\/input_zero_small.png\" alt=\"\" class=\"wp-image-5429\" width=\"574\" height=\"431\"\/><\/figure><\/div>\n\n\n\n<p>And here at 10V:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2018\/12\/input_small_10v.png\" alt=\"\" class=\"wp-image-5428\" width=\"571\" height=\"428\"\/><\/figure><\/div>\n\n\n\n<p>There&#8217;s something weird going on, as in some cases the histogram is bimodal. For example here at 1V:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2018\/12\/input_small_1v.png\" alt=\"\" class=\"wp-image-5427\" width=\"565\" height=\"424\"\/><\/figure><\/div>\n\n\n\n<p>Integration of positive voltages is also about 3 times quicker than negative voltages. It&#8217;s not clear to me why this is. Positive and negative voltages use different reference resistors, however these don&#8217;t seem to be significantly different and I need to investigate further.<\/p>\n\n\n\n<p>The positive and negative responses however seem to be quite linear. The following plot shows input voltage versus ADC count. You can see the slope difference between positive and negative voltages quite clearly:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2018\/12\/10vto-10v.png\" alt=\"\" class=\"wp-image-5425\" width=\"539\" height=\"404\"\/><\/figure><\/div>\n\n\n\n<p>Before moving forward, I&#8217;d like to better understand why I&#8217;m seeing this difference between positive and negative voltages. I should then be in a position to combine large and small slopes to create a multislope ADC.<\/p>\n\n\n\n<p>Update: I cleaned the board in an ultrasonic cleaner (distiled water, 60 degrees for ~15min, with a small amount of washing up liquid. Then agitated in IPA for ~30min). This seems to have cleared up the slope issue above. Here&#8217;s a revised graph:<br><\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2018\/12\/10v_to10v_after_clean.png\" alt=\"\" class=\"wp-image-5447\" width=\"540\" height=\"405\"\/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Notes<\/h2>\n\n\n\n<p> PCB Back:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2018\/12\/IMG_0964.jpg\" alt=\"\" class=\"wp-image-5434\" width=\"501\" height=\"376\"\/><\/figure><\/div>\n\n\n\n<p><a href=\"https:\/\/www.eevblog.com\/forum\/projects\/multislope-design\/\">EEV Blog Thread<\/a><\/p>\n\n\n\n<p><a href=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2018\/12\/data.zip\">Data for plots<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/sgenomics\/pcbs\/tree\/master\/multislope\/multislope\">Kicad files<\/a><\/p>\n\n\n\n<p>\n\nHacky code used in this post:\n\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &amp;lt;SPI.h&amp;gt;  \n  \n\/\/ name      header   arduino\n\/\/ SW_RST    2        4\n\/\/ SW_INPUT2 6        3\n\/\/ SW_INPUT1 8        2\n\/\/ SW_REF2B  10       A7\n\/\/ SW_REF2A  12       A6\n\/\/ SW_REF1B  14       A5\n\/\/ SW_REF1A  16       A4\n\/\/ CMP_OUT   18       A3\n\n#define SW_RST    5\n#define SW_INPUT2 3\n#define SW_INPUT1 2\n#define SW_REF2B  A7\n#define SW_REF2A  A6\n\/\/#define SW_REF1B  A5 - original\n#define SW_REF1B  A1\n#define SW_REF1A  A4\n\/\/#define CMP_OUT   A3 - original\n#define CMP_OUT   A2\n\n\nvoid input_off() {\n  digitalWrite(SW_INPUT2,HIGH);\n  delayMicroseconds(100);\n  digitalWrite(SW_INPUT1,LOW);\n}\n\nvoid input_on() {\n  digitalWrite(SW_INPUT1,HIGH);\n  delayMicroseconds(100);\n  digitalWrite(SW_INPUT2,LOW);\n}\n\nvoid references_off() {\n  digitalWrite(SW_REF1A,HIGH);\n  digitalWrite(SW_REF1B,HIGH);\n  digitalWrite(SW_REF2A,HIGH);\n  digitalWrite(SW_REF2B,HIGH);\n}\n\nint read_cmp() {\n  int r = analogRead(CMP_OUT);\n  return r;\n}\n\nvoid dump_cmp() {\n  int r = read_cmp();\n  Serial.print(r);\n  Serial.print(&amp;amp;amp;amp;quot; &amp;amp;amp;amp;quot;);\n}\n\nvoid ref_on(int p) {\n  digitalWrite(p,LOW);\n}\n\nvoid ref_off(int p) {\n  digitalWrite(p,HIGH);\n}\n\nvoid reset_integrator() {\n  digitalWrite(SW_RST,HIGH);\n  delayMicroseconds(10001);\n\/\/  delay(3000);\n  digitalWrite(SW_RST,LOW);\n}\n\nvoid setup() {  \n\n  \/\/ put your setup code here, to run once:\n  Serial.begin(115200);\n\n  pinMode(SW_RST   ,OUTPUT); \n  pinMode(SW_INPUT2,OUTPUT); \n  pinMode(SW_INPUT1,OUTPUT); \n  pinMode(SW_REF2B ,OUTPUT); \n  pinMode(SW_REF2A ,OUTPUT); \n  pinMode(SW_REF1B ,OUTPUT); \n  pinMode(SW_REF1A ,OUTPUT); \n  pinMode(CMP_OUT  ,INPUT ); \n  \n  input_off();\n  references_off();\n  reset_integrator();\n\n \/\/     ref_on(SW_REF2B); \n  Serial.println(&amp;quot;input complete&amp;quot;);\n  for(;Serial.available() == 0;) {\n    dump_cmp();\n    Serial.println();\n    delay(500);\n  }\n  Serial.println(&amp;quot;running...&amp;quot;);\n}\n\nvoid loop() {\n\n  \/\/ Serial.println(&amp;quot;start&amp;quot;);\n  input_off();\n  delayMicroseconds(1000);\n \/\/ Serial.println(&amp;quot;inputoff&amp;quot;);\n  references_off();\n \/\/ Serial.println(&amp;quot;refoff&amp;quot;);\n  delayMicroseconds(1000);\n  reset_integrator();\n \/\/ Serial.println(&amp;quot;int reset&amp;quot;);\n  delayMicroseconds(1000);\n  int p = read_cmp();\n  int c=0;\n  for(;p != 0;) {\n    reset_integrator();\n    p = read_cmp();\n    \/\/Serial.print(p);\n    \/\/Serial.print(&amp;quot; &amp;quot;);\n    c++;\n    if(c&amp;gt;10) break;\n  }\n  \/\/Serial.println();\n  \/\/dump_cmp();\n\n  input_on();\n  delayMicroseconds(500);\n  input_off();\n\n\n  int pol = read_cmp();\n\n  \/\/ input negative\n  if(pol &amp;amp;amp;amp;gt; 0) {\n    Serial.print(&amp;quot;-&amp;quot;);\n\n    unsigned int count=0;\n    for(;;) {\n      ref_on(SW_REF2B); \n      delayMicroseconds(5);\n      ref_off(SW_REF2B);\n      int c = read_cmp();\n      if(c == 0) break;\n      count++;\n      if(count &amp;gt; 64000) {Serial.print(&amp;quot;B&amp;quot;); count=0;}\n    }\n    Serial.println(count);\n  }\n\n  \/\/ input positive\n  if(pol &amp;gt;= 0) {\n    Serial.print(&amp;quot;+&amp;quot;);\n    unsigned int count=0;\n    for(;;) {\n      ref_on(SW_REF2A);\n      delayMicroseconds(5);\n      ref_off(SW_REF2A);\n      int c = read_cmp();\n      if(c &amp;gt; 0) break;\n      count++;\n      if(count &amp;gt; 64000) {Serial.print(&amp;quot;B&amp;quot;); count=0;}\n    }\n    Serial.println(count);\n  }\n\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been playing with a multislope ADC design. Multislope ADC are often used in high end multimeters, and as I have a mild obsession with 8.5 digit multimeters, I wanted to try making a multislope ADC. The current design, such as it is was developed with significant input from EEVBlog users (see this thread). This [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-5423","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1RRoU-1pt","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/5423","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/comments?post=5423"}],"version-history":[{"count":20,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/5423\/revisions"}],"predecessor-version":[{"id":5460,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/5423\/revisions\/5460"}],"wp:attachment":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/media?parent=5423"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/categories?post=5423"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/tags?post=5423"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}