PWM pins on ATTiny841

Hi Guys,

I'm currently designing a board to provide up to eight digital outputs and at least two digital inputs. I need as many of the digital output pins as possible to be pwm, so it seemed to me that the ATTiny841 would be ideal as it is said to have up to 6 pwm channels.

Now, the pcb design is relatively straightforward, but I now realise that programming the unit is going to be trickier than I thought because, I believe, that for output pins to be pwm they have to be allocated in the code first and not just used in the same way as the pwm pins on the devices I have used before. From the data sheet it seems that you have to configure registers to do this. This is something I know absolutely nothing about unfortunately, having previously only written relatively simple sketches for manipulating leds for ATMega328 and ATTiny85 chips before.

Is there any recommended source of reading that would take a relative newbie like myself through the processes involved, such that I would be able to understand which data I would need from the ATTiny841 datasheet and how to use it, or an example of the coding method?

Many Thanks
Bernie

The ATMega328 has 6 PWM pins. I don't see why you need a ATTiny841 for that. And if you really want to use the 841, check out http://forum.arduino.cc/index.php?topic=304606.0 . They have a 7-page discussion about the 841 in the IDE.

If you use my ATTiny841 core (link in sig) you don't have to worry about that - it already sets the TOCCR registers.

Setting up which pins have the PWM output on them if you're programming via atmel studio or writing your own core or something is trivial in any case; it's a pair of 1-byte registers, with 2 bits per pin, which you can set to either timer 0, 1, or 2.

In my core, I do this:

static void initTimer841(void) 
{
  Timer2_ClockSelect(0);
  TOCPMSA0=0b00010000;
  TOCPMSA1=0b10100100;
  TOCPMCOE=0b11111100;
  Timer2_SetWaveformGenerationMode(1);
  Timer2_ClockSelect(3);

}

TOCPMSAx registers set which outputs go to which timers, TOCPMCOE sets which pins output PWM when the timer they're pointed at is generating PWM (as opposed to ignoring that and acting as normal IO pins) That function gets called by main() as part of init() (before it calls setup() or loop())

Take a look at the pinout I use in my core:

Note how the two pwm remap options would conflict with serial0.

On the topic of PCB design, I also sell breakout boards (even assembled ones) for the ATTiny841 - again, see tindie link in sig :wink:

Honestly, I think the Tiny841 is probably the coolest chip in the ATtiny line, and I've probably got more of them doing something than I have '328p-based projects. Having the hardware serial, so you can get a nice compact Optiboot bootloader onto them makes a surprisingly big difference.

@Isaac96

My main reason for choosing to use the ATtiny841 is that I need to keep my board design as small and compact as possible and because there are 20 pins for the ATtiny841 as opposed to 32 for the ATmega328 it seemed the 841 was the better choice, seeing as most of the 328's i/o's would end up unused.

@DrAzzy

Well, that just goes to illustrate my lack of knowledge! I had, in fact, already downloaded your core to use. I didn't realise that it also set the pwm allocations! I note what you say about the serial pins - so, can I edit the core to allocate pwm to two different pins? If so, how would I go about editing the file? In fact, perhaps the question should be - which file do I edit and what do I do with it in order to modify the core? Showing yet more of the steepness of my learning curve there!

I did consider buying some of your boards actually, but they were out of stock when I looked :-[, so I've breadboarded a chip for the software development. My final design carries the voltage regulator and an ULN2803 transistor array as well. It will have a specific function to perform, so the input and output connections will be grouped in clusters rather than neatly in a row. Eventually I'll be getting batches of 100+ made, so I need to get it right!

Thanks Guys
Bernie

There are two things you'd need to change in the core if you wanted to change that...
In wiring.c, you'd need to change the values those registers are set to (see datasheet). This you could just do in your program - but analogWrite() wouldn't know about the change, and would still respond to the old pin numbers.

To fix that, you'd need to change the CORE_OCxx_PIN defines in core_pins.h

I'm not sure you really want to do that though - you only get 8 options for which pin can have PWM, so if you want 6 PWM channels, you only get 2 non-PWM pins out of those, and those are needed for the serial port...

(er - 20 pins? It's a SOIC-14 package - it's got 11 IO pins)

It comes in a couple of QFN packages as well, the smallest is 3x3mm. Half a dozen of the pins are NC.

edit: I wish the 841 had an asynchronous timer

Aaah, yeah, that is a shame, but this is a tiny, and a cheap one too; we already get three timers, dual uarts, a real SPI port and a dozen ADC channels, so maybe asking for an async timer is getting greedy - though they were least kind enough at least to give us external clock option for all three timers.

Thanks again DrAzzy :slight_smile: Yes, jboyton is right, it's the QFN package that I'll be using for space saving. As I won't have to do the actual soldering (I'll be getting the boards made and assembled commercially) the small footprint is ideal.

Now that I think about it, I probably won't be using the serial port for comms (I'll be programming using pogo pins via a set of ICSP pads, and will make SDA and SCL available for future I2C use) so the pin mapping on your pinout diagram will work just fine for me.

Bernie

Atmel took out the 8-bit asynchronous timer (that you find in an Atmega328 and a few of the Tinys) and replaced it with a second 16-bit timer (that the 328 lacks). It's a tradeoff. They have so many Tinys but it's impossible to offer every combination of features.

STDummy -- where are you getting the soldering done? Is it expensive?

jboytone -- I get my boards made and assembled in China (sorry to the local companies, but they can't compete on price or lead times). The actual company I use is called Sitopway - easy to find on ebay or Google.

As to price, for my last boards(s) I paid around 485usd for a batch of 100 (ie 4.85usd each). That breaks down as:

  • 60usd for the pcbs (each 0.75 by 2 inches in size overall)
  • 313usd for the components (attiny84A-MU, 4 or 5 leds, 10 resistors, a few capacitors and an ICSP 6 pin header on each board)
  • 82usd soldering cost
  • 30usd for the solder stencil (one off cost)
    Shipping costs (which included another batch of other boards) worked out at 30usd to the UK and the total time from sending the gerbers to receiving the boards was about two weeks. Sometimes I get clobbered by customs, sometimes I don't.

HTH
Bernie

Thank you.

Apologies for resurrecting this thread guys, but I seem to have run into a bit of a problem. I'm using DrAzzy's ATtiny841 core and I thought at first all was well as I simply loaded the blink sketch into a breadboarded ATtiny841 and it worked as it should. Problem is, I can't get analogWrite to work. No matter what values I instruct, I only get the equivalent of analogWrite (pin, 0) or (analogWrite pin, 255) - ie the same as digitalWrite (pin, LOW) or (digitalWrite pin, HIGH). A simple fade up and down sketch results in a blink sketch.

Anyone else have this problem, or have I missed something and have to edit the core in any way? I thought from what DrAzzy mentioned that pins 2, 3, 7, 8, 9 and 10 were defined as pwm by the core - but they don't behave as such.

Bernie

I cannot reproduce this problem. Onboard LED on pin 2 works with analog write, and you say it doesn't work on pin 2.

Can you please post code that has this problem?

Also what board is selected from boards menu?

Physical pin 2 or arduino pin 2?

Hi Guys

Thanks for the replies. I've tried again this morning and it gets stranger. Pins 2, 3 and 7 (PB2, PA7 and PA3) do work ok with the sketch, but pins 8, 9 and 10 (PA2, PA1 and PA0) do not, they just give HIGH and LOW outputs.

Here's the sketch:

/*
 Fade
 
 This example shows how to fade an LED on a pin
 using the analogWrite() function.
 
 This example based on the Arduino Example Fade sketch
 but modified to use timing instead of the delay() function
 
 */
int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by
unsigned long currentTime;
unsigned long loopTime;
int pin = 10;
 
void setup()  { 
  // declare pin to be an output:
  pinMode(pin, OUTPUT);
  currentTime = millis();
  loopTime = currentTime; 
} 

void loop()  { 
  currentTime = millis();
  if(currentTime >= (loopTime + 20)){  
    // set the brightness of pin:
    analogWrite(pin, brightness);    

    // change the brightness for next time through the loop:
    brightness = brightness + fadeAmount;

    // reverse the direction of the fading at the ends of the fade: 
    if (brightness == 0 || brightness == 255) {
      fadeAmount = -fadeAmount ; 
    }     
    loopTime = currentTime;  // Updates loopTime
  }
  // Other processing can be done here
                           
}

Its pretty much the example fading sketch supplied with the IDE.

Any thoughts?

Bernie

I'll investigate with the other pins today and report back.

Many Thanks DrAzzy :slight_smile:

Bernie

I tried it also and it didn't work for pin=10.

But when I checked the datasheet I realized it can't work for that pin. Pin 10 (841 pin 13) isn't one of the 8 pins that can be configured for PWM output.

The configuration registers are confusing, to me at least. So I took the time to map them out. If you look in core_pins.h it's already there, but I figured it was worth confirming it for myself.

This is how they map:

TOCC0	OC0B	pin 9 / PA1 - 841 pin 12	disabled
TOCC1	OC0A	pin 8 / PA2 - 841 pin 11	disabled
TOCC2	OC1B	pin 7 / PA3 - 841 pin 10
TOCC3	OC0A	pin 6 / PA4 - 841 pin 9
TOCC4	OC0B	pin 5 / PA5 - 841 pin 8
TOCC5	OC1A	pin 4 / PA6 - 841 pin 7
TOCC6	OC2B	pin 3 / PA7 - 841 pin 6
TOCC7	OC2A	pin 2 / PB2 - 841 pin 5

edit: As you can see, pins 8 and 9 (841 pins 11 and 12) are disabled. For the timer 0 outputs you need to use pins 5 and 6, which to make things more confusing happen to be 841 pins 8 and 9. Or else reconfigure the 841 if you need those specific pins.

Ah - ha! Cheers for that jboyton :slight_smile: . Just goes to show what happens if you don't read or understand the datasheets! A quick test shows all 6 pins (2 to 7) are performing as hoped.

All I have to do now is to read up on configuration registers and try to make sense of the datasheet so I can reconfigure pins myself if I ever need to again. Currently all that has been carefully explained to me still seems like a foreign language, but I will try to understand!

Thanks again for all the help guys,

Karma all round

Bernie

Errr, ever so sorry guys, but I forgot to ask - if I do want to reassign pwm away from pins 4 and 6 (PA6/SDA and PA4/SCL), because I may (will) want those for I2C purposes only, and allocate them to pins 8 and 9 (PA2 and PA1) to keep 6 pwm pins, I assume I change the relevant lines in core_pins.h but after that - what do I do then?

What else do I have to do such that the pwm pins move to those alternative pins? Do I have to compile anything, and if so how? Apologies for my lack of knowledge in this but I am trying to learn - honest! This is my first steps outside the IDE and its awfully scary here :cold_sweat:

TIA

Bernie