Hi All
This is something I struggled with so I thought I would share my experience and how I went about solving the issues I had. My aim was to implement a sensor which would trigger if it detected any noise above a set threshold. It is part of a bigger system which makes use of an I2C bus, so I had to get that working on the ATTINY85 as well. I hope this will help anyone trying to use a ATTINY in Arduino.
My development PC is an Intel I5 running Windows 7 Pro.
A summary of what I did:
- Get the AVR ISP MkII and attiny85 to work from Arduino IDE
- Get the I2C interface working
- Get the bipolar ADC on the tiny up and running
AVR ISP MkII and Arduino
Very debated topic. I first tried it with 1.5.5 but eventually gave up. I installed the latest libusb-win32 drivers for it and it seemed to work until I connect it to the circuit. When it it not connected to the board, avrdude gives a status: MOSI fail, SCK fail which is to be expected. As soon as it is connected to the circuit, it gives the classic did not find any USB device "usb" error associated with incorrect drivers. This baffled me for some time until I eventually gave up and moved to 1.0.5 which works fine, which suggests that there is something broken in 1.5.5.
I did not try any other versions as I did not have too much time to fiddle around.
ATTINY85 and Arduino
This went hand in hand with the programmer. I made use of the "google" tiny core called arduino-tiny available from Google Code Archive - Long-term storage for Google Code Project Hosting.. The core I used was version 0100-0018. Just follow the instructions contained in the README file. From Prospective Boards.txt I just took the attiny85 running at 8MHz internal oscillator to create the boards.txt file. That is the IDE done and dusted.
The Arduino pin names are described in cores\tiny\pins_arduino.c. REMEMBER TO DO A "BURN BOOTLOADER" BEFORE UPLOADING YOUR SKETCH. This will set the correct fuse bits for the internal oscillator, etc. If you change to a different board (chip/freq), you will have to burn bootloader again. To upload the sketch, hold down SHIFT and click on upload, or select Upload Using Programmer from the file menu (I make use of the file menu option since my free hand holds down reset on my I2C bus master UNO to free up the I2C lines during programming).
I2C Slave Implementation
I first tried using the USIi2c available from Arduino Playground - USIi2c, but I found it not to work reliably. In my final solution I used the latest version from GitHub - rambo/TinyWire: My modifications to TinyWire Arduino libs where the onRequest and onReceive were implemented and that works 100%.
Bipolar ADC Implementation
The final part of the project was to connect a condenser microphone to the ADC inputs of the tiny85 and set the ADC to bipolar mode. After studying the core files and the datasheet, the solution was fairly simple. Just set the BIN bit in ADCSRB, set the reference to internal 1.1V and give the correct channel number to analogRead() in the core libraries. There was no need to change any of the core libraries, though it is my plan to change it to support differential inputs directly. The only trick with the unmodified core is to select channel number 13 if you are using A2 and A3 for differential input. The way to determine the channel number is to go look in core_adc.h, convert the binary value next to the configuration you need to decimal (in my case Pos2_Neg3_20x = B0111 which is 7) and add 6. The value of 6 is because the arduino analog pin numbers come after the digital pins, and the attiny has 6.
On the hardware side of the ADC in bipolar mode, it is important that the internal 1.1V reference is used. The ADC can behave funny if the reference is left at DEFAULT.
Code for my ATTINY85 noise trigger:
#include <TinyWireS.h>
const byte I2C_SLAVE_ADDR = 0x5;
const byte LED_PIN = 1;
int adcReading = 0;
int adcMax = -1000;
int adcMin = 1000;
int triggerLevel = 60;
byte triggerCount = 0;
volatile byte i2cReadPos = 0;
volatile byte i2cBuf[4];
void setup() {
pinMode(LED_PIN, OUTPUT);
TinyWireS.begin(I2C_SLAVE_ADDR);
TinyWireS.onReceive(receiveEvent);
TinyWireS.onRequest(requestEvent);
analogReference(INTERNAL);
ADCSRB|= 0x80; // enable bipolar input mode
}
void loop() {
adcReading = analogRead(7 + CORE_ANALOG_FIRST); // bipolar input channels 2 and 3 20x gain
if (adcReading > 511) adcReading-= 1024;
if (adcReading > adcMax) adcMax = adcReading;
if (adcReading < adcMin) adcMin = adcReading;
if (triggerCount < 255){
if (adcReading < -triggerLevel){
triggerCount++;
} else if (adcReading > triggerLevel){
triggerCount++;
}
}
digitalWrite(LED_PIN, triggerCount ? HIGH : LOW);
}
void requestEvent() {
if (i2cReadPos){
TinyWireS.send(i2cBuf[--i2cReadPos]);
} else {
TinyWireS.send(0);
}
}
void receiveEvent(byte howMany){
if (howMany < 1) return;
if (howMany > 5) return;
while(howMany--){
switch (TinyWireS.receive()){
case 1: // get current adc reading
i2cBuf[1] = adcReading >> 8;
i2cBuf[0] = adcReading & 0xFF;
i2cReadPos = 2;
break;
case 2: // get Min/Max values
i2cBuf[3] = adcMin >> 8;
i2cBuf[2] = adcMin & 0xFF;
i2cBuf[1] = adcMax >> 8;
i2cBuf[0] = adcMax & 0xFF;
i2cReadPos = 4;
adcMin = 1000;
adcMax = -1000;
break;
case 3: // set trigger level
triggerLevel = TinyWireS.receive() * 256 + TinyWireS.receive();
break;
case 4: // get trigger count
i2cBuf[0] = triggerCount;
i2cReadPos = 1;
triggerCount = 0;
break;
}
}
}