Closed brianthornock closed 4 years ago
Sigh...
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
// Assign pins of ATTiny841, make sure it runs at 8 MHz internal oscillator
//DigitalPin Assignments
const unsigned int pwm1 = 6;
const unsigned int pwm2 = 5;
const unsigned int pwm3 = 7;
const unsigned int pwm4 = 8;
void setup() {
//Define what each pin is
pinMode(pwm1, OUTPUT);
pinMode(pwm2, OUTPUT);
pinMode(pwm3, OUTPUT);
pinMode(pwm4, OUTPUT);
//Set up the timer outputs to the correct pins. Don't touch timer 0 so that millis() works correctly
//Pin 8 -> PWM2 -> TOCC4 (make timer OC2B)
//Pin 9 -> PWM1 -> TOCC3 (make timer OC2A)
//Pin 10 -> PWM3 -> TOCC2 (make timer OC1B)
//Pin 11 -> PWM4 -> TOCC1 (make timer OC1A)
TOCPMSA0 = (1<<TOCC1S0) | (1<<TOCC2S0) | (1<<TOCC3S1); //This sets TOCC1 throught TOCC3
TOCPMSA1 = (1<<TOCC4S1); //This sets TOCC4 to be OC2B
TOCPMCOE = (1<<TOCC1OE) | (1<<TOCC2OE) | (1<<TOCC3OE) | (1<<TOCC4OE); //Enable the time/output compare on TOCC1-4
//Disable interrupts on timers
TIMSK1 = 0;
TIMSK2 = 0;
//Set up 16 bit timers so that we can use PWM
//PWM is 10-bit fast, 0x03FF TOP, no prescaler
//Set to Fast, 10-bit PWM, max value of 1024
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11) | (1<<WGM10); //TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10) | _BV(WGM11);
TCCR1B = (1<<WGM12) | (1<<CS10); //No prescaler, | _BV(WGM12)
TCCR1C = 0b00000000; //Set to zero when in PWM mode
TCCR2A = (1<<COM2A1) | (1<<COM2B1) | (1<<WGM21) | (1<<WGM20); //TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20) | _BV(WGM21); //Set to Fast, 10-bit PWM, max value of 1024
TCCR2B = (1<<WGM22) | (1<<CS20); //No prescaler, | _BV(WGM22)
TCCR2C = 0b00000000; //Set to zero when in PWM mode
uint16_t dutyCycle1 = 200;
uint16_t dutyCycle2 = 400;
uint16_t dutyCycle3 = 600;
uint16_t dutyCycle4 = 800;
writeDutyCycle(3,dutyCycle1); //PWM1 is on TOCC3
writeDutyCycle(4,dutyCycle2); //PWM2 is on TOCC4
writeDutyCycle(2,dutyCycle3); //PWM3 is on TOCC2
writeDutyCycle(1,dutyCycle4); //PWM4 is on TOCC1
}
void loop() {
}
void writeDutyCycle(uint8_t tocc, uint16_t duty) {
// Set duty cycle based on the TOCC pin being specified
if(tocc == 1) {
OCR1A = duty;
}
else if (tocc == 2) {
OCR1B = duty;
}
else if (tocc == 3) {
OCR2A = duty;
}
else if (tocc == 4) {
OCR2B = duty;
}
TOCPMCOE |= 1<<tocc;
}
https://forum.arduino.cc/index.php?topic=697361.0
Failure to post code and links to related discussion in the github issue, thus ensuring that nobody but me has the background to help.
Sorry! When I created the issue, I thought I attached the file. Evidently I did not. Here is my greatly simplified code that I used for trying this out:
// Assign pins of ATTiny841, make sure it runs at 8 MHz internal oscillator
//DigitalPin Assignments const unsigned int pwm1 = 6; const unsigned int pwm2 = 5; const unsigned int pwm3 = 7; const unsigned int pwm4 = 8;
void setup() { //Define what each pin is pinMode(pwm1, OUTPUT); pinMode(pwm2, OUTPUT); pinMode(pwm3, OUTPUT); pinMode(pwm4, OUTPUT); pinMode(4,OUTPUT); pinMode(3,OUTPUT); pinMode(2,OUTPUT);
//Set up the timer outputs to the correct pins. Don't touch timer 0 so that millis() works correctly //Pin 8 -> PWM2 -> TOCC4 (make timer OC2B) //Pin 9 -> PWM1 -> TOCC3 (make timer OC2A) //Pin 10 -> PWM3 -> TOCC2 (make timer OC1B) //Pin 11 -> PWM4 -> TOCC1 (make timer OC1A) //TOCPMSA0 = (1<<TOCC1S0) | (1<<TOCC2S0); //This sets TOCC1 throught TOCC3 TOCPMSA1 = (1<<TOCC4S1) | (1<<TOCC5S1) | (1<<TOCC6S0) | (1<<TOCC7S0); //This sets TOCC4 to be OC2B TOCPMCOE = (1<<TOCC6OE) | (1<<TOCC7OE) | (1<<TOCC5OE) | (1<<TOCC4OE); //Enable the time/output compare on TOCC1-4
//Disable interrupts on timers TIMSK1 = 0; TIMSK2 = 0;
//Set up 16 bit timers so that we can use PWM //PWM is 10-bit fast, 0x03FF TOP, no prescaler //Set to Fast, 10-bit PWM, max value of 1024 TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11) | (1<<WGM10); //TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10) | _BV(WGM11); TCCR1B = (1<<WGM12) | (1<<CS10); //No prescaler, | _BV(WGM12) TCCR1C = 0b00000000; //Set to zero when in PWM mode
TCCR2A = (1<<COM2A1) | (1<<COM2B1) | (1<<WGM21) | (1<<WGM20); //TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20) | _BV(WGM21); //Set to Fast, 10-bit PWM, max value of 1024 TCCR2B = (1<<WGM22) | (1<<CS20); //No prescaler, | _BV(WGM22) TCCR2C = 0b00000000; //Set to zero when in PWM mode
OCR1A = 800; OCR1B = 600; OCR2A = 400; OCR2B = 200;
}
Using the code you posted on forums I cannot reproduce your problem. I don't suppose you had the wrong pinout mapping selected? And TOCC1 is on the serial RX line- you didn't have a serial adapter plugged in by any chance did you? Depending on it's design, it's TX line might have been forceful enough to keep the tiny from driving the pin low (which would be potentialyl damaging to the tiny, as it would involve excessive current - most adapters have a 1K resistor in series with their TX pin, so if it finds itself fighting a low impedance pin trying to drive the line the other direction, they don't damage eachother, though...)
Code you posted on github is a mess, presumably from frantically changing things in hope of finding clues - but once I changed the TOCC* register writes to do what your comments and posts said you were trying to do, (and what you do in code posted on forum), that did not reproduce any bad behavior either.
Thank you so much for looking into this. I just got in some new chips that I will try with, as it seems the problem is clearly on my end. Thanks again!
I have created a simple program for creating four PWM outputs using timers 1 and 2. Any PWM output assignments made to TOCC0-3 result in constant HIGH state on the pins. Assigning them to TOCC4-7 works exactly as expected on the same chip.