Removing the 555 from my circuit....ATtiny85 with crystal.

So,

I want to pulse an LED at 38KHz (period = 26uS) with an Attiny85 as the “controller”, to send IR codes.

Now, I currently have a working circuit with a 555 chip, the LED does blink at 38KHz and I can use the reset pin of the 555 to send IR codes. I seem to have a break down at a certain baud rate (using the Vishay stuff) but another issue for later if I do want more speed.

The 555 takes power. I know there are “lower power” CMOS versions…but secondly it takes up board space, costs a little, needs calibrating (variable resistor) and requires 2 caps as well.

So, I am looking at using an external 20MHz crystal with the two caps (I have ordered some 12pf, 18pf and 22pf to test). This gives me a period of 0.05uS!

So if I have basic code such as:

byte IRled = 0;

void setup() {

  pinMode(IRled, OUTPUT);
}

void loop() {

  int x = 3124;

  for (byte i = 0; i < 16; i++) {

    if (bitRead(x, i)) {
      highbit();
    }
    else {
      digitalWrite(IRled, LOW);
      delayMicroseconds(1000);
    }
  }

}

void highbit() {
  // 26uS period = HIGH -> 13uS -> LOW -> 13uS ->HIGH
  // One period = 26uS. 1ms per bit = ~ 40 periods

  for (byte i = 0; i < 40; i++) {
    digitalWrite(IRled, HIGH);
    delayMicroseconds(13);
    digitalWrite(IRled, LOW);
    delayMicroseconds(13);
  }
}

Would this be feasible? 20MHz is 0.05uS per clock cycle. Was hoping that means with the 20 clock cycles per microsecond that would be fast enough?

The microseconds/for loops could be used to “calibrate” maybe?

Thanks!

Would save soldering and board space and even power hehe.

OK my bad.

I found a 16MHz crystal and some 22pf ceramic caps in the box of "salvageable random electronic junk".

Wired up a basic ATtiny85 with just a resistor and LED (output) with the crystal across pins 2 and 3, each pin with a 22pF cap to GND.

It works...so I can only assume 20Mhz is even finer...

Why don't you use ready-made IR sender modules, coming with their own modulators?

You may have problems with the microsecond delay, because the clock (T1) typically uses 4µs ticks. This will make a 13 micros delay range from 12 to 16µs effectively, not very precise :frowning:

I'd use a timer to produce the carrier frequency, instead of the 555, and only turn on and off the timer output generator. This may work without an external crystal as well. Then you also can use that timer to output pulse trains and pauses in exact multiples of the carrier frequency.

I'm not really familiar with the Tiny's, please look up details about their hardware features in the data sheet yourself!

Thanks both.

I have found some basic code that turns on a pin timer and is giving me a nice square wave output.

byte led=2;

void setup() {
  // put your setup code here, to run once:
   DDRB |= (1<<PB0); //Set pin PB0 as output

 TCNT0 = 0;
 TCCR0A=0;
 TCCR0B=0;
 
 TCCR0A |=(1<<COM0A0); //Timer0 in toggle mode Table 11-2
 TCCR0A |=(1<<WGM01); //Start timer 1 in CTC mode Table 11.5
 TCCR0B |= (1 << CS00);// Prescaler table 11.6
 OCR0A=104; //CTC Compare value 

 pinMode(led,OUTPUT);
 
}

void loop() {

  for (byte i = 0; i < 8; i++){
  digitalWrite(led,HIGH);
  delay(500);
  digitalWrite(led,LOW);
  delay(500);
 }
  
}

The timer code works fine. I get the 38Khz I am after on PB0 (pin 5).
The problem is then all other I/O pins seem non-functional. Is delay or something effected by the use of the timer?

Johnny010:
...
The timer code works fine. I get the 38Khz I am after on PB0 (pin 5).
The problem is then all other I/O pins seem non-functional. Is delay or something effected by the use of the timer?

You will be very probably right: Arduino (UNO) uses Timer/Counter0 to count time. I think Arduino ported to ATTiny85 will work the same way. You may use Timer/Counter1 for the square wave generating or your own counting of time (for inaccurate time counting you can even use Watchdog in interrupt mode). Try to look into ATTiyn85 datasheet and discover how the code you posted works. It should be easy to use Timer/Counter1 to generate the square wave.

If the ATTiny would work in stable conditions you can use internal RC oscillator instead of external crystal. You need much lower frequency to be able to generate the PWM and you can callibrate the oscillator with 1% precision (given constant temperature and voltage).

Johnny010:
The timer code works fine. I get the 38Khz I am after on PB0 (pin 5).
The problem is then all other I/O pins seem non-functional. Is delay or something effected by the use of the timer?

Please check your setup code. The timer registers should be completely initialized, only setting some bits can result in unwanted operation, as you already observed. At least the timer interrupts should be disabled, else the installed ISRs may run too often.

Use a different timer, If possible, because T0 is used for system timekeeping (millis...).

Smajdalf:
You will be very probably right: Arduino (UNO) uses Timer/Counter0 to count time. I think Arduino ported to ATTiny85 will work the same way. You may use Timer/Counter1 for the square wave generating or your own counting of time (for inaccurate time counting you can even use Watchdog in interrupt mode). Try to look into ATTiyn85 datasheet and discover how the code you posted works. It should be easy to use Timer/Counter1 to generate the square wave.

If the ATTiny would work in stable conditions you can use internal RC oscillator instead of external crystal. You need much lower frequency to be able to generate the PWM and you can callibrate the oscillator with 1% precision (given constant temperature and voltage).

Thank you. Already been on it. My head is spinning as registers and stuff are pretty new to me.
Don’t get me wrong, I have seen them and sort of understand what they do (like a list of set up instructions for the MCU).

A lot of the language is new and I have tried in the last hour with the datasheet alone come up with this…it doesn’t work as I expected…but I am sort of happy I can change the prescaler and get different PWM frequencies on PB1…

Any idea what I am doing wrong? I want 38Khz (or 40 and then mess with the calibrator to get 38Khz ish or as close as later).

I seem to have managed (somehow…no idea how) to get the 26uS I need. Doesnt match up with the datasheet. Also dont have the usual delay() working.

The green LED comes on and does not blink. The IR led I have on PB1 (the PWM pin) is producing the 38KHz I want (but I have no idea why…I just messed till it kinda worked?). Sorry for my notes.

byte greenled=3;

void setup() {
  // put your setup code here, to run once:
   DDRB |= (1<<PB1); //Set pin PB1 as output

 cli();
 TCCR1=0b00000000;    //Timer 1 Register cleared.
 PLLCSR |=(1 << PCKE); // Asynchronous Mode
 OCR1C = 60;         // Not sure what this does? Like a max roll over for the counter?
 TCCR1 |= (1 << CTC1); // The timer is cleared when the counter and compare 
                       //register value match. CTC1 is the register bit to cause the 
                       //clearing in the TCCR1 byte register.
                       
 TCCR1 |= (1 << COM1A0); //Bits 5 and 4 of TCCR1 (COM1A0 and COM1A1) indicate what to do when comparator == counter
 TCCR1 |= (0 << COM1A1);  // When A0 is 1 and A1 is 1, the pin is toggled on a compare.

 TCCR1 |= (0 << CS13);    // Set Prescaler to 40KHz. "The Clock Select bits 3, 2, 1, and 0 define the prescaling source of Timer/Counter1"
 TCCR1 |= (0 << CS12);    //CS 0001 OCR1C 64....I seem to be getting near the 26microsecond PWM period I need???? 
 TCCR1 |= (0 << CS11);
 TCCR1 |= (1 << CS10);
 


 pinMode(greenled,OUTPUT);
 
}

// Loops still not working. Green indicator LED connected to PB3 (digital 3).
// PB3 = PCINT3/XTAL1/CLKI/OC1B_/ADC3

void loop() {

  digitalWrite(greenled,HIGH);
  delay(500);
  
  digitalWrite(greenled,LOW);
  delay(500);
  

}

What does PLLCSR.PCKE affect? Are you sure that you need to change it?

You can update TCCR1 in one go, like

TCCR1 = 0 //allow to exclude any of the following lines by //
      | (1<<CTC1) //...
      | ...
      ;

This will prevent invalid or undesired register states, which can occur when the bits are set in subsequent instructions.

One Output Compare Register (usually OCRnA - see data sheet) can be used to force a compare match, which in turn can reset the counter, so that it will run at the required frequency. The match also can be used to toggle the counter output pin. I think that you figured out most of that already.

For your high speed signal you can set the prescaler to clk/1, and load half of the required ticks for 26µs (13ticks_per_microsecond, i.e. 1316 for a 16MHz clock) into the OCR. This allows to fine tune the output frequency to 2 clock ticks per period. A higher prescaler divider is only required when the value doesn’t fit into the OCR.

Also make sure that you enable interrupts after calling cli()!

Delay works on inner counting of time: it counts overflow interrupts from Timer0. By cli() you disable ALL interrupts so the ATTiny thinks no time have elapsed and first delay() takes forever. Remove the cli() command and set Timer1 to not trigger any interrupts (maybe it is already set this way).

Thanks so much. Karma for all.

So I ended up with:

byte greenled = 3;

void setup() {
  // put your setup code here, to run once:
  DDRB = 0;
  DDRB |= (1 << PB1); //Set pin PB1 as output
  OCR1C = 8;    // Counter Max


  TCCR1 = 0
          | (1 << COM1A0) //Bits 5 and 4 of TCCR1 (COM1A0 and COM1A1) indicate what to do when comparator == counter
          | (0 << COM1A1)  // When A0 is 1 and A1 is 0, the pin is toggled on a compare.
          | (0 << CS13)
          | (1 << CS12)  // Table 12-5. Timer/Counter1 Prescale Select
          | (0 << CS11)
          | (0 << CS10);

  pinMode(greenled, OUTPUT);

}

void loop() {

  digitalWrite(greenled, HIGH);
  delay(500);

  digitalWrite(greenled, LOW);
  delay(500);


}

I have a flashing LED and also the PWM output I needed!

My last question, although this “works”…why are my values 8 for the compare register when my pre-scalar is at 40KHz? I can’t quite understand the datasheet.

PS: I am using the internal 8MHz clock. I may change this to an external 16MHz or External 8MHz in future.

My assumptions:
When a clock cycle happens, the counter is incremented. The value is compared against the register OCR1C. If it is equal (8 clock cycles), then the output pin is switched (PB1) and the clock reset.

So by my working…8Mhz with 8 clock cycles = 1micro second. Not the 13 or 26?

The counter increments in prescaled (1µs) steps, reaching 13 and reset to zero after 13µs. Well, not exactly, my bad :frowning:
The counter is reset with the next prescaler tick, thus the OCR should be set to 12 to make the counter count from 0 to 12 inclusively. See the formula for CTC mode.

You don't understand the datasheet well.
I guess you refer to table 12-3. If you set prescaler to PCK/8 (asynchronous mode from PLL running at 64 MHz) and OCR1C to 199 you will get PWM with frequency 40 kHz while duty cycle of the PWM will be determined by OCR1A or OCR1B.
For me readig registers description is best source of information:
You set clock source by CS1 in TCCR1, look at table 12-5. Your setting 0100 means timer frequency will be CK/8. If you really have main clock at 8Mhz, the Timer1 runs at 1MHz. So it increments TCNT1 register with 1MHz frequency. When TCNT1==OCR1C in next (timer clock) tick TCNT1 is reset to 0 instead of incremented. When TCNT1 gets to 0 (== OCR1A's default value) the PB1 pin is toggled (Table 12-4). That means the PB1 should be toggled every (OCR1C+1)==9 us, the whole cycle should take 18 us and your output should have 1000/18 ~ 56 kHz frequency on PB1.

Are you sure you have 38 kHz?
Are you sure the clock speed of the ATTiny is 8 MHz?

Smajdalf:
Are you sure you have 38 kHz?
Are you sure the clock speed of the ATTiny is 8 MHz?

Thanks, that has made things a lot more clear.

Well now I feel like an idiot. Someone had told me my HAMEG 3 oscilloscope had a 1kHz calibration frequency.

I have just set up a trusty arduino UNO and set to output a 2ms HIGH 2ms LOW signal and calibrated my scope to it…it now actually gives the 26us ish period I’d expected.

I have the ATtiny85 bootloaded as 8MHz via the Arduino IDE using Arduino as ISP.

Here are my registry settings:

  DDRB = 0
         | (1 << PB1); //Set pin PB1 as output
  OCR1C = 12;    // Counter Max
  
  TCCR1 = 0
          | (1 << COM1A0) //Bits 5 and 4 of TCCR1 (COM1A0 and COM1A1) indicate what to do when comparator == counter
          | (0 << COM1A1)  // When A0 is 1 and A1 is 0, the pin is toggled on a compare.
          | (0 << CS13)
          | (1 << CS12)  // Table 12-5. Timer/Counter1 Prescale Select
          | (0<< CS11)
          | (0 << CS10);

So the clock select is the CK/8 (0100) giving the 1uS pulses per clock tick.
I want a 26uS period, so 13uS per HIGH and LOW.
The OCR1C = 12 (12 values including 0?) clock reset register.

So I am now getting the 26uS I expect!

Lesson on the day.

#1 Don’t trust anyone. Find the manual.

Thanks again by the way! Already feel a lot more confident with registers and reading datasheets…some way to go though I bet ha!