2
\$\begingroup\$

I'm using an ATtiny13 running at 1.2 MHz and would like to generate a 40 kHz square wave on PB3 and PB4. The signal on PB4 should be 180 degrees offset (inverted) from PB3.

I know that I need to set certain registers to achieve this, but I do not know which registers or which values they need to be set at.

Any help with the code would be appreciated.


Update:

Thank you for the help so far. This is what I have got:

void setup() {

// Disable all interrupts
TIMSK0 |= (0<< OCIE0B) | (0<<OCIE0A) | (0<<TOIE0);

// Define outputs
DDRB = (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);

// Enable CTC
TCCR0A |= (1<<WGM01) | (0<<WGM00); 
TCCR0B |= (0<<WGM02);

// 1.2MHz / 40kHz 
OCR0A = 30;
OCR0B = 30;

// Toggle on Compare Match
TCCR0A |= (0<<COM0A1) | (1<<COM0A0) | (0<<COM0B1) | (1<<COM0B0);

// No prescaler
TCCR0B |= (0<<CS02) | (0<<CS02) | (1<<CS00);

// Make it start
GTCCR |= (1<<PSR10);

// Force one invert
TCCR0B |= (1<<FOC0B);
}

void loop() {
}

With this code, I am getting an 18.5 kHz signal on PB2 and PB1, with a 180 degree phase shift between them.

Does the code look correct or have I missed something? If I play around with the OCR0A and OCR0B values, I might be able to get the desired 40 kHz. However I should not have to do that, since 30 should be the correct value if the microcontroller is running at 1.2 MHz.

Any ideas?

\$\endgroup\$
  • 2
    \$\begingroup\$ Hello Alex , EE is not working like that. Firstly show what you have tried so far , what problems you faced. Put some works of you so that we try to find a solution. \$\endgroup\$ – emre iris Feb 18 at 17:55
  • 1
    \$\begingroup\$ Read ATTiny13 manual. There you can find the whole list of registers and how to achieve what you want \$\endgroup\$ – John Am Feb 18 at 18:23
  • \$\begingroup\$ Are you wanting to use PWM or are you simply toggling pin states? \$\endgroup\$ – JYelton Feb 18 at 18:58
  • \$\begingroup\$ So take a look at the timer/counter section of the datasheet for the microcontroller. That holds the answer to your question. \$\endgroup\$ – Jaywalk Feb 18 at 19:16
  • \$\begingroup\$ @JYelton Pulse width does not need to change so I assume toggling the pin state at the desired frequency would be the simplest and best solution. \$\endgroup\$ – alex Feb 18 at 19:21
2
\$\begingroup\$

I often use the ATtiny13 for little one-off projects that blink LEDs or control timing of external switches (theatrical props). Sometimes I just need them to change an IO pin at a given frequency and literally nothing else. The following is a quick and dirty way to toggle a GPIO using a delay.

Note: this is not a timing-accurate nor recommended way to accomplish this in an efficient manner. Using a timer and PWM allows you to continue executing other code while the signal is generated.

#define F_CPU 1200000

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    // Set PB3 and PB4 as output
    DDRB |= (1 << DDB3) | (1 << DDB4);
    // Start PB4 high
    PORTB |= (1 << PORTB4);

    while (1) 
    {
        // Toggle PB3 and PB4
        PORTB ^= (1 << PORTB3) | (1 << PORTB4);
        // 40kHz period is 25µs
        _delay_us(25);
    }
}

Toggling pins isn't a single clock-cycle, and the util/delay function is not accurate, so delaying for 25 microseconds is a naive approach, but if your requirements are not strict, it may suit your purpose. Adjust the delay value if needed.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Most microcontrollers have a dizzying array of counter-timer features, and it can certainly be tricky to set them up how you want them.

The critical information is in chapter 11. 8-bit Timer/Counter0 with PWM of the ATTiny13 datasheet.

The place to start is with table 11.8 where you want a mode which goes from BOTTOM (0) to a number you choose OCRA (modes 2, 5 or 7 of that table). "Counter-Timer Match" mode 2 is probably the simplest, but you can probably do what you want with the 5 and 7.

All the code will look pretty much like the example at the top of page 52.

I didn't try it, but this is what you'll have to do.

  • No interrupts (TIMSK0)
  • Pins A and B to be outputs (DDR etc in 10.2.1, note text about pullups)
  • a counting mode which counts from 0 to N and then resets to 0 ("Clear Timer on Compare Match", mode 2 of table 11.8)
  • N is OCR0A, needs to be 1.2e6 / 40e3 = 30
  • Ouptput on pin A, invert every time the counter gets to P (COM0A1:0, mode b01 of Table 11-2.)
  • P is defined to be the same as N (it's OCR0A)
  • Output on another pin B, inverts B every time the counter gets to Q (COM0B1:0 mode b01 of table 11-5)
  • Q is OCR0B, also 30
  • No prescaler (CS02:0) and counter values (30) to get your desired frequency
  • Make it start (GTCC0)
  • Force B to invert once (FOC0B Force Output Compare B)
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.