{"id":769,"date":"2012-10-15T00:19:19","date_gmt":"2012-10-14T22:19:19","guid":{"rendered":"http:\/\/blog.ulrichard.ch\/?p=769"},"modified":"2012-10-15T00:19:19","modified_gmt":"2012-10-14T22:19:19","slug":"raspberrypi-reading-analog-input-using-an-attiny-through-i2c","status":"publish","type":"post","link":"https:\/\/ulrichard.ch\/blog\/?p=769","title":{"rendered":"RaspberryPi reading analog input using an AtTiny through i2c"},"content":{"rendered":"<p>The <a href=\"http:\/\/www.raspberrypi.org\/\" target=\"_blank\" rel=\"noopener\">raspberrypi<\/a> has some GPIO (General Purpose Input Output) pins. That&#8217;s great for experimenting with electronics for example sensors and actuators. It&#8217;s totally different than an <a href=\"http:\/\/www.arduino.cc\/\" target=\"_blank\" rel=\"noopener\">Arduino<\/a> in many respects, but that&#8217;s something they have in common. Some of the pins have special functions. For example SPI, I2C, UART &#8230;<\/p>\n<p>There is a <a href=\"http:\/\/adafruit.com\/products\/914\" target=\"_blank\" rel=\"noopener\">breakboard adapter<\/a> for all the GPIO pins with a ribbon cable that you can order from the US. That&#8217;s cool, but ordering stuff from abroad can be expensive. And the pins look somehow like good old IDE. So I soldered an adapter myself and bought an IDE cable. Well, some pins worked, and some didn&#8217;t&#8230; Enough for the first round of experimenting, but it took a while to find out what&#8217;s going on. I just assumed that all the wires of the IDE cable were connected which for some reason was not the case.<\/p>\n<p>But something is missing that the arduino offers: analog. Before I really needed analog sensing capabilities, I found an <a href=\"http:\/\/www.raspberrypi-spy.co.uk\/2012\/08\/reading-analogue-sensors-with-one-gpio-pin\/#more-520\" target=\"_blank\" rel=\"noopener\">article, describing a hack to read analog input<\/a> by measuring the time it takes to discharge a capacitor through the resistance you want to measure. Immediately, I tried it myself with a photo resistor. The author warned, that the timings with the python script are not really accurate, and that the correct values for the components would have to be calculated. The Values I got were fluctuating wildly, and I couldn&#8217;t really see a difference with the brightness in all that noise.<\/p>\n<p>So I looked for something more accurate. I still have some AtTiny&#8217;s and they have analog inputs. But SPI is the only means of communication they support in hardware. Last week, I implemented uart receiving capabilities in software, but this time I was looking for i2c. <!--more-->I found <a href=\"http:\/\/code.google.com\/p\/codalyze\/source\/browse\/cyz_rgb\/trunk\/usiTwi\/?r=294\" target=\"_blank\" rel=\"noopener\">a library that seemed to fit<\/a>, but at first I didn&#8217;t get it to work. After a lot of experimenting and searching on the internet, I found out that I have to set the fuses for the internal PLL clock rather than the default internal RC oscillator. Actually the <a href=\"http:\/\/www.engbedded.com\/fusecalc\">fuse calculator<\/a> is a great tool for finding out the correct values for the fuses. The uart implementation initially also suffered from clock problems. I solved them by connecting a crystal as an accurate clock source. But this time I had also a stepper motor driver connected, and thus the pins of the AtTiny were exhausted. Another thing I learned while experimenting was that if I send a commad over i2c to the attiny while it is executing the steps for the stepper motor, i2c communication will be broken on the AtTiny until the next reset. When probed with i2cdetect, it seemed to respond on all possible addresses.<\/p>\n<p>The AtTiny has 10 bit analog inputs, but I configered the reading to 8bit precision, because it was a little bit easier, and for the light sensitive resistor, that&#8217;s accurate enough. The values I get are much more meaningful than what I got with the capacitor discharge method.<\/p>\n<p>I will make the code available on github, once the whole project is advanced a little bit further. Until then, here are the important parts:<\/p>\n<p>code on the attiny:<\/p>\n<pre class=\"brush: c; gutter: false; first-line: 1\">\/\/ This program is free software; you can redistribute it and\/or modify it under the\n\/\/ terms of the GNU General Public License as published by the Free Software\n\/\/ Foundation; either version 2 of the License, or (at your option) any later\n\/\/ version.\n\n\/\/ This program is distributed in the hope that it will be useful, but WITHOUT ANY\n\/\/ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n\/\/ PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n\n\/\/ This program will serve as an interface between the raspberrypi and the easystepper\n\/\/ as well as provide an analog input. Communication between the raspi and the attiny will be I2C.\n\/\/ Created by Richard Ulrich &lt;richi@paraeasy.ch&gt;\n\/\/ Inspired by :\n\/\/ http:\/\/www.schmalzhaus.com\/EasyDriver\/index.html\n\/\/ http:\/\/arduino.cc\/playground\/Code\/USIi2c\n\/\/ http:\/\/auv.co.za\/blog\/attiny45quadraturedecoder\n\/\/ http:\/\/correll.cs.colorado.edu\/?p=1801\n\n\/\/ ATMEL ATTINY45 \/ ATTINY85\n\/\/                                    +-\/-+\n\/\/ PCINT5\/!RESET\/ADC0\/dW        PB5  1|    |8  Vcc\n\/\/ PCINT3\/XTAL1\/CLKI\/!OC1B\/ADC3 PB3  2|    |7  PB2 SCK\/USCK\/ADC1\/T0\/INTO\/PCINT2\n\/\/ PCINT4\/XTAL2\/CLKO\/OC1B\/ADC2  PB4  3|    |6  PB1 MISO\/D0\/OC0B\/OC1A\/PCINT1            pwm1\n\/\/                              GND  4|    |5  PB0 MOSI\/D1\/SDA\/AIN0\/!OC0A\/AREF\/PCINT0  pwm0\n\/\/                                    +----+\n\/\/                       +-\/-+\n\/\/                      1|    |8  Vcc\n\/\/ stepper step      &lt;- 2|    |7 &lt;-  I2C_SCL\n\/\/               LDR -&gt; 3|    |6  -&gt; stepper direction\n\/\/               GND    4|    |5 &lt;-&gt; I2C_SDA\n\/\/                       +----+\n\n#include &lt;inttypes.h&gt;\n#include \"usiTwiSlave.h\"\n#include &lt;avr\/io.h&gt;\n#include &lt;util\/delay.h&gt;\n#include &lt;avr\/interrupt.h&gt;\n#include &lt;avr\/eeprom.h&gt;\n\nuint8_t  EEMEM i2cSlaveAddr = 0x10; \/\/ Default address\nuint16_t EEMEM stepDuration = 50;   \/\/ Default step duration\n\nint main(void)\n{\n\t_delay_ms(100); \/\/ give the master some time to grab the i2c bus\n\tsei(); \t\t\t\/\/ enable interrupts\n\tif(eeprom_read_byte(&amp;i2cSlaveAddr) &lt; 7 || eeprom_read_byte(&amp;i2cSlaveAddr) &gt; 77)\n\t\teeprom_write_byte(&amp;i2cSlaveAddr, 0x10);\n\tusiTwiSlaveInit(eeprom_read_byte(&amp;i2cSlaveAddr)); \/\/ initialize i2c\n\n\t\/\/ Set Port B pins 3 and 1 as output\n\tDDRB = (1 &lt;&lt; PB3) | (1 &lt;&lt; PB1);\n\n\t\/\/ Prepare for analog input\n\t\/\/ Configure ADMUX register\n\tADMUX = (1 &lt;&lt; ADLAR)| \/\/ 8bit precision\n\t\t\t(1 &lt;&lt; MUX1) | \/\/ Use ADC2 or PB4 pin for Vin\n\t\t\t(0 &lt;&lt; REFS0)| \/\/ set refs0 and 1 to 0 to use Vcc as Vref\n\t\t\t(0 &lt;&lt; REFS1);\n\n  \t\/\/Configure ADCSRA register\n\tADCSRA = (1 &lt;&lt; ADEN)| \/\/set ADEN bit to 1 to enable the ADC\n     \t\t (0 &lt;&lt; ADSC); \/\/set ADSC to 0 to make sure no conversions are happening\n\n\t\/\/ the main loop\n\twhile(1)\n\t{\n\t\t\/\/ set ADSC pin to 1 in order to start reading the AIN value\n\t\tADCSRA |= (1 &lt;&lt; ADSC);\n\t\twhile(((ADCSRA &gt;&gt; ADSC) &amp; 1))\n\t\t\t; \/\/ do nothing until the ADSC pin returns back to 0;\n\t\tconst uint8_t analogval = ADCH; \/\/for 8 bit precision we can just read ADCH\n\n\t\tif(usiTwiDataInReceiveBuffer())\n\t\t{\n\t\t\tconst uint8_t cmd = usiTwiReceiveByte();\n\n\t\t\tswitch(cmd)\n\t\t\t{\n\t\t\t\tcase 0xA1: \/\/ change the i2c address (sends 1 byte)\n\t\t\t\t{\n\t\t\t\t\tuint8_t recv = usiTwiReceiveByte();\n\t\t\t\t\teeprom_write_byte(&amp;i2cSlaveAddr, recv);\n\t\t\t\t\tusiTwiSlaveInit(recv); \/\/ initialize i2c\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 0xA2: \/\/ set the duration of a single step (sends 2 bytes)\n\t\t\t\t{\n\t\t\t\t\tuint16_t dur = usiTwiReceiveByte() &lt;&lt; 8;\n\t\t\t\t\tdur         += usiTwiReceiveByte();\n\t\t\t\t\teeprom_write_word(&amp;stepDuration, dur);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 0xB1: \/\/ move stepper forward   (sends 2 bytes)\n\t\t\t\t\tPORTB |= (1 &lt;&lt; PB1); \/\/ stepper direction forward\n\t\t\t\tcase 0xB2: \/\/ move stepper backwards (sends 2 bytes)\n\t\t\t\t{\n\t\t\t\t\tuint16_t steps  = usiTwiReceiveByte() &lt;&lt; 8;\n\t\t\t\t\tsteps          += usiTwiReceiveByte();\n\t\t\t\t\tuint16_t dur2   = eeprom_read_word(&amp;stepDuration) \/ 2;\n\t\t\t\t\tfor(uint8_t i=0; i&lt;steps; ++i)\n\t\t\t\t\t{\n\t\t\t\t\t\tPORTB |= (1 &lt;&lt; PB3);\n\t\t\t\t\t\tfor(uint16_t j=0; j&lt;dur2; ++j)\n\t\t\t\t\t\t\t_delay_ms(1);\n\n\t\t\t\t\t\tPORTB &amp;= ~(1 &lt;&lt; PB3);\n\t\t\t\t\t\tfor(uint16_t j=0; j&lt;dur2; ++j)\n\t\t\t\t\t\t\t_delay_ms(1);\n\t\t\t\t\t}\n\t\t\t\t\tPORTB &amp;= ~(1 &lt;&lt; PB1); \/\/ stepper direction low\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 0xC1: \/\/ query analog value of ADC2 with 8 bit (expects 1 byte)\n\t\t\t\t{\n\t\t\t\t\t\/\/ send the value from the analog input\n\t\t\t\t\tusiTwiTransmitByte(analogval);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}; \/\/ switch\n\t\t\tcontinue;\n\t\t}\n\n\t\t_delay_ms(10);\n\t}\n\n\treturn 1;\n}<\/pre>\n<p>client code on the raspberrypi:<\/p>\n<pre class=\"brush: python; gutter: false; first-line: 1\">#! python\n\nimport smbus, time\n\nclass AttinyStepper:\n\tdef __init__(self, i2cSlaveAddr = 0x10, stepDuration = 50, i2cBusNbr = 1):\n\t\tself.i2cSlaveAddr = i2cSlaveAddr\n\t\tself.stepDuration = stepDuration\n\t\tself.i2c = smbus.SMBus(i2cBusNbr)\n\t\t# set the step duration\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, 0xA2)\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, self.stepDuration &gt;&gt; 8)\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, self.stepDuration &amp; 0xFF)\n\n\tdef changeSlaveAddress(self, newAddr):\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, 0xA1)\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, newAddr)\n\n\tdef stepsForward(self, numSteps):\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, 0xB1)\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, numSteps &gt;&gt; 8)\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, numSteps &amp; 0xFF)\n\n\tdef stepsBackward(self, numSteps):\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, 0xB2)\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, numSteps &gt;&gt; 8)\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, numSteps &amp; 0xFF)\n\n\tdef readAnalog(self):\n\t\tself.i2c.write_byte(self.i2cSlaveAddr, 0xC1)\n\t\tlightval = self.i2c.read_byte(self.i2cSlaveAddr)\n\t\treturn lightval\n\n\tdef __repr__(self):\n\t\tprint \"attiny interfacing to the easy stepper driver at i2c address %d\" % self.i2cSlaveAddr<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The raspberrypi has some GPIO (General Purpose Input Output) pins. That&#8217;s great for experimenting with electronics for example sensors and actuators. It&#8217;s totally different than an Arduino in many respects, but that&#8217;s something they have in common. Some of the pins have special functions. For example SPI, I2C, UART &#8230; There is a breakboard adapter [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,7,1],"tags":[43,178,182],"class_list":["post-769","post","type-post","status-publish","format-standard","hentry","category-projects","category-software","category-uncategorized","tag-c","tag-python","tag-raspberrypi"],"_links":{"self":[{"href":"https:\/\/ulrichard.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/769","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ulrichard.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ulrichard.ch\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ulrichard.ch\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ulrichard.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=769"}],"version-history":[{"count":0,"href":"https:\/\/ulrichard.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/769\/revisions"}],"wp:attachment":[{"href":"https:\/\/ulrichard.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=769"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ulrichard.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=769"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ulrichard.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=769"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}