Correct frequency on TCCR2 Atmega8 - timer

I'm new to microcontrollers, so I'm interested is it possible to set correct frequency mode on TCCR2 8bit timer?I need it to control a servo;
On TCCR1 I do smth like this:
DDRB |= (1<<1) | (1<<2);
ICR1 = 20000;
TCCR1A = (1<<WGM11)|(1<<COM1A1) | (1<<COM1B1);
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
OCR1A = 1500;//middle pos
And it works fine, but it seems there is no "ICR2" register and no capture mode on this timer, so I don't understand how can I set frequency to control servo on PB3.Is there any onter ways to control servos?
Thanks!

Input Capture does not set a pin, so it can't be used to control a servo. ICR1 is usually used for input compare, but is also used for output compare on Timer 1 in some PWM modes.
PB3 is controlled by the output compare on Timer 2. You have do set it up similarly to what you have for Timer 1. The OCR2 register may be relevant to your needs.

Related

Stm32f303vc discovery tim3 is not working

I would like to configure tim3 ch1 ch2 as encoder mode, I have the same code on tim2( it's also general purpose timer) and it's working good.
Maybe there's another bits should I set but I cant find them.
I was trying to configure this timer to work without any outputs, just generate interrupt after set period of time but it's not working as well.
//TIM2 CH1 PA0 CH2 PA1 AF1
//TIM3 CH1 PE2 CH2 PE3 AF2
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN ;
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOEEN;
GPIOA->MODER |= GPIO_MODER_MODER0_1 | GPIO_MODER_MODER1_1;
GPIOE->MODER |= GPIO_MODER_MODER2_1 | GPIO_MODER_MODER3_1;
GPIOA->AFR[0] |= 0X00000011;
GPIOE->AFR[0] |= 0X00002200;
TIM2->SMCR = TIM_SMCR_SMS_0;
TIM2->CCMR1 = TIM_CCMR1_CC1S_0|TIM_CCMR1_CC2S_0;
TIM2->ARR = 24;
TIM2->DIER = TIM_DIER_UIE;
TIM2->CR1= TIM_CR1_CEN;
TIM3->SMCR = TIM_SMCR_SMS_0 ;
TIM3->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0;
TIM3->ARR = 24;
TIM3->DIER = TIM_DIER_UIE;
TIM3->CR1= TIM_CR1_CEN ;
enter image description here
Set SMCR to 0
Your code sets both timers to encoder mode 1, see the description of the SMCR register in the reference manual.
0001: Encoder mode 1 - Counter counts up/down on TI1FP1 edge depending on TI2FP2 level.
In this mode, the timer counter is incremented or decremented by the signals on then CH1 and CH2 input, instead of the internal clock. There must be some other component on the board, or line noise when they are unconnected, that managed to trigger TIM2 a few times.
PE2 is connected to an output of another IC
Check the schematics in the board user manual. PE2 is connected to the DRDY output of the onboard accelerometer.
You can use the CubeMX tool to find available pins for TIM3. Select your board in the Board Selector screen, it will show that PE2 and PE3 are already connected to something.
Set TIM3 combined channels to encoder mode, it will assign some free pins to the timer. You can then hold down CTRL and click on the pin to see alternatives (they will blink in blue), and you can drag the pin assignments with the mouse.
Ok, I find a solution :)
If I assign TIM3 CH1 to PB4 and CH2 to PB5 it's work good, but I don't understand why, can someone explain it ?

AVR CTC Timer Frequency Apparent Inaccuracy

I'm a beginner with programming AVR devices, in an attempt to move away from the inefficient _ms_delay() and _us_delay() blocking functions I've been trying program using the built in timers to control the timing of a basic LED flashing program with the CTC timer mode on a 16-bit timer. My goal is to make the LED flash at 2 Hz, on for 0.5s, off for 0.5s.
According to the ATMega328P datasheet, the freqency of a CTC output should be f_CTC = f_Clock/(2N(OCR1A+1), since my chip is a 328P Xplained mini, it's default CPU speed is 16 MHz, using the above formula, with N=64, the required OCR1A value to achieve my desired frequency should be 62499. With all of this in mind I wrote the following code:
#include <avr/io.h>
int main(void)
{
// Setup for timer TC1 (16-bit) in CTC mode to run at 2 Hz
TCCR1A = 0x00;
OCR1A = 62499; // Sets time resolution to 0.5 s
TCCR1B = 0x0b;
TCCR1C = 0x00;
// Set pin directions
PORTD &= ~(1<<PORTD6);
DDRD |= (1<<DDD6);
while (1)
{
if(TIFR1 & (1<<OCF1A))
{
PORTD ^= (1<<PORTD6);
}
TIFR1 |= (1<<OCF1A);
}
}
However, when I run the code the LED flashes at a frequency of 1 Hz, which I was able to time with my phone. Additionally, when I change OCR1A to 31249, which should increase the frequency to 4 Hz it seems to be flashing at 8 Hz, or on-and-off 4 times per second. I feel like I'm misunderstanding something about how CTC mode works, if someone could explain it simply to me, or any other issues with my code, I would be grateful.
I noticed one thing that could cause the issues you are seeing.
You are using the line TIFR1 |= (1<<OCF1A); to clear the OCF1A bit. You are running that line very frequently, so there is a high chance that when OCF1A gets set, your code just clears it immediately before the if statement can see that it was set. You have no control over when that bit gets set; it can happen at any point in your loop.
You should only clear OCF1A after verifying that it is 1, like this:
if (TIFR1 & (1 << OCF1A))
{
PORTD ^= (1 << PORTD6);
TIFR1 |= (1 << OCF1A);
}

Controlling a servo-motor with PWM on MSP430

I am a beginner coder learning on the MSP430FR4133.
I'm using a servo motor as part of my system, which is controlled by PWM.
The motor rotates across 180°, with a 1ms pulse being far right and 2ms pulse being far left in a 20ms period. Unfortunately I'm simply having no success operating it.
I have some very simple code that my intention was to simply force the motor to the right-most position:
WDTCTL = WDTPW | WDTHOLD;
P1DIR |= BIT7; //P1.7 Output
P1SEL0 |= BIT7; //P1.7 Select
TA0CCR0 = 20000-1; //Set Period to 20ms.
TA0CCTL1 = OUTMOD_7; //CCR1 Reset/Set
TA0CCR1 = 1000; //Set Duty Cycle to 1ms
TA0CTL = TASSEL_SMCLK | MC_UP | TACLR; //Use SMCLK in Up Mode
Unfortunately, the code isn't operating as I intended. The motor is supplied by a 5v supply, though the PWM signal from the MPS430 is only 3.3v. Could this also be an issue?
Thanks for any assisstance, and I can expand on anything I have not given enough information on.

Setting high speed PWM on ATtiny85

I am having trouble setting up high speed PWM on my ATtiny85. I need to use the PCK, at a speed of 400 kHz. I believe that I have followed the data sheet correctly, but for some reason, the timer interrupt flags are not working.
If I program the device, the output of the corresponding pin is a constant 5 V.
If I comment out the PCK setup and use the system clock instead, the flags are correctly set and PWM works fine. The code is posted. Why aren't the flags setting and the PWM isn't working?
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
PORTB = 0; //Reset values on port B
// After setting up the timer counter,
// set the direction of the ports to output
DDRB |= (1<<PB1) | (1<<PB0); // Set the direction of PB1 to an output
// PLLCSR - PLL control and status register:
// PLL is a clock multiplier - multiplies system 8 MHz by 8 to 64 MHz
// PLL is enabled when:PLLE bit is enabled,
// CKSEL fuse is programmed to 0001. This clock is
// switched off in sleep modes!
PLLCSR |= (1<<PLLE); // PLL enable
// Wait until the PLOCK bit is enabled
// before allowing the PCK to be enabled
//WaitForPLOCK();
//unsigned int i = 0;
while ((PLLCSR & (1<<PLOCK)) == 0x00)
{
// Do nothing until plock bit is set
}
PLLCSR |= (1<<PCKE); // Enable asynchronous mode, sets PWM clock source
TCCR1 =
(1<<CTC1) | // Enable PWM
(1<<PWM1A) | // Set source to pck
(1<<(CS10)) | // Clear the pin when match with ocr1x
(1<<COM1A1);
GTCCR = (1<<PWM1B) | (1<<COM1B1);
// Set PWM TOP value - counter will count and reset
// after reaching this value
// OCR1C
// 400 kHz 159
// 450 kHz 141
// 500 kHz 127
OCR1C = 159;
// Enable Timer1 OVF interrupt
TIMSK = (1<<OCIE1A) | (1<<TOIE1);
sei();
// This should set the duty cycle to about 75%
OCR1A = 120;
The solution involved the CKDIV8 fuse. To program this fuse correctly however, HVSP "High Voltage Serial Programming" was required. After removing this fuse so that the device operated at 8 MHz, the PWM gave a 400 kHz output. I hope other people find this useful!
The errata (section 27 of the datasheet) states 'PLL will not lock under 6 MHz'. The only workaround listed is to set the clock to 6 MHz or higher.

Setting up multiple timers with AVR

I am trying to set up two timer interrupt routines with Teensy 2.0 Microcontroller (which is based on ATMEGA32U4 8 bit AVR 16 MHz) for independent control of two servo motors
After much trial - I was able to set one up on pin 7 of port C, but
How do I set up the second ISR to be initialized and called independently of the first?
Do I need to setup the second timer and, if so, what would such code look like?
Here is the setup code:
int main(void)
{
DDRE = 0xFF;
TCCR1A |= 1 << WGM12; // Configure timer 1 for CTC mode
TCCR1B = (1<<WGM12) | (1<<CS11) ;
OCR1A = 1000; // initial
TIMSK1 |= 1 << OCIE1A; // Output Compare A Match Interrupt Enable
sei(); // enable interrupts
// ...code that sets pulseWidth based on app logic variable.
// Not showing as its not important
}
ISR(TIMER1_COMPA_vect)
{
if (0 == pulseWidth)
{
return;
}
static uint8_t state = 0;
int dutyTotal = 20*1000;
if (0 == state)
{
PORTC |= 0b10000000;
OCR1A = pulseWidth;
state = 1;
}
else if (1 == state)
{
PORTC &= 0b01111111;
OCR1A = dutyTotal - pulseWidth;
state = 0;
}
}
While it's difficult to give a definitive answer without knowing more about your application (e.g. what kind of servo/motor, - I'm guessing model RC type with 1-2ms pule?) there are two approaches to solving the problem:
Firstly, In your code you seem to be manually generating a PWM signal by toggling PC7. You could add another output by increasing your number of states - you need one more than the number of servos to give the gap which sets the pulse repetition frequency. This is a common technique when you need to drive a lot of servos, since most RC servos don't care about pulse phasing or frequency (within limits), only the pulse width, so you can generate a bunch of different pulses one after the other on different outputs while only using one timer like this (in a sort of pseudo-code state diagram):
State 0:
Turn on output 1
Set timer TOP to pulse duration 1.
Go to state 1:
State 1:
Turn off output 1
Turn on output 2
Set timer TOP to pulse duration 1.
Go to state 2:
State 2:
Turn off output 2
Set timer TOP to pulse duration 3.
Go to state 0:
"Pulse duration 3" sets the PRF (pulse repetition frequency). If you want get fancy,
you can set this to 1/f-pd1-pd2, to give a constant frequency.
[ "TOP" is AVR-speak for the thing that sets the wrap (overflow) rate of the timer. See data sheet. ]
Secondly, there is a much easier way if you're only using two servos - use the hardware PWM functionality of the timer. The AVR timers have a built-in PWM function to do the pin-toggling for you. Timer1 on the mega32 has two PWM output pins, which could work great for your two servos and you then don't (necessarily) need an interrupt handler at all.
This is also the right solution if you are PWM driving motors directly (e.g. through an H-Bridge.)
To do this, you need to put the timer into PWM mode and enable the OC1A and OC1B output pins, e.g.
/*
* Set fast PWM mode on OC1A and OC1B with ICR1 as TOP
* (Mode 14)
*/
TCCR1A = (1 << WGM11) | (1 << COM1B1) | (1 << COM1A1);
TCCR1B = (3 << WGM12);
/*
* Clock source internal, pre-scale by 8
* (i.e. count rate = 2MHz for 16MHz crystal)
*/
TCCR1B |= (1 << CS11);
/*
* Set counter TOP value to set pulse repetition frequency.
* E.g. 50Hz (good for RC servos):
* 2e6/50 = 40000. N.B. This must be less than 65535.
* We count from t down to 0 so subtract 1 for true freq.
*/
ICR1 = 40000-1;
/* Enable OC1A and OC1B PWM output */
DDRB |= (1 << PB5) | (1 << PB6);
/* Uncomment to enable TIMER1_OVF_vect interrupts at 50Hz */
/* TIMSK1 = (1 << TOV1); */
/*
* Set both servos to centre (1.5ms pulse).
* Value for OCR1x is 2000 per ms then subtract one.
*/
OCR1A = 3000-1;
OCR1B = 3000-1;
Disclaimer - this code fragment compiles but I have not checked it on an actual device so you may need to double-check the register values. See the full datasheet at http://www.atmel.com/Images/doc7766.pdf
Also, you perhaps have some typos in your code, bit WGM12 doesn't exist in TCC1A (you've actually set bit 3, which is FOC1A - "force compare", see datasheet.) Also, you are writing DDRE to enable outputs on port E but toggling a pin on port C.
Halzephron, thank you so much for your answer. I dont have the high enough reputation to mark your answer, hopefully someone else will.
Details below:
You are absolutely right about being able to use a single IRS to control a number of servos - embarrassing I did not think of that, but given how well your simpler solution worked - I'll just use that.
... Also, you are writing DDRE to enable outputs on port E but toggling a pin on port C.
Thanks, I commented out that line, and it works the same - (so I dont need to enable output at all?)
Bit WGM12 doesn't exist in TCC1A (you've actually set bit 3, which is FOC1A - "force compare", see datasheet.)
I removed that too, but leaving the rest of my code unchanged - it results in servos moving slower, with way less torque and jittering as they do, even after arriving at desired position. Servo makes a weird "shaky" noise (frequency ~10-20, I'd say) and the arm it trembling, so for the reasons I don't understand - setting this bit seems necessary.
I suspected that a timer per motor is highly inelegant, and so I really like your second approach (built - in timer-generated PWM),
... This is also the right solution if you are PWM driving motors directly (e.g. through an H-Bridge.)
Very curious, why? I.e. what's the difference between using this method vs, say, timer-generated PWM.
In your code, I had to change below line to get 50HZ, otherwise I was getting 25HZ before (verified with a scope)
ICR1 = 20000-1; // was 40000 - 1;
One other thing I noticed with scope was that the timer-generated PWM code I have - produces less "rectangular" shape than the PWM code snippet you attached. It takes about 0.5 milliseconds for the signal to drop off to 0 with my code, and its absolutely instantaneous with yours (which is great). This solved another problem I had been bashing my head against: I could get analog servos to work fine with my code (IRS-generated PWM), but any digital servo I tried - just did not move, as if it was broken. I guess the shape of the signal is critical for digital servos, I never read this anywhere. Or maybe its something else I dont know.
As a side note, another weirdness I spent a bunch of time on - I uncommented the TIMSK1 = (1 << TOV1); line, thinking I always needed it - but what happened, my main function would get frozen, blocked forever upon first call to delay_ms(...) not sure what it is - but keeping it commented out unblocks my main loop (where I read the servo positin values from the USB HID using Teensy's sample code)
Again, many thanks for the help.

Resources