clock problems with 7-segment display in proteus - c

here is a simple 7-segment display with a pushbutton the problem is whenever I make the clock 1 MHZ the display doesn't run as expected but when I use 8 MHZ clock it works fine.
here is the code:
#define F_CPU 1000000L
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
DDRD &= ~(1<<PD4);
DDRC |= (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3);
PORTC = 0;
while (1)
{
if(PIND & (1<<PD4)){
_delay_ms(25);
if(PIND & (1<<PD4)){
PORTC++;
}
}
}
}

F_CPU Should be the same as the hardware fuses configuration in proteus you could change them by double-click on atmega 16 and change CKSEL Fuses as following
some info maybe help
_delay_ms() It only west some CPU cycles depend on the required time by using F_CPU in the calculation
You need to increase this delay to 300ms to make sure that program does not process the same click more than one and if you hold the key down it will increase in visual manner
analysis of the wrong behavior
25ms is a very short time ... a normal human click will take around 200-300ms so in every click the microcontroller will consider it more than one
when I use 8 MHZ clock it works fine
when you change F_CPU to 8MHZ the _delay_ms() it make the calculation on this speed and will west more cycles ... while the actual speed is 1MHZ
this differance in speed (between F_CPU and the actual speed) led to make 8 times slower delay ='25ms' *8 ='200 ms'
simple solution increase the _delay_ms(25) to _delay_ms(200) to make the same effect
update (info about how delay work)
_delay_ms Is just LOOP to waste CPU cycles and it blocks the CPU from work
the frequency of the microcontroller is determined by the hardware fuses so you need to tell the software which frequency you use throw define F_CPU so the software will know each cycle will take time = 1/F_cpu
when you need a delay, the software already know the amount of time taken by each clock so it will calculate the number of cycle to achieve the required delay time(if you need delay 1ms delay and each clock tack 1 us then you need to wait for 1000 cycles to achieve these delay)
in Assembly there is instruction called nop take only 1 cycle to execute and do nothing
the following code is not correct but it makes something similar when the compiler translate _delay_ms() in Assembly
for(int i=0;i<50;i++)nop;
this code will make 50 nop and wast 50 cycles(actually more than 50 because access and increment variable 'i' will consume some cycles but neglect it to show the idea)
read more
Do AVR delay functions use timers?
how to make delay in AVR Assembly

Related

CubeMX timer configuration question (screenshot attached)

I am trying to understand how timer on the internal clock works.
I've attached my CubeMX config below.
For now, I have set the main clock to 480 MHz which is the maximum for this STM32H743ZI chip.
I am using TIM 2 so I am looking at APB1.
there from the clock tree I see that it is currently so to 240 MHz for Timer Clocks, and 120 MHz for Peripheral Clocks.
My first question is that why is it using the 120MHz where it clearly says "240 MHz" for "timer clocks on APB1"? I have verified the frequency with an oscilloscope.
It is a long shot but according to what I read is that the maximum timer clock for this chip is 200 MHz. So 240 being greater than 200, perhaps the chip is automatically applying a /2 divider? I would think the clock configuration tree would say something, instead of allowing the "240 MHz" to be applied?
My second question:
For the sake argument, let's say that the maximum timer clock really is 200 MHz, how do I go about setting 200 MHz as clock frequency for APB1? I am sure there is no way to achieve 200 MHz without compromising on the max MCU clock and bring it down from 480 to 400 MHz perhaps?
Can I trust the automatic prescaler/multiplier adjustments that CubeMX is doing whenever I change something?
How did you checked it with the scope? It is inside the chip?
The timer clock is 240MHz, other peripheral clocks connected to the APB1 are 120MHz.
according to what I read is that the maximum timer clock for this chip
is 200 MHz.
Where did you read that? official documentation says something different
I think this question does not make too much sense
You see the values, you can check them manually if you wish, but in this case computers are usually are better than humans. Personally I did not have any problems with Cube. BTW I use it only for the clocks (I am too lazy to calculate all the prescallers by hand), but I program it bare register way.

Generate a fixed number of pulses on the STM32F4 PWM

I am trying to control a servo motor (link). It is a brushless DC motor with an interface similar to a stepper motor.
The motor rotates for a defined distance based on the number of pulses it receives from the PWM. The speed is determined by the pulse frequency of the PWM, like a stepper motor.
To control this motor I am using a microcontroller STM32F407ZET6. I can easily change the frequency and Duty Cycle of PWM, but my doubt is the following:
How do I generate a fixed number of pulses in the PWM? For example, I want the PWM to send 1000 pulses at a certain time with a frequency of 20KHz and a Duty Cycle of 50%. 20KHz and 50% Duty Cycle are easy to define, but I can't determine how to generate the 1000 fixed pulses.
One of the solutions I tried was to connect the PWM back to a timer in counter mode and stop the PWM when the required number of pulses has been generated. But the number of pulses is not always fixed, sometimes ranging from 998 to 1005 (for example).
Is it possible to do this without the need for feedback?
Simpest way:
UG interrupt = count cycles. After n cycles disable the timer.
In the memory create a buffer with the timer register values and use timer burst mode.
Configure DMA mem-mem with n cycles same source and destination address. After n cycles end of transaction interrupt will be generated - disable the timer.
Use slave timer counting when the PWM is updating (overflowing). Set the overflow interrupt and disable the PWM timer.
many other methods.
This can be easily achieved by combining the so called "One-pulse mode" (reference manual page 551) with the repetition counter (page 529). All you've got to do is enabling this mode (OPM bit in CR1), set the repetition counter (RCR) and start the timer. IIRC you also have to force an update event in order to get RCR loaded. The reference manual will have more information on that.

How to set frequency and duty cycle of Timer1 in 16bit P&F correct PWM

I am using a 328P (Running on the internal 8mhz) to generate a Square wave at around 111K hz or 120K hz with and adjustable duty cycle.
I'm fairly new to doing this level of hardware manipulation so please excuse my ignorance, I spent 3 days looking online and in the datasheet but I'm afraid my understanding of what the acronyms and abbreviations mean is still too limited.
So far I have come up with the following code after doing the research online and in the datasheet. But I feel like I'm missing something, What register manipulates frequency and what register manipulates duty cycle in (Datasheet 20.12.5) Phase and Frequency Correct PWM Mode?
void setup(){
DDRB |= (1 << DDB1); //Set PB1 as output
OCR1A = (Unsure of what TOP should be here);
TCCR1A = (1 << WGM10) | (1 << COM1B0) | (1 << COM1A0);
TCCR1B = (1 << CS10) | (1 << WGM13);
}
void loop(){
//manipulate duty cycle with other code here
}
What am I missing or what should I be doing differently here?
I tried to use the online AVR Timer Calc to help me get clock ticks needed for that frequency. It says a total of 72 Timer ticks with no prescaler and 16 bit timer would yield a 111Khz (approximate) Square wave. Jumping to 73 or 71 jumps the frequency too much out of the desired range. is there any way to get that closer on an AVR?
After a lot of research along side a friend of mine who is also an EE and works with embedded systems we came to find the best solution for getting what I needed out of the 328p. I will post the solution below for anyone who is interested and needs something similar.
void setup() {
// put your setup code here, to run once:
//Set Timer1 for around 109Khz signal
cli();//stop interrupts
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
//Set register bits
TCCR1A = _BV(COM1A1) | _BV(WGM11);
TCCR1B = _BV(CS10) | _BV(WGM12) | _BV(WGM13);
ICR1 = 73; // frequency = 8000000/73 = 109.589 kHz
OCR1A = 0; //0% Duty Cycle or Full Off.
sei();//allow interrupts
}
void loop() {
// put your main code here, to run repeatedly:
OCR1A = 36; //50% Duty Cycle 73/2 = 36.5 Can be changed as needed.
}
This code sets the registers for Timer 1 so it shouldn't interfere with millis or other timing functions in the Arduino libraries. I needed to manipulate a specific pin anyways and PB1 (OC1A) (or Arduino digital pin 9) is the pin that this will oscillate.
You can change ICR1 to any value you need based on some simple math,
Your clock frequency divided by the value of the counter equals the approximate frequency produced. OCR1A sets the duty cycle of the signal.
You are limited in the exact frequency but for my needs this worked out OK.
I was still able to use it to drive the transducer I was using.
This was a quick answer to the initial problem and allows me to change the duty cycle as a bonus. I don't remember the exact information on the registers we set, When I have time I will update this answer with the info from the data sheet pertaining to that.
In the title, you asked "ATMega328P How to set TIMER1 PWM Frequency". You tune the frequency by setting the TOP value to what you want it to be. A smaller TOP value means the counter reaches TOP sooner, so the frequency is higher. The prescaler and clock source you use for the timer determines how fast it counts up, so that also affects the frequency, what ranges of frequencies are possible, and the resolution you get for setting the frequency. Your TOP value also determines how much resolution you have when setting the duty cycle, since the duty cycle should be an integer less than or equal to TOP.
Near the bottom of your post, you asked "is there any way to get that closer on an AVR?" Since your AVR is running at 8 MHz, every frequency you can generate with its timers will be of the form (8 MHz)/N, where N is some integer. That's because the timers can't do anything or change anything between ticks of the clock source you are supplying to them. Timer 1 will get a clock tick 8 times per microsecond, and each time that clock tick happens it can advance its count and/or control a PWM pin and/or fire an interrupt. I think you already figured this out using the online AVR timer calculator. Here are some of the achievable PWM frequencies you can get on an AVR running at 8 MHz:
8000 kHz / 73 = 109.6 kHz
8000 kHz / 72 = 111.1 kHz
8000 kHz / 71 = 112.7 kHz
If you need more precise frequency tuning, you need to get a faster clock source in your system one way or another. You could get a faster microcontroller or maybe figure out how to supply a faster clock as an input to a timer on the microcontroller.

STM32 - How to trigger interrupt after a certain PWM ON time?

I'm new to ARM MCUs (STM32F411), and I have been trying to find my way around the peripherals using STM's HAL library and STM32Cube.
I've already configured my board in order to use some peripherals:
Timer 2 for running an interrupt with a certain frequency
Timer 3 for running PWMs on 3 channels of it.
ADC with 4 channels, into DMA mode, for reading some analog input.
Let us suppose, now, that the PWM's whole period is 100 ms and its duty cycle is 50% (50 ms PWM on and 50 ms PWM off).
I would like to trigger an interrupt after a certain time of the PWM on level, let us say 50% of it.
Hence, I would like to run an interrupt at 25 ms in order to use the ADC for sampling it's analog inputs.
Do you have any suggestion on how could I implement such a kind of interrupt?
Thank you in advance for your help!
Since the ADC of the STM32F411 is used in Regular mode (not Injected mode) and only three channels out of four are used to generate PWM on Timer 3, the fourth channel can be used to trigger the ADC.
Hence Timer 3 is configured as follows:
CH1 used for Output Compare mode 0 (TIM3->CCMR1.OC1M = 0)
CH2, CH3, CH4 used for PWM outputs
Therefore TIM3->CCR1 is loaded to a value that gives 25% of duty, then it will generate TIM3_CH1 events that can be used to trigger ADC start-of-conversion at 25% of your TIM3 timebase.

Beginner - avr32 turn on led, compiler does not see variables

I have microprocessor at32uc3b0256 and I want turn on leds, (simple program from examples). To do this I use Atmel Studio. I found sample code:
#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz clock speed
#endif
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
DDRC = 0xFF; //Makes PORTC as Output
while(1) //infinite loop
{
PORTC = 0xFF; //Turns ON All LEDs
_delay_ms(1000); //1 second delay
PORTC= 0x00; //Turns OFF All LEDs
_delay_ms(1000); //1 second delay
}
}
But when i wrote it to Atmel Studio i got some errors, Atmel Studio dont see DDRC and PORTs as variable. How can I fix it?
Screen form Atmel Studio
You are using GPIO example for AVR8 architecture. AVR32 architecture is completely different introducing GPIO module as separate HW block connected through PBA (I think). There are no registers like DDRC,...
You can look at AVR32 architecture as on network of subcomponents where MCU core is only one of the modules. There are 2 main buses PBA and PBB each connected to different modules.
To make AVR32 firmware work you need do this:
configure and start main MCU core clock you want to use
AVR32 MCU core is usually running at low 32KHz clock after reset. To achieve better performance you need higher clock up to 66MHz. I usually start PLL at some common frequency and divide all clocks (CPU,PBA,PBB,HSB) from it later. As a source for the PLL you need some clock for example internal RC or oscillator driven by external crystal. If you want also USB then you need to take in mind it needs specific frequency so compromise ... For more info check SCIF module in datasheet and or in examples.
switch to it when started properly
Either wait a bit (100ms) or check if clock is running directly (SCIF module has some capabilities for it I think).
configure/start used HW modules
now do your stuff
Bootlaoder
Another thing you need to take care of is the boot loader. I do not like JTAG as I have a bad experience with it (does not take much to fry it and the programing with it is really uncomfortable). With JTAG you can easily wipe out bootloader (each chip is shipped with it) and trust me getting it back to work is really nasty.
Bootloader on the other hand is simple and elegant. For example I use FLIP and has simple comandline file for programing chip. Then I just open command prompt execute it. And on each rebuild/programming I just hit up arrow to repeat last command in the prompt and hit enter. In comparison to many clicks with JTAG is this much faster and simpler. Here example of the cmd:
avr32-objcopy -O ihex AT32UC3L064.elf AT32UC3L064.hex
Batchisp -device AT32UC3L064 -hardware RS232 -port COM1 -baudrate 115200 -operation onfail abort memory flash erase f blankcheck loadbuffer AT32UC3L064.hex program start reset 0
The avr32-objcopy.exe is in the AVR studio bin directory.
With Bootloader you need to tell the compiler your program is not starting at 0x0000 because that would be overlapping with bootloader. To do that see the trampoline examples.
This is how my AVR32 app usually looks like:
#include <avr32/io.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "intc.c"
#include "gpio.c"
#include "pm_uc3l.c"
#include "scif_uc3l.c"
#include "adcifb.c"
#include "flashcdw.c"
#include "pdca.c"
//#include "pwma.c"
#include "tc.c"
#include "usart.c"
#include "eic.c"
#include "genclk.h"
#include "osc.c"
#include "dfll.c"
#include "sysclk.c"
#include "status_codes.h"
#include "cycle_counter.h"
#include "sleep.h"
#include "delay.c"
#define cpu_clk 30000000
#define _LED AVR32_PIN_PA04
void system_init()
{
delay_init(115000);
Disable_global_interrupt();
INTC_init_interrupts();
scif_start_rc120M();
delay_ms(100);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_CPU,PM_CKSEL_DIVRATIO_4);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_PBA,PM_CKSEL_DIVRATIO_4);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_PBB,PM_CKSEL_DIVRATIO_4);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_HSB,PM_CKSEL_DIVRATIO_4);
pm_set_all_cksel(SCIF_RC120M_FREQ_HZ,cpu_clk,cpu_clk,cpu_clk);
flashcdw_set_flash_waitstate_and_readmode(cpu_clk);
pm_set_mclk_source(PM_CLK_SRC_RC120M);
delay_init(cpu_clk);
}
//------------------------------------------------------------------------------------------------
void wait_ms(U32 dt)
{
U32 t0,t1;
t0=Get_system_register(AVR32_COUNT);
dt=((dt*cpu_clk)+999)/1000;
t0&=RDTSC_mask;
for (;;)
{
t1=Get_system_register(AVR32_COUNT);
t1&=RDTSC_mask;
if (t0>t1) t1+=RDTSC_mask+1;
if ((t1-t0)>=dt) break;
}
}
//------------------------------------------------------------------------------------------------
void wait_us(U32 dt)
{
U32 t0,t1;
t0=Get_system_register(AVR32_COUNT);
dt=((dt*cpu_clk)+999999)/1000000;
t0&=RDTSC_mask;
for (;;)
{
t1=Get_system_register(AVR32_COUNT);
t1&=RDTSC_mask;
if (t0>t1) t1+=RDTSC_mask+1;
if ((t1-t0)>=dt) break;
}
}
//------------------------------------------------------------------------------------------------
int main(void)
{
system_init();
// here init what you need
gpio_configure_pin(_LED,GPIO_DIR_OUTPUT|GPIO_INIT_HIGH);
for (;;)
{
// here do your stuff
gpio_tgl_gpio_pin(_LED);
wait_ms(200);
}
//------------------------------------------------------------------------------------------------
I do not use framework manager instead I include the stuff myself... and my framework is rewritten to avoid unnecessary includes and slowdowns of compilation. Also beware that framework updates are not always compatible so sometimes after update your code will not compile ... It is better to have one solid framework and not update it unless you really need to.
Select only the modules you need to (no need to include them all). For example you need intc,gpio,scif etc my includes are from bigger project so many of them are useless for you and also not all headers/modules are available for all of the AVR32 chips.
I got a bit off topic (I think was necessary) so back to GPIO
The API and architecture is completely changed. Do not be fooled by the pin names. For example pin PA35 does not mean port A pin 35 !!! There is no port PA It is just naming convention without any real meaning to the architecture which is a bit silly and took me a while to got along with it. There are as many ports as needed to cover all the pins. Each port support 32 pins and the pin number is the real thing you need to know.
Each pin is defined somewhere in avr32/io.h as a define like AVR32_PIN_PA04 and it contains numerical value of the pin position in chips GPIO. To obtain gpio port/mask you just do this:
port = pin>>5
mask = 1<<(pin&31)
Now to access GPIO registers directly I recommend to look at gpio.c. You can set,res,test,read 32 pins at a time to speed up (if they are at the same port). The speed is dependent mainly on the buss clock (usually PBA for GPIO) so if your clock for it is low do not expect high toggle rate. beware GPIO access is slow and if not used wisely can kill the performance of your code...
If HW pins selected for your App are done wisely you can have really fast speeds. For example I got toggle speeds around 2-5 MHz !!!
Here example of setting a pin from gpio.c
void gpio_set_gpio_pin(uint32_t pin)
{
U32 bit= 1 << (pin & 0x1F);
volatile avr32_gpio_port_t *gpio_port = &GPIO.port[pin >> 5];
gpio_port->ovrs = bit; // Value to be driven on the I/O line: 1.
gpio_port->oders = bit; // The GPIO output driver is enabled for that pin.
gpio_port->gpers = bit; // The GPIO module controls that pin.
}
You can use this to set multiple pins at the same port simply by exchanging bit with the mask of all pins you want to set ...
If you are using Interrupts for GPIO beware that the interrupt controller INTC is also a separate module connected by buss and wrongly set clock or wait states can cause huge problems.

Resources