I am trying to configure the Systick Timer to generate a 1ms interrupt. My MCU is STM32F767 and my clock frequencies are as shown below
Oscillator = HSE
No PLL
SYSCLK = 25 MHz
AHB Prescaler = 2
HCLK = 12.5 MHz
APB1 Prescaler = 2
PCLK1 = 6.25 MHz
APB2 Prescaler = 2
PCLK2 = 6.25 MHz
I have configured the clock properly and have verified the frequencies as being correct.
Now the next part is that I want to configure SysTick timer to generate an interrupt every 1 ms. As I understand the HAL_Delay() method requires the systick timer to be set for interrupt of 1 ms.
Now since my HCLK is 12.5 MHz so each cycle lasts 0.08 us. To get an interrupt every 1 ms I have to configure the SysTick reload value to be 12500. I am doing exactly that.
HAL_SYSTICK_Config(12500);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
Hoever Now when i call the following code,
while(1){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_Delay(1000);
counter++;
}
the pin toggles at rate of around 3 seconds instead of 1. What am i doing wrong here?
So, I figured out the solution, I though my HSE was 25 MHz which was not the case, After reading the data sheet of the MCU(dont rely on CubeMX for this value as the default HSE on CubeMX was displayed as 25 MHz which is not the case in case of nucleo-stm32f767zi board.), I found out that HSE is sourced from ST-Link circuitry and frequency of that signal is 8 Mhz and not 25 MHz as i originally thought. That is why my Led was toggling approximately three times slower.
Related
Recently bought a new USB oscilloscope and tried to measure the frequency of avr timer0. There is 12 MHz crystal oscillator connected to atmega and timer0 set up to fast PWM mode without prescaler. Here is the code:
#include <avr/io.h>
int main(void)
{
DDRB = 0x08;
TCCR0 |= (1<<WGM00)|(1<<WGM01)|(1<<COM01)|(1<<CS00);
OCR0 = 128;
while(1){
}
}
But on oscilloscope frequency equals 46.90 kHz.
Fuse bits are on the next image:
But if I blink a LED with a delay of 1 ms, I got frequency around 2 MHz.
So, please explain to me, what's going on, and why timer works wrong (or where I'm wrong).
The frequency seems correct to me. If your clock is 12MHz and you have an 8 bit PWM your PWM frequency is actually 12MHz/256 = 46.875kHz.
I'm trying to configure the baudrate of USART1 on an STM32L152. When using the external Clock the baudrate is half of what I configured (e.g. 57600 instead of 115200). However, when using the internal HSI everything is correct. The internal is 16 MHz and the external is an 8 MHz crystal that is used to drive the PLL for a 32 MHz system clock.
This is the RCC init code, which is pretty much standard I guess.
int RCC_Configuration(void)
{
/* DISABLE HSI and target clocks prior to clock config */
RCC_HSICmd(DISABLE);
RCC_PLLCmd(DISABLE);
RCC_HSEConfig(RCC_HSE_OFF);
/* Set HSE as sys clock*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
/* Enable ADC & SYSCFG clocks */
RCC_APB2Periph_SYSCFG , ENABLE);
/* Allow access to the RTC */
PWR_RTCAccessCmd(ENABLE);
/* Reset RTC Backup Domain */
RCC_RTCResetCmd(ENABLE);
RCC_RTCResetCmd(DISABLE);
/* LSI used as RTC source clock */
/* The RTC Clock may varies due to LSI frequency dispersion. */
/* Enable the LSI OSC */
RCC_LSICmd(ENABLE);
/* Wait until LSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
/* Select the RTC Clock Source */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
/* Enable the RTC */
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC APB registers synchronisation */
RTC_WaitForSynchro();
// ENABLE HSE
RCC_HSEConfig(RCC_HSE_ON);
ErrorStatus HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
/* 32Mhz = 8Mhz * 12 / 3 */
RCC_PLLConfig(RCC_PLLSource_HSE, RCC_PLLMul_12, RCC_PLLDiv_3);
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while(RCC_GetSYSCLKSource() != 0x0C) // 0x0C = PLL
{
}
/* Enable the PWR clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR->CR = PWR_CR_VOS_0; /* Select the Voltage Range 1 (1.8V) */
while((PWR->CSR & PWR_CSR_VOSF) != 0); /* Wait for Voltage Regulator Ready */
/* HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK1 = HCLK/2 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* Enable the GPIOs clocks */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC| RCC_AHBPeriph_GPIOD| RCC_AHBPeriph_GPIOE| RCC_AHBPeriph_GPIOH, ENABLE);
/* Enable comparator, LCD and PWR mngt clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_COMP | RCC_APB1Periph_LCD | RCC_APB1Periph_PWR,ENABLE);
}
return 0;
}
I'm using STDperiph to configure the UART1, which on this mcu will run on PCLK2. Checked all the init methods and the register contents. The mantissa and fraction of the baudrate register are correctly calculated and should yield the correct baud rate no matter what the PCLK value is.
This is the UART init code:
void usartinit(void)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitStructure.USART_BaudRate = 115200 ;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* Enable GPIO clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_PinAFConfig(USARTx_GPIO, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(USARTx_GPIO, GPIO_PinSource10, GPIO_AF_USART1);
/* Configure USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = USARTx_TX;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(USARTx_GPIO, &GPIO_InitStructure);
/* Configure USART Rx as input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = USARTx_RX;
GPIO_Init(USARTx_GPIO, &GPIO_InitStructure);
/* USART configuration */
USART_Init(USART1, &USART_InitStructure);
/* Enable USART */
USART_Cmd(USART1, ENABLE);
}
The only possibility I can think of right now is that the crystal is just 4 MHz, but this is a Nucleo board and the MCO from the attached STLink is used for HSE, which definitely is 8 MHz.
What's the blatant mistake I'm making?
It seems the clock is messed up. Check the HSE_VALUE macro in your code. That might be using default Dev board crystal value. I would suggest to change that value to the crystal you are using. You can use this link to set the clock speed.
I think the previous answer is correct. When using HSI your system clock is 16MHz, whereas when using HSE you system clock is 32MHz.
I suspect HSE value is set to 16MHz.
You could also test this by setting the multiplier to 4 and the divider to 2 so that the system clock is 16MHz when running the HSE.
The HSE value will be in the startup code somewhere.
The value is used by the USART code so that it knows what frequency the USART is being driven with in order to calculate the baud rate.
Ok, finally figured it out. On the Nucleo boards in the default configuration, the HSE clock is connected to the MCO clock output of the STLink Programmer on the board. On multiple of my boards however this clock signal gets distorted so much that the target uC only sees 4 MHz. If I output the HSE on the MCO of the target it produces a 4 MHz square wave with a weird duty cycle of 75%. When probing the MCO input signal with a scope the probe capacitance is sufficent to produce the correct 8 MHz input.
So, I guess don't trust your eval boards... Will now get a few crystals and populate the "real" external clock on those boards.
When I call vTaskDelay, the delay lasts half of the supposed time. I have traced back the problem and I see that the Tick rate value is the double of what it should be as defined in configTICK_RATE_HZ. I checked this using the tick hook to toggle a led and measuring the frequency with an oscilloscope.
I am configuring the Atmel SAM L21 Xplained pro A board (ATSAML21J18A), with Atmel Studio 7 and FreeRTOS v8.0.1, based on the files of an ASF example called "FreeRTOS tickless demo using OLED1 Xplained".
My CPU clock runs at 12MHz from the SYSTEM_CLOCK_SOURCE_OSC16M. The configured tick rate is 100 Hz, from a timer clocked from GLCK_O(CPU clock). However, when I change the CPU clock rate at 4MHz instead 12 MHz, the Tick rate is correct, so I guess I'm missing some configuration somewhere for the timer which runs the OS tick.
Here are some values of OS tick rate I get with different CPU clock rates:
CPU: 4 MHz - Tick rate: 100 Hz
CPU: 8 MHz - Tick rate: 548 Hz
CPU: 12 MHz - Tick rate: 218 Hz
CPU: 16 MHz - Tick rate: 548 Hz
CPU: 48 MHz - Tick rate: 2,25 kHz
Also, when I configure the OS tick timer clock source as the internal ultra low power oscilator ULPOSC32k running at 32kHz, the tick rate is correct, independently of the CPU clock frequency (100Hz).
Moreover, when I select tickless mode (1 or 2), even with the configuration that works well in tick mode, with the CPU at 4MHz and the tick interrupt generated from the Systick timer, I have the same problem, the dalay lasts half of what it should.
In FreeRTOSConfig I have:
#define configUSE_PREEMPTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 1
#define configPRIO_BITS 2
#define configCPU_CLOCK_HZ ( system_gclk_gen_get_hz(GCLK_GENERATOR_0) )
#define configTICK_RATE_HZ ( ( portTickType ) 100 )
The tick timer configuration is:
void vPortSetupTimerInterrupt(void)
{
// Struct for configuring TC
struct tc_config tcconf;
// Set up configuration values
tc_get_config_defaults(&tcconf);
tcconf.clock_source = GCLK_GENERATOR_0;
tcconf.counter_size = TC_COUNTER_SIZE_32BIT;
tcconf.run_in_standby = true;
tcconf.clock_prescaler = TC_CLOCK_PRESCALER_DIV1;
tcconf.wave_generation = TC_WAVE_GENERATION_MATCH_FREQ;
// Initialize the TC
tc_init(&tc, TICK_TC, &tcconf);
// Register and enable callback for freeRTOS tick handler
tc_register_callback(&tc, (tc_callback_t) xPortSysTickHandler, TC_CALLBACK_CC_CHANNEL0);
tc_enable_callback(&tc, TC_CALLBACK_CC_CHANNEL0);
// Set top value equal to one os tick
tc_set_top_value(&tc, TIMER_RELOAD_VALUE_ONE_TICK);
// Enable the timer
tc_enable(&tc);
}
where TIMER_RELOAD_VALUE_ONE_TICK comes from:
//! Frequency of timer
#define TIMER_HZ ( configCPU_CLOCK_HZ )
//! Value per os tick of timer
#define TIMER_RELOAD_VALUE_ONE_TICK ( TIMER_HZ / configTICK_RATE_HZ )
//! Maximum value of timer
#define TIMER_MAX_COUNT ( 0xffffffff )
//! Maximum possible suppressed ticks with timer
#define TIMER_MAX_POSSIBLE_SUPPRESSED_TICKS ( TIMER_MAX_COUNT / TIMER_RELOAD_VALUE_ONE_TICK )
I would appreciate very much any insight on this timer issue, which keeps me stuck. I have already checked two similar questions related to this:
STM32 SysTick counting twice as fast as it should
freertos tick factor 2 too fast on stm32f4xx
The saml21 has 5 timer/counters TC0 - TC4. The count registers are 16bit. You can use TC0 and TC1(or TC2 and TC3) together to make it 32bit. TC4, the only timer in PDO, does not have another timer paired with it. It can't be used as a 32bit timer(though it will allow you to try).
Change TIMER_MAX_COUNT to 0xffff and tcconf.counter_size to TC_COUNTER_SIZE_16BIT and you will be able to use TC4 instead of TC2.
Changing the Timer instance from TC4 to TC2 solves the issue.
// Initialize the TC
tc_init(&tc, TICK_TC, &tcconf);
//! Timer/Counter instance to use as tick timer
//#define TICK_TC TC4
#define TICK_TC TC2
Now it generates a correct 100 Hz tick independently of the CPU clock frequency configured.
However, I still have to see the implications this will have when I activate the low power modes, as it seems the TC4 is the only timer active in Power Domain 0
(PD0)(the lowest power domain).
I am programming the microcontroller PIC16F676 SPI interface with MCP2515. It will set a flag in every 224ms, and timercounter will increase from 0*F8 to 0*FF then overflow to set this flag. Therefore, 32ms * 07H = 224ms. The question is how to let the timer interrupt every 32ms,WHERE this 32ms comes from.
//Timer interrupts every 32ms and set a flag every 224ms (32ms * 07H = 224ms)
//Initial value = FFH - 07H = F8H
if(T0IF) //TMR0 overflow interrupt flag bit
{
TimerCounter++;
if(!TimerCounter) //if rolled over, set flag. Main will handle the rest.
{
TimerCounter = 0*F8;
gSampleFlag = 1;
}
T0IF = 0; //reset for next flag
}
The 32 ms period of the timer is determined by the configuration of the timer, which is not included in your code excerpt (i.e., it may be done elsewhere in your code). Read section 4.0 of the PIC16F630/676 datasheet, which explains the TIMER0 Module.
Timer0 is configured as follows:
T0CS is either:
cleared to select the internal clock source (Timer mode) for Timer0,
or set to select the external clock source (Counter mode).
T0IE is set to enable the Timer0 interrupt.
The prescaler may be used in conjunction with the internal clock source to adjust the tick rate of Timer0
PSA is cleared to assign the prescaler to Timer0.
PS2:PS0 are set to select the prescaler rate.
So either the external clock source or the internal clock source and prescaler determine the tick rate of Timer0.
32ms is the time period of clock source which your timer counter is counting for 0x07 times.
Your timer unit is synchronised with common clock source which is derived from either external crystal or internal oscillator. During clock configuration you need to decide what should be peripheral bus clock through which your timer unit is interfaced. While configuring timer unit you can further divide this peripheral clock to less frequency using prescaler to increase the range of period.
Now suppose your peripheral bus clock frequency is 1MHz and your prescaler is 1, your counter will increment or decrement every 1us and for 0x07 count, it will generate only 7us of period. In your example you need to set prescaler 32000 (if it allowed to set) as reference clock for counting so that 1 count means 32ms.
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.