Hello all, I've been doing Arduino projects for a while now, and I've just started using ATTiny microchips.
A project I've been working on is a simple IR code transmitter en route to a more useful application within my projects. I've started with trying to control TVs.
My work is based off of AdaFruit's IR Sensor tutorial here. All ATTiny programming is done using Arduino as ISP.
I gathered the code for a "Nakamichi" TV remote power button. Uploading this code to an Arduino Mega 2560, I made it turn on and off successfully.
//#include "avr/eeprom.h" //I'm not sure if this is needed
#include "avr/pgmspace.h"
int IRledPin = 4; // LED connected to digital pin 4
int tvONsignal[] PROGMEM = {
// ON, OFF (in 10's of microseconds)
316, 272,
74, 120,
74, 122,
74, 124,
72, 124,
70, 124,
72, 124,
72, 220,
70, 126,
72, 126,
70, 124,
72, 124,
70, 124,
72, 222,
68, 126,
70, 224,
62, 232,
60, 380,
58, 2236,
296, 292,
50, 146,
48, 146,
52, 146,
50, 146,
48, 146,
50, 146,
50, 242,
50, 146,
52, 146,
48, 146,
48, 148,
48, 146,
52, 242,
48, 146,
52, 242,
48, 244,
50, 390,
50, 0
};
int ONcodeLength = sizeof(tvONsignal)/(2*sizeof(int));
// The setup() method runs once, when the sketch starts
void setup() {
// Serial.begin(9600);
// initialize the IR digital pin as an output:
pinMode(IRledPin, OUTPUT);
}
void loop()
{
// Serial.println("Sending IR signal");
SendTVONCode_P();
delay(3*1000); // wait three seconds (3 seconds * 1000 milliseconds)
}
// This procedure sends a 38KHz pulse to the IRledPin
// for a certain # of microseconds. We'll use this whenever we need to send codes
void pulseIR(int microsecs) {
// we'll count down from the number of microseconds we are told to wait
//cli(); // this turns off any background interrupts
while (microsecs > 0) {
// 38 kHz is about 13 microseconds high and 13 microseconds low
digitalWrite(IRledPin, HIGH); // this takes about 3 microseconds to happen
delayMicroseconds(10); // hang out for 10 microseconds, you can also change this to 9 if its not working
digitalWrite(IRledPin, LOW); // this also takes about 3 microseconds
delayMicroseconds(10); // hang out for 10 microseconds, you can also change this to 9 if its not working
// so 26 microseconds altogether
microsecs -= 26;
}
//sei(); // this turns them back on;
}
void SendTVONCode_P()
{
// All the delays are multiplied by 10 because the array values represent delays in 10's of microseconds
for (int i = 0; i < ONcodeLength; i++)
{
pulseIR(10*pgm_read_word(&tvONsignal[2*i]));
delayMicroseconds(10*pgm_read_word(&tvONsignal[2*i + 1]));
}
delay(65); // delay and send code again
for (int i = 0; i < ONcodeLength; i++)
{
pulseIR(10*pgm_read_word(&tvONsignal[2*i]));
delayMicroseconds(10*pgm_read_word(&tvONsignal[2*i + 1]));
}
}
As you can see, I used PROGMEM to try to save RAM, especially when using a smaller ATTiny13a. I also made a for-loop to cycle through the pulses and delays stored in an array instead of explicitly flashing each one directly. This saved space (memory overflow before), and helped with compatibility with other controls. I also didn't turn off background interrupts (I tried before and it didn't do anything).
When uploading this same code to my ATTiny13a, however, the two blinks of code transmission are much faster. Perhaps half of the time it took my Arduino Mega 2560 to transmit the same code. I tried it on my TV anyway, and it didn't work.
I tried to figure out what was wrong with it for a long time. Almost 3 days of nonstop Google-ing, and I've narrowed it down, but haven't gotten it working yet. First, I made sure that accessing the codes from program memory was going successfully, I did this by blinking an LED a certain number of times (from the code I was trying to transmit) divided by 10. For example, I made the LED blink a number of times equal to pgm_read_word(&tvONcode[0])/10. This is 316/10 = 31 times (integer division), and indeed it was accessing the array as expected, even after trying several values.
Since I suspected the internal clock for the ATTiny13a wasn't operating the same as the Arduino Mega 2560 (from the faster blinking), I wanted to test it in another way to make sure it wasn't my code that was buggy. I uploaded the basic blink sketch to see if the interval was indeed 1 second exactly. Lo and behold, it was not. It was about 1.25 seconds (hand-timed by me). I made sure it was accurate by blinking at 10 second intervals, and I got about 12.6 seconds.
To try to fix it, I tried multiplying the delays by 1/1.26, but that didn't work either. It also took a lot more space, since non-integers are stored as floating point numbers, and it ended up overflowing.
My attempts to fix this include changing the boards.txt file in the ATTiny13a core files.
###########################################################################
attiny13int.name=Attiny13 @ 128 KHz (internal watchdog oscillator)
attiny13int.upload.using=arduino:arduinoisp
attiny13int.upload.maximum_size=1024
attiny13int.upload.speed=250 # important for not losing connection to a slow processor
attiny13int.bootloader.low_fuses=0x7B
attiny13int.bootloader.high_fuses=0xFF
attiny13int.bootloader.unlock_bits=0x3F
attiny13int.bootloader.lock_bits=0x3F
attiny13int.build.mcu=attiny13
attiny13int.build.f_cpu=128000
attiny13int.build.core=core13
###############################################################
attiny13at4.name=ATtiny13 @ 4.8MHz (internal 4.8 MHz clock)
attiny13at4.upload.using=arduino:arduinoisp
attiny13at4.bootloader.low_fuses=0x69
attiny13at4.bootloader.high_fuses=0xff
attiny13at4.upload.maximum_size=1024
attiny13at4.build.mcu=attiny13
attiny13at4.build.f_cpu=600000
attiny13at4.build.core=core13
###############################################################
attiny13.name=ATtiny13 @ 9.6MHz (interne 9.6 MHz clock)
attiny13.upload.using=arduino:arduinoisp
attiny13.bootloader.low_fuses=0x7a
attiny13.bootloader.high_fuses=0xff
attiny13.upload.maximum_size=1024
attiny13.build.mcu=attiny13
attiny13.build.f_cpu=9600000
attiny13.build.core=core13
###############################################################
I tried 128kHz, 600kHz, 1MHz, 1.2MHz, 4MHz, 4.8MHz, 8MHz, 9.6MHz, 10MHz, 12MHz, and 16MHz by changing the number in the last block from 9600000 to each one of the frequencies I wanted to try. This didn't work. I also tried changing to each frequency AND burning the bootloader then testing my code, and still no luck. Each time, the blinking speed would change. Maybe I have to reprogram the fuse bits (which might change the hex numbers in the board.txt file), but I don't know how to safely do any of that. I have nothing left.
So, if anyone has any ideas, please help me out and I will be very thankful. If anyone has any questions, just post here and I will reply as soon as possible.
PS: Sorry for the long post; I just wanted to be very thorough.