I was studying avr timers (Mazidi) in that book where a program was given in timer chapter it said whenever we need to calculate the value to enter inside TCNT0 ,we should calculate like this. for example 8Mhz, 256 prescalar , 1 s delay
8 Mhz = .125 usec
256 x 0.125 = 32 usec
for 1 ms delay
1sec / 32usec = 31250 clock cycles = 0x7A12
so the value for TCNT0 is
1+FFFF-7A12 = 0x8255 //what this step means
Also when polling we look for TIFRs 0th bit for 1. when it becomes 1 we stop the timer and stop the clock source, but why we do this
TIFR = 0x1 //clears TIFR??
in the book it was written it clears TIFR . How is this possible when that bit is already 1, writing 1 on it makes it clear?
1+FFFF-7A12 = 0x8255 //what this step means
This is not the usual way to use a timer, but it subtracts your number from 0 (which is equivalent to 0xFFFF + 1) so that it "counts down" and trips when the timer reaches 0.
It makes much more sense to us TOC (timer output compare) instead.
TIFR = 0x1 //clears TIFR??
Yes. This register is not a memory location. It is mapped to a memory location. Some registers do work this way.
Related
I am currently working with S32k142 microcontroller.
I would like to configure a 1ms delay using the RTC clock. I have an external RTC clock(32.768KHz) which has been configured to drive the RTC module of the microcontroller.
I have programmed the following:
void wait_1ms_RTC(void)
{
UINT32 tpr = (UINT32)RTC->TPR; // RTC Time Prescaler Register: increments at a freq of 32.768KHz
UINT32 tsr = (UINT32)RTC->TSR; // RTC Time Seconds Register: increments every second
tpr = tpr + (UINT32)32; // 32->1ms(32*30.51us=976.32us)
if (tpr <= 32767)
{
while (((UINT32)RTC->TPR <= tpr)&& ((UINT32)RTC->TSR <= tsr));
}
else
{
while (((UINT32)RTC->TPR <= (tpr - 32768))&& ((UINT32)RTC->TSR <= tsr+1));
}
}
This code simply reads the TPR and TSR register, and waits till the TPR register and TSR register reached certain value that corresponds to 1ms.
This works most of the time except in few occasions where it does not create a delay of 1ms ,I am assuming it is happening during the roll over, but still cannot figure out where exactly is the issue in the code.
Any ideas on how this can be solved?
You have over complicated it; you only need the TPR. By shifting the TPR value left by 1 bit, and assigning it to uint16_t, the natural modulo 216 arithmetic deals with the roll-over for you:
#define RTC_TPR_MILLISEC ((32768<<1)/1000)
void wait_1ms_RTC(void)
{
// RTC Time Prescaler Register: 0 to 2^15,
// shift-left 1 but to make it 2^16 so uint16_t modulo arithmetic works
uint16_t start = RTC->TPR << 1 ;
while( (RTC->TPR << 1) - start < RTC_TPR_MILLISEC )
{
// spin
}
}
It fact it is probably even simpler than that. The user manual shows that TPR is a 16 bit register and that TSR is incremented when TPR:14 transitions from 1 to 0. It does not imply that TPR is a 15 bit value and that the counter is reset to zero after 32767. I am not familiar with the part, but if in fact it is a full 16 bit counter as the documentation suggests then the shifting is unnecessary:
#define RTC_TPR_MILLISEC (32768/1000)
void wait_1ms_RTC(void)
{
// RTC Time Prescaler Register: 0 to 2^16
uint16_t start = RTC->TPR ;
while( RTC->TPR - start < RTC_TPR_MILLISEC )
{
// spin
}
}
If you are not sure why that works, see How to deal with a wrapping counter in embedded C (the example there is a 32 bit counter, but the same applies for 16 bit).
Recently, I started programming the Atmega328P in pure c/c++, without all the arduino libraries and arduino IDE. I want to blink an LED at a rate of 1Hz (1 sec. on, 1 sec. off). Unfortunately, I can only use Timer0, an 8-bit timer. The mcu has a clock frequency of 16MHz and I chose a prescaler of 1024 to reduce to number of overflows as much as possible to reduce jitter, as an interrupt routine always has overhead (this makes more sense if you read the rest of my question). Using simple maths, I came to conclusion that after 1 second, Timer0 has overflowed 61 times and that the TCNT0 register equals 8.
Then, I came up with this solution:
#define F_CPU 16000000ul
#include <avr/io.h>
#include <avr/interrupt.h>
#define bit(b) (1 << (b))
void initBlinkTimer()
{
//Timer0 with CTC Mode
TCCR0A |= bit(WGM01) | bit(WGM00);
//Compare TCNT0 with 8
OCR0B = 8;
//Interrupt at OCR0B compare match aka: execute interrupt when TCNT0 equals 8
TIMSK0 |= bit(OCIE0B);
//Set PB5 as output
DDRB |= bit(PB5);
//Set the prescaler to 1024
TCCR0B |= bit(CS02) | bit(CS00);
//Enable global interrupts, so that the interrupt routine can be executed upon the OCR0B compare match
sei();
}
//Keeps track of the number of overflows
volatile unsigned char nOverflows = 0;
ISR(TIMER0_COMPB_vect)
{
if(nOverflows >= 61)
{
//Toggle PB5
PORTB ^= bit(PB5);
//Reset timer
nOverflows = 0;
TCNT0 = 0;
}
else
{
nOverflows++;
}
}
int main()
{
initBlinkTimer();
while(1){}
}
This code initializes an 8-bit CTC timer with a prescaler of 1024. An interrupt service routine (ISR) is executed when TCNT0 equals OCR0B, which I set to 8 in my code. In the ISR, the nOverflows variable is compared to 61. If nOverflows equals 61, one second has passed and the PB5 pin is to be toggled. It also performs a greater-than check, in case the mcu missed the 61th overflow (if that's somehow possible in this case). The timer and nOverflows variable are cleared after toggling the pin and the timer then starts again from zero.
My question is: Is this a good way to blink an LED at 1Hz, when only an 8-bit timer is available? Can/should a part of this be implemented in the hardware instead of in the software?
You don't need super high precision in your LED blinking; no one will be able to tell with their eyes if it is slightly off.
I'd say you should configure the timer to overflow about one to ten times per millisecond. Let's say it overflows every 251 microseconds (the exact number doesn't matter). Then every time it overflows, you add 251 to a uint16_t variable for counting microseconds. If the microsecond counter is greater than or equal to 1000, you subtract 1000 from it and increment your millisecond counter, which should probably be a uint32_t so you can use it to time long periods of time.
But what if the overflow period is not an exact number of microseconds? That's still fine, because it will probably be expressible in the form "N/M milliseconds", where N and M are whole numbers. So every time the overflow happens, you increment your counter by N. If the counter reaches M, you subtract M from the counter and add 1 to your millisecond counter. (In the preivous paragraph, we only considered the M=1000 case, and I think by starting with that case it is easier to see what I'm talking about.)
You can either use an ISR to update your millisecond counter or do it in your main-line code by frequently checking for an overflow flag. Either way would work.
So now you have a variable that counts up once per millisecond, like the Arduino millis() function, and you can use it for all sorts of millisecond-scale timing, including blinking LEDs.
The least-significant bit (bit 0) of the millisecond counter toggles once per millisecond, so its period is 2 ms. The next bit up from that (bit 1) has a period of 4 ms. Bit 10 has a period of 2048 ms.
So a simple way to blink your LED with a period of 2048 ms would be:
led_state = millisecond_counter >> 10 & 1;
(The code above uses bitwise operations to set led_state to be a copy of bit 10 from the millisecond counter. Assuming you run this code frequently and write led_state out to the LED using the I/O registers, your LED would then have a period of 2048 ms.)
If you really care that your LED is slow by 2.4%, you could do something more complicated like this:
static uint16_t last_toggle = 0;
if ((uint16_t)(millisecond_counter - last_toggle) >= 1000)
{
last_toggle += 1000;
toggle_the_led();
}
I'm having a hard time finding what I suspect is a pretty silly mistake in my code. I'm using an ATmega328.
What I need is to generate a PWM signal whose duty cycle varies not between 0% and 100%, but between two other values. This is taken into account by setting the macros duty_max and duty_min. What I'm doing in my code is reading the ADC, which has a resolution of 1024 values, and mapping the value read to the range of accepted values:
#define duty_max 239
#define duty_min 50
[...]
//Reading the ADC
ADMUX = 0b01000101;
ADCSRA |= (1<<ADSC);
while(!(ADCSRA & (1<<ADIF)));
ADCSRA |= (1<<ADIF);
//Setting the variable 'duty' to the value read by the ADC
cli();
duty = ADC;
sei();
//Mapping to the range of accepted values
duty = round((duty*(duty_max-duty_min))/1023 + duty_min);
//Generating the PWM signal
OCR0B = duty;
//Timer 0
TCCR0A = 0b00100011;
TCCR0B = 0b00000001;
The problem I'm having is that the signal is not working as it should. When sweeping the ADC reading from 0 to 1023 and measuring the output signal with an oscilloscope, I would like the signal to go from the minimum duty cycle stablished to the maximum. However, it goes from 0 to 40% (approximately) FOUR times. Namely, when the value of the ADC increases, at some time the duty cycle stops increasing and returns to 0, and then keeps increasing, until it gets to 0... Four times within the whole ADC range.
If I replace the mapping formula with duty = round(duty/4); it works alright, but the duty cycle falls out of the accepted range (as it goes from 0% to 100%).
Why is this happening? The mistake must be in the mapping formula, but I can't find it and I have already been dealing with it for a while now.
I have been able to almost replicate your symptoms by truncating to 16 bits the result of
(duty*(duty_max-duty_min))/1023
When duty is 347, the output value drops from 114 (which is around 47% of maximum) to 50, which is the minimum duty cycle. This happens three times and a bit over the input range (not four).
To prevent this from happening you might try and, in this instance, divide both numbers by a common divisor: the duty difference, 189, is divisible by 3, and so is 1023. Try writing it as
duty = round((duty*63)/341) + duty_min;
and see whether this changes anything.
I'm trying to generate note for example Do , do's frequency is 523.
I wrote some codes but, i did not work
Systick 8 mhz
void note1(void){ // Note Do
for (int i = 0; i < 523; i++){
GPIOE->ODR = 0x4000;
delay_ms(1);
GPIOE->ODR = 0x0000;
delay_ms(1);
}
}
How can we solve this problem ?
EasyMx Pro v7
I'm calling the function like that
void button_handler(void)
{
note1();
// Clear pending bit depending on which one is pending
if (EXTI->PR & (1 << 0)){
EXTI->PR = (1 << 0);
}
else if (EXTI->PR & (1 << 1)){
EXTI->PR = (1 << 1);
}
}
523 times sending 1 and 0 and delay_ms 1 = 1 ms
1000 = 1 sec
On STM32 (as I can see you have it) you have timers which can be configured as PWM output.
So use timer, set period and prescaler values according to your needed frequency and set duty cycle on channel to 50%.
If you need 523Hz PWM output, then set your timer PWM to 523Hz using prescaler and period value:
timer_overflow_frequency = timer_input_clock /
(prescaler_value + 1) /
(period_value + 1) ;
Then, for your output channel set value half of timer period value.
For standard peripheral library, tutorial can be used from here:
https://stm32f4-discovery.net/2014/05/stm32f4-stm32f429-discovery-pwm-tutorial/
Link from unwind for Cube https://electronics.stackexchange.com/questions/179546/getting-pwm-to-work-on-stm32f4-using-sts-hal-libraries
You appear to have a fundamental misunderstanding. In your code note1(), the value 523 will affect only the duration of the note, nit its frequency. With 1ms high, 1ms low repeated 523 times you will generate a tone of approximately 500Hz for approximately 1.43 seconds. I say "approximately" because there will be some small overhead in the loop other then the time delays.
A time delay resolution 1ms is insufficient to generate an accurate tone in that manner. To do it in the manner you have, each delay would need to be 1/2f seconds, so for 523Hz approximately 956ms. The loop iteration count would need to be ft, so for say .25 seconds, 131 iterations.
However if button_handler() is as it appears to be an interrupt handler, you really should not be spending 1.46 seconds in an interrupt handler!
In any event this is an extraordinarily laborious, CPU intensive and inaccurate method of generating a specific frequency. The STM32 on your board is well endowed with hardware timers with direct GPIO output that will generate the frequency you need accurately with zero software over head. Even if none of the timers map to a suitable GPIO output that you need to use, ou can still get one to generate an interrupt at 1/2f and toggle the pin in the interrupt handler. Either way that will leave the processor free to do useful stuff while the tone is being output.
I have been for some time on how to control a motor (control its speed) with fast pwm mode with my atmega32. I need to use the 8-bit Timer0, because i have other uses for the other counters. I think I know how to inialise the timer for this task:
void initial_io (void){
DDRC = 0xFF;
DDRB = 0xFF;
PORTA = (1<<PA4)|(1<<PA5);
TCCR0 = (1<<WGM01)|(1<<WGM00); // PWM mode : Fast PWM.
TCCR0 = (1<<CS02)|(1<<CS00); // PWM clock = CPU_Clock/1024
}
But then comes the problem. I simply don't know what to do next, what to do on my main.
My exact project is to drive a remote controlled car with acceleration. So when I ask from the car to go forward it must accelerate from stop to maximum speed whith fixed acceleration. I don't know any Assembly, so if you can help me please do it in C. Any help will be much appreciated.
Well, I guess you're okay with all port B and C pins being outputs. Also, you shouldn't need to do anything in assembly on AVR. The assembly-only stuff is available as macros in avr-libc.
Setup
First off, you're setting up TCCR0 wrong. You have to set all the bits at once, or you have to use a read-modify-write operation (usually TCCR0 |= _BV(bit_num); to set a bit or TCCR0 &= ~_BV(bit_num); to clear it). (_BV(N) is an avr-libc macro that's more legible than the (1<<N) stuff you're using, but does the same thing.) Also, you're missing the polarity of your PWM output, set by the COM00 and COM01 bits. Right now you have them (implicitly) disabled PWM output (OC0 disconnected).
So I'm going to assume you want a positive-going PWM, i.e. larger PWM input values result in larger high-output duty cycles. This means COM01 needs to be set and COM00 needs to be cleared. (See pp. 80-81 of the ATmega32(L) data sheet.) This results in the setup line:
TCCR0 = _BV(WGM01) | _BV(WGM00) // PWM mode: Fast PWM.
| _BV(COM01) // PWM polarity: active high
| _BV(CS02) | _BV(CS00); // PWM clock: CPU_Clock / 1024
Duty Cycle
Now we get to the actual duty cycle generation. Timer 0 is pretty stupid, and hard wires its BOTTOM to 0 and TOP to 0xFF. This means that each PWM period is PWM_Clock / 256, and since you set PWM_Clock to CPU_Clock / 1024, the period is CPU_Clock / 262144, which is about 33 ms for an 8 MHz CPU clock. So each PWM clock, this counter counts up from 0 to 255, then loops back to 0 and repeats.
The actual PWM is generated by the OC circuit per Table 40. For the COM0* setting we have, it says:
Clear OC0 on compare match, set OC0 at BOTTOM
What this means is that each time the counter counts up, it compares the count value to the OCR0 register, and if they match it drives the OC0 output pin to GND. When the counter wraps around to 0, it drives the pin to VCC.
So to set the duty cycle, you just write a value corresponding to that duty cycle into OCR0:
OCR0 = 0; // 0% duty cycle: always GND.
OCR0 = 64; // 25% duty cycle
OCR0 = 128; // 50% duty cycle
OCR0 = 172; // 67% duty cycle
OCR0 = 255; // 100% duty cycle; always VCC. See below.
That last case is there to resolve a common problem with PWM: the number of possible duty cycle settings is always one more than the number of count steps. In this case, there are 256 steps, and if the output could be VCC for 0, 1, 2, … 256 of those steps, that gives 257 options. So rather than prevent either the 0% or 100% case, they make the one-shy-of-100% case disappear. Note 1 on Table 40 says:
A special case occurs when OCR0 equals TOP and COM01 is set. In this case, the compare match is ignored, but the set or clear is done at BOTTOM.
One more thing: if you write to OCR0 in the middle of a PWM cycle, it just waits until the next cycle.
Simulating Acceleration
Now to get the "constant acceleration" you want, you need to have some kind of standard time base. The TOV0 (timer 0 overflow) interrupt might work, or you could use another of the timers or some kind of external reference. You'll use this standard time base to know when to update OCR0.
Constant acceleration just means that the speed changes linearly with time. Taking this a step further, it means that for each update event, you need to change the speed by a constant amount. This is probably nothing more than saturation arithmetic:
#define kAccelStep 4
void accelerate_step() {
uint8_t x = OCR0;
if(x < (255 - kAccelStep))
OCR0 = x + kAccelStep;
else
OCR0 = 255;
}
Just do something like this for each time step and you'll get constant acceleration. A similar algorithm can be used for deceleration, and you could even use fancier algorithms to simulate nonlinear functions or to compensate for the fact that the motor does not instantly go to the PWM-specified speed.
As you seem to be a beginner on AVR programming, I suggest you go the easy way: start with Arduino.
The Arduino environment offers simple functions so you don't need to manipulate the processor registers directly. For instance, to control a PWM output, you simply have to call analogWrite() (documentation here)
Here is a tutorial to hook up a motor to an Arduino.
Here is a tutorial to program a ATMega32 from Arduino IDE