i.MX 8M EVK : how to calculate the frequency values for a 1ms timer? - timer

I want to implement a simple "GPT" timer that generates an interrupt every 1ms.
However, I get an interrupt exactly every 3ms (instead of the desired 1ms).
Where is my error? What values should I set to get a 1ms timer?
Here is my calculation for the GPT timer:
EXPLANATION OF TIMER VALUES:
We take for source clock the PLL1 DIV2 400MHz
We define the root divisor at 4 => 400MHz / 4 = 100MHz
100MHz = one increment every 10ns
We want an interrupt to be generated every 1 ms
So we have :
Output_compare_value = delay_time x GPT_frequency
Output_compare_value = 1 x 10^-3 x (1/(10 x 10^-9)) = 100000
Here is my code (I change the state of a GPIO at each interrupt to check the operation of my timer on the oscilloscope):
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_debug_console.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"
#include "fsl_gpt.h"
#include "fsl_gpio.h"
#include "fsl_common.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define GPT_IRQ_ID GPT1_IRQn
#define EXAMPLE_GPT GPT1
//#define EXAMPLE_GPT_CLK_FREQ \
// (CLOCK_GetPllFreq(kCLOCK_SystemPll1Ctrl) / (CLOCK_GetRootPreDivider(kCLOCK_RootGpt1)) / \
// (CLOCK_GetRootPostDivider(kCLOCK_RootGpt1)) / 2) /* SYSTEM PLL1 DIV2 */
#define EXAMPLE_GPT_CLK_FREQ 100000
#define EXAMPLE_GPT_IRQHandler GPT1_IRQHandler
#define EXAMPLE_LED_GPIO GPIO3
#define EXAMPLE_LED_GPIO_PIN 23U
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
volatile bool gptIsrFlag = false;
/* The PIN status */
volatile bool g_pinSet = false;
/*******************************************************************************
* Code
******************************************************************************/
void EXAMPLE_GPT_IRQHandler(void)
{
/* Clear interrupt flag.*/
GPT_ClearStatusFlags(EXAMPLE_GPT, kGPT_OutputCompare1Flag);
gptIsrFlag = true;
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F, Cortex-M7, Cortex-M7F Store immediate overlapping
exception return operation might vector to incorrect interrupt */
#if defined __CORTEX_M && (__CORTEX_M == 4U || __CORTEX_M == 7U)
__DSB();
#endif
}
/*!
* #brief Main function
*/
int main(void)
{
uint32_t gptFreq;
gpt_config_t gptConfig;
/* Define the init structure for the output LED pin*/
gpio_pin_config_t led_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
/* Board pin, clock, debug console init */
/* Board specific RDC settings */
BOARD_RdcInit();
BOARD_InitBootPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
BOARD_InitMemory();
CLOCK_SetRootMux(kCLOCK_RootGpt1, kCLOCK_GptRootmuxSysPll1Div2); /* Set GPT1 source to SYSTEM PLL1 DIV2 400MHZ */
CLOCK_SetRootDivider(kCLOCK_RootGpt1, 1U, 4U); /* Set root clock to 400MHZ / 4 = 100MHZ */
GPT_GetDefaultConfig(&gptConfig);
/* Initialize GPT module */
GPT_Init(EXAMPLE_GPT, &gptConfig);
/* Divide GPT clock source frequency by 3 inside GPT module */
GPT_SetClockDivider(EXAMPLE_GPT, 1);
/* Get GPT clock frequency */
gptFreq = EXAMPLE_GPT_CLK_FREQ;
/* GPT frequency is divided by 3 inside module */
gptFreq /= 1;
/* Set both GPT modules to 1 second duration */
GPT_SetOutputCompareValue(EXAMPLE_GPT, kGPT_OutputCompare_Channel1, gptFreq);
/* Enable GPT Output Compare1 interrupt */
GPT_EnableInterrupts(EXAMPLE_GPT, kGPT_OutputCompare1InterruptEnable);
/* Enable at the Interrupt */
EnableIRQ(GPT_IRQ_ID);
PRINTF("\r\nPress any key to start the example");
GETCHAR();
/* Init output LED GPIO. */
GPIO_PinInit(EXAMPLE_LED_GPIO, EXAMPLE_LED_GPIO_PIN, &led_config);
/* Start Timer */
PRINTF("\r\nStarting GPT timer ...");
GPT_StartTimer(EXAMPLE_GPT);
while (true)
{
/* Check whether occur interupt and toggle LED */
if (true == gptIsrFlag)
{
PRINTF("\r\n GPT interrupt is occurred !");
gptIsrFlag = false;
if (g_pinSet)
{
GPIO_PinWrite(EXAMPLE_LED_GPIO, EXAMPLE_LED_GPIO_PIN, 0U);
g_pinSet = false;
}
else
{
GPIO_PinWrite(EXAMPLE_LED_GPIO, EXAMPLE_LED_GPIO_PIN, 1U);
g_pinSet = true;
}
}
else
{
__WFI();
}
}
}

I found out what my problem was with the timer. The truth is that all my values were fine, but it was the execution of the logging that was taking time (line PRINTF("GPT interrupt is occurred !");) So I could have lowered my reload value even more, but I would still have the logging that was taking time to run.

Related

Incorrect 1ms delay at GD32VF103

I use GD32VF103C_START kit from GigaDevice and try LED blinking sample project. I found this project in the Internet and it compiles just fine (I've only changed from 500ms to 1000ms=1s).
main.c:
#include "gd32vf103.h"
#include "gd32vf103c_start.h"
#include "systick.h"
int main(void)
{
/* enable the LED clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* configure LED GPIO port */
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
gpio_bit_reset(GPIOA, GPIO_PIN_7);
while(1){
/* insert 1s delay */
delay_1ms(1000);
/* toggle the LED */
gpio_bit_write(GPIOA, GPIO_PIN_7, (bit_status)(1-gpio_input_bit_get(GPIOA, GPIO_PIN_7)));
/* insert 1s delay */
delay_1ms(1000);
gpio_bit_write(GPIOA, GPIO_PIN_7, (bit_status)(1-gpio_input_bit_get(GPIOA, GPIO_PIN_7)));
}
}
systick.c:
#include "gd32vf103.h"
#include "systick.h"
void delay_1ms(uint32_t count)
{
uint64_t start_mtime, delta_mtime;
/* don't start measuruing until we see an mtime tick */
uint64_t tmp = get_timer_value();
do{
start_mtime = get_timer_value();
}while(start_mtime == tmp);
do{
delta_mtime = get_timer_value() - start_mtime;
}while(delta_mtime <(SystemCoreClock/4000.0 *count));
}
But instead of 1s delay it delays like for 13s. Where is mistake?
Problem is non in main.c, neither in systick.c, it's in system_gd32vf103.c.
There are:
/* system frequency define */
#define __IRC8M (IRC8M_VALUE) /* internal 8 MHz RC oscillator frequency */
#define __HXTAL (HXTAL_VALUE) /* high speed crystal oscillator frequency */
#define __SYS_OSC_CLK (__IRC8M) /* main oscillator frequency */
/* select a system clock by uncommenting the following line */
/* use IRC8M */
//#define __SYSTEM_CLOCK_48M_PLL_IRC8M (uint32_t)(48000000)
//#define __SYSTEM_CLOCK_72M_PLL_IRC8M (uint32_t)(72000000)
//#define __SYSTEM_CLOCK_108M_PLL_IRC8M (uint32_t)(108000000)
/********************************************************************/
//#define __SYSTEM_CLOCK_HXTAL (HXTAL_VALUE)
//#define __SYSTEM_CLOCK_24M_PLL_HXTAL (uint32_t)(24000000)
/********************************************************************/
//#define __SYSTEM_CLOCK_36M_PLL_HXTAL (uint32_t)(36000000)
//#define __SYSTEM_CLOCK_48M_PLL_HXTAL (uint32_t)(48000000)
//#define __SYSTEM_CLOCK_56M_PLL_HXTAL (uint32_t)(56000000)
//#define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
//#define __SYSTEM_CLOCK_96M_PLL_HXTAL (uint32_t)(96000000)
#define __SYSTEM_CLOCK_108M_PLL_HXTAL (uint32_t)(108000000)
and you need uncomment #define __SYSTEM_CLOCK_HXTAL (HXTAL_VALUE) line. That's it.

How do I enable the Timer_A0 module for the following CCS IDE MSP432P401R Launchpad microcontroller code?

I have the following code for a task that requires me to use the following code to use the Timer_A0 module in the CCS IDE to control the speeds of the motors for a robot that uses the MSP432P401R launchpad as the control unit. How do I initialize the Timer_A0 module in the C programming code below?:
#include "driverlib.h"
#include "mechrev.h"
/* Define macros and function prototypes if needed */
#define BTN1_PIN GPIO_PORT_P1,GPIO_PIN1
#define BTN2_PIN GPIO_PORT_P1,GPIO_PIN4
#define ENB1_PIN GPIO_PORT_P1,GPIO_PIN6
#define ENB2_PIN GPIO_PORT_P1,GPIO_PIN7
#define PWM1_PIN GPIO_PORT_P2,GPIO_PIN4
#define PWM2_PIN GPIO_PORT_P2,GPIO_PIN5
#define PWM3_PIN GPIO_PORT_P2,GPIO_PIN6
#define PWM4_PIN GPIO_PORT_P2,GPIO_PIN7
#define BMP0_PIN GPIO_PORT_P4,GPIO_PIN0
#define BMP7_PIN GPIO_PORT_P4,GPIO_PIN7
#define BMP2_PIN GPIO_PORT_P4,GPIO_PIN2
#define BMP6_PIN GPIO_PORT_P4,GPIO_PIN6
#define BMP3_PIN GPIO_PORT_P4,GPIO_PIN3
#define BMP5_PIN GPIO_PORT_P4,GPIO_PIN5
#define BTN3_PIN GPIO_PORT_P4, GPIO_PIN0 | GPIO_PIN7
#define BTN4_PIN GPIO_PORT_P4, GPIO_PIN2 | GPIO_PIN6
#define BTN5_PIN GPIO_PORT_P4, GPIO_PIN3 | GPIO_PIN5
/* Define configuration structs if needed */
/* Declare global variables if needed */
int i = 0;
uint32_t counter = 0;
/* Main program */
void main(void)
{
/* Stop Watchdog Timer */
WDT_A_holdTimer();
/* Call the mechrev_setup function included in the mechrev.h header file */
mechrev_setup();
/* Initialize GPIOs P1.1 and P1.4 for PushButtons (S1 and S2 switches) */
MAP_GPIO_setAsInputPinWithPullUpResistor(BTN1_PIN);
MAP_GPIO_setAsInputPinWithPullUpResistor(BTN2_PIN);
/* Initialize GPIOs P1.6 and P1.7 for Motor Driver IC Enable Pins */
MAP_GPIO_setAsOutputPin(ENB1_PIN);
MAP_GPIO_setAsOutputPin(ENB2_PIN);
/* Initialize GPIOs P2.4, P2.5, P2.6 and P2.7 for PWM functionality */
MAP_GPIO_setAsInputPin(PWM1_PIN);
MAP_GPIO_setAsInputPin(PWM2_PIN);
MAP_GPIO_setAsInputPin(PWM3_PIN);
MAP_GPIO_setAsInputPin(PWM4_PIN);
/* Initialize Timer A0 to generate PWM signals */
(Timer_A0 module needs to be initialized here)
/* Declare local variables if needed */
/* Call the initialization grading macro */
MACRO_LAB4_INIT();
while(1)
{
/* Design a Polling process to detect PushButtons press and adjust the PWM duty cycles
accordingly */
if (MAP_GPIO_getInputPinValue(BTN1_PIN) == GPIO_INPUT_PIN_LOW)
{
if(i == 1)
{
TA0CCR1 = 999;
TA0CCR2 = 0;
TA0CCR3 = 999;
TA0CCR4 = 0;
}
if(i == 2)
{
TA0CCR1 = 1998;
TA0CCR2 = 0;
TA0CCR3 = 1998;
TA0CCR4 = 0;
}
if(i == 3)
{
TA0CCR1 = 3000;
TA0CCR2 = 0;
TA0CCR3 = 3000;
TA0CCR4 = 0;
}
for (i=0; i<10000; i++); // switch debouncing
}
else if (MAP_GPIO_getInputPinValue(BTN2_PIN) == GPIO_INPUT_PIN_LOW)
{
if(i == 1)
{
TA0CCR1 = 0;
TA0CCR2 = 999;
TA0CCR3 = 0;
TA0CCR4 = 999;
}
if(i == 2)
{
TA0CCR1 = 0;
TA0CCR2 = 1998;
TA0CCR3 = 0;
TA0CCR4 = 1998;
}
if(i == 3)
{
TA0CCR1 = 0;
TA0CCR2 = 3000;
TA0CCR3 = 0;
TA0CCR4 = 3000;
}
for (i=0; i<10000; i++); // switch debouncing
}
else
{
TA0CCR1 = 0;
TA0CCR2 = 0;
TA0CCR3 = 0;
TA0CCR4 = 0;
}
/* Note: Call the event grading macro after changing PWMs */
MACRO_LAB4_EVENT();
}
}
void PORT4_IRQHandler(void)
{
/* Check the interrupt status */
uint32_t status;
status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P4);
if (status)
{
if(MAP_GPIO_getInputPinValue(BMP0_PIN) == GPIO_INPUT_PIN_LOW ||
MAP_GPIO_getInputPinValue(BMP7_PIN) == GPIO_INPUT_PIN_LOW)
{
i = 1;
counter++;
}
else if (MAP_GPIO_getInputPinValue(BMP2_PIN) == GPIO_INPUT_PIN_LOW ||
MAP_GPIO_getInputPinValue(BMP6_PIN) == GPIO_INPUT_PIN_LOW)
{
i = 2;
counter++;
}
else if (MAP_GPIO_getInputPinValue(BMP3_PIN) == GPIO_INPUT_PIN_LOW ||
MAP_GPIO_getInputPinValue(BMP5_PIN) == GPIO_INPUT_PIN_LOW)
{
i = 3;
counter++;
}
}
else
{
counter++;
}
MACRO_LAB3_EVENT();
/* Clear the PORT4 interrupt flag */
MAP_GPIO_clearInterruptFlag(GPIO_PORT_P4, status);
}
Before you can configure the timer itself, you need to initialize a struct that you will use to configure the timer (there are slight differences in the values needed for upmode, updownmode, continuous mode). You can download the Driverlib Manual MSP432 DriverLib for MSP432 devices which contains detailed use of the timers.
Another very helpful tutorial is Interrupts, Timers & Debugging
You are mixing both Driverlib names and register-level names in your code. That's fine, just make sure you keep the nomenclature straight and don't confuse register access names with user variables, etc..
Now, to configure your timer Timer_A0, you need to initialize a structure to use configuring the time. An example for configuring the timer in up mode would be:
/* TimerA0 UpMode Configuration Parameter */
const Timer_A_UpModeConfig upConfigTA0 =
{
TIMER_A_CLOCKSOURCE_ACLK, /* ACLK Clock 32 KHz (uint_fast16_t clockSource) */
TIMER_A_CLOCKSOURCE_DIVIDER_1, /* Rollover in 1 sec (uint_fast16_t clockSourceDivider) */
ACLKMAX, /* 32767 ticks (uint_fast16_t timerPeriod) */
TIMER_A_TAIE_INTERRUPT_DISABLE, /* Rollover TAIE (uint_fast16_t timerInterruptEnable_TAIE) */
TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE, /* CCR0 CCR0IE (uint_fast16_t captureCompareInterruptEnable_CCR0_CCIE) */
TIMER_A_DO_CLEAR /* Clear Timer (uint_fast16_t timerClear) */
};
Above the timer is configured to use ACLK (32KHz), but you can use SMCLK as well.
Within your code you will need to configure the timer using the struct above. For example:
/* Configuring TimerA0 for Up Mode */
MAP_Timer_A_configureUpMode (TIMER_A0_BASE, &upConfigTA0);
You can also configure/set any additional timer interrupts you plan to use, e.g.
/* Set Capture/Compre Register 3 */
MAP_Timer_A_setCompareValue (TIMER_A0_BASE, MPUCCR, MPUCCRTICKS);
/* enable CCRn compare interrupt */
MAP_Timer_A_enableCaptureCompareInterrupt (TIMER_A0_BASE, MPUCCR);
At this point you have your timer and interrupts configured and read to use, but the timer is not yet started. Before the timer and interrupts are active, you must start the timer itself. Generally, you do this right before you enter you program loop (the while (1) { ... } loop). That way you can configure other peripherals without having your interrupts starting to fire until you complete all your configuration. After everything is configured, start the timer:
/* Starting the Timer_A0 in up mode (just before while loop) */
MAP_Timer_A_startCounter (TIMER_A0_BASE, TIMER_A_UP_MODE);
With every timer, you have two primary interrupt service routines provided by driverlib. The first handles CCR0 and is named TA0_0_IRQHandler() for Timer_A0 (or TA1_0_IRQHandler for Timer_A1, etc..)). It's declaration is:
/**
* Timer A0 CCR0 Interrupt
*/
void TA0_0_IRQHandler(void)
{
...
}
All other interrupts associated with the timer use TA0_N_IRQHandler(). For instance for capture/compare registers CCR1 - CCR5 and the TAIE rollover interrupt (one clock-cycle after CCR0). It has a declaration of
/**
* Timer A0 Interrupt Handler (remaining interrupts)
*/
void TA0_N_IRQHandler(void)
{
...
}
Since you are looking to control a robot arm, I presume you will be using the timer for PWM control. The tutorial covers that fairly well.
I placed complete example using Timer_A to driver PWM on pastebin at MSP432 PWM Control of Tri-Color LED. That shows the use of upmode to drive PWM.
DO NOT OVERLOAD THE INTERRUPT FUNCTIONS WITH FUNCTION CALLS OR COMPUTATIONALLY INTENSIVE CODE. They are effectively signal-handlers. You want to avoid time consuming processing in the ISR (Interrupt Service Request) functions. Instead, the best approach is to set a flag in the interrupt function to complete processing in your program loop, e.g.
/* Starting the Timer_A0 in up mode */
MAP_Timer_A_startCounter (TIMER_A0_BASE, TIMER_A_UP_MODE);
while (1)
{
if (btn1pressed) { /* respond to button presses by calling button handlers */
btn1_handler();
}
if (btn2pressed) {
btn2_handler();
}
if (getmpudata) { /* retrieve data from MPU9250 */
get_MPU_data();
}
if (getmagdata) { /* retrieve data from AK8963 */
get_MAG_data();
}
...
Above, each of the variable names contained in the if (...) statements are simply bool variables set in the interrupt functions that tell your program it's time to process whatever function they trigger. Processing is done in main() not in the interrupt functions. The reason being that heavy computation in the interrupt function can cause the interrupt to fire again before your processing is complete (your code takes more time than the time between interrupts). That is a sure-fire way to cause your program to crater.
The driverlib user's guide is a goldmine for configuring all the peripherals. See if you can get your timer working and look at the tutorial link I provided above. Let me know if you have further questions.

ATtiny817 Xplained Mini RTC Configuration

I am using a ATtiny817 xplained Mini, I want to toggle LED using overflow interrupt for every 10 sec from RTC, but i am not able generate the interrupt. Is the configurations correct?
I have configured the Main clock source 32kHz (Low Power Oscillator), using 1KHz from it to clock the RTC with no prescaler.
#define RTC_SAMPLE_PERIOD (1024 * 10)
void RTC_init(void)
{
/* Configuring the Clock Source */
_PROTECTED_WRITE(CLKCTRL.OSC32KCTRLA, CLKCTRL_RUNSTDBY_bm);
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, !CLKCTRL_PEN_bm);
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, !CLKCTRL_CLKOUT_bm | CLKCTRL_CLKSEL_OSCULP32K_gc);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_OSC32KS_bm));
/* Initialize RTC */
while (RTC.STATUS > 0)
; //Wait for All registers to be Synchronized
/* Set Period */
RTC.PER = RTC_SAMPLE_PERIOD;
/* Configuring RTC CLOCK */
RTC.CLKSEL = RTC_CLKSEL_INT1K_gc; //Selecting 1kHz from 32KHz Low Power Oscillator (OSCULP32K)
/* Run in debug: enabled */
RTC.DBGCTRL |= RTC_DBGRUN_bm;
RTC.CTRLA = RTC_RTCEN_bm /* Enable: enabled */
| RTC_RUNSTDBY_bm; /* Run In Standby: enabled */
/* Enable Overflow Interrupt */
RTC.INTCTRL |= RTC_OVF_bm;
}
ISR(RTC_CNT_vect)
{
LEDupdateFlg = 1;
RTC.INTFLAGS |= RTC_OVF_bm;
}

Getting uptime from RTC

I wanted to get uptime of the system from the RTC in seconds. The point is that while I can sum up values from the RTC time register (RTC_TR) it only works up to 24 hours and then overflows while one day is being added to RTC date register (RTC_DR).
How do I count seconds from the time I start up the system? I don't need the calendar.
Below the explaination of what do I mean by "overflow"
I've configured RTC according to STM's RTC_LSI example for StdPeriph and set only the time and not the date.
However when I get the time from RTC_TR using RTC_GetTime function, after 23h59m59s, the time goes back to 0h0m0s.
Of course RTC_TR holds time in its BCD format in tens and units of current hour, minute and second and days are counted in RTC_DR. Anyway I'd like it to keep on adding hours and not to add the days to the date register as I want to calculate only uptime and I'm afraid that if I started counting the months and days I'd have problems.
void RtcConfig(void)
{
RTC_InitTypeDef RTC_InitStructure;
RTC_TimeTypeDef RTC_TimeStructure;
RTC_DateTypeDef RTC_DateStructure;
uint32_t LSIFreq = 0;
/* Enable the PWR clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
/* Allow access to Backup Domain */
PWR_BackupAccessCmd(ENABLE);
/* Disable wake-up source(ALARM) to guarantee free access to WUT level-OR input */
RTC_ITConfig(RTC_IT_ALRA, DISABLE);
/* Clear Wakeup flag */
PWR_ClearFlag(PWR_FLAG_WU);
/* Enable wake-up source(ALARM) to guarantee free access to WUT level-OR input */
RTC_ITConfig(RTC_IT_ALRA, ENABLE);
/* Enable the LSI OSC */
RCC_LSICmd(ENABLE);
/* Wait till LSI is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
{}
/* Check if the StandBy flag is set (leaving stand-by) */
if (PWR_GetFlagStatus(PWR_FLAG_SB) != RESET)
{
/* Clear StandBy flag */
PWR_ClearFlag(PWR_FLAG_SB);
/* Check if the StandBy flag is cleared */
if (PWR_GetFlagStatus(PWR_FLAG_SB) != RESET)
{
while(1);
}
RTC_WaitForSynchro();
/* No need to configure the RTC as the RTC config(clock source, enable,
prescaler,...) are kept after wake-up from STANDBY */
}
else
{
/* RTC Configuration ******************************************************/
/* Reset Backup Domain */
RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);
/* Select the RTC Clock Source */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
/* Enable the RTC Clock */
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC APB registers synchronisation */
RTC_WaitForSynchro();
/* Get the LSI frequency: TIM14 is used to measure the LSI frequency */
LSIFreq = GetLSIFrequency();
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
RTC_InitStructure.RTC_AsynchPrediv = 99;
RTC_InitStructure.RTC_SynchPrediv = (LSIFreq/100) - 1;
RTC_Init(&RTC_InitStructure);
/* Set the time to 00h 00mn 00s AM */
RTC_TimeStructure.RTC_H12 = RTC_H12_PM;
RTC_TimeStructure.RTC_Hours = 0;
RTC_TimeStructure.RTC_Minutes = 0;
RTC_TimeStructure.RTC_Seconds = 0;
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStructure);
}
}
uint32 GetLSIFrequency(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_ClocksTypeDef RCC_ClockFreq;
/* TIM14 configuration *******************************************************/
/* Enable TIM14 clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
/* Reset TIM14 registers */
TIM_DeInit(TIM14);
/* Configure TIM14 prescaler */
TIM_PrescalerConfig(TIM14, 0, TIM_PSCReloadMode_Immediate);
/* Connect internally the TIM14_CH1 to the RTC clock output */
TIM_RemapConfig(TIM14, TIM14_RTC_CLK);
/* TIM14 configuration: Input Capture mode ---------------------
The reference clock(LSE or external) is connected to TIM14 CH1
The Rising edge is used as active edge,
The TIM14 CCR1 is used to compute the frequency value
------------------------------------------------------------ */
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV8;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM14, &TIM_ICInitStructure);
/* Enable the TIM14 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM14_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable TIM14 counter */
TIM_Cmd(TIM14, ENABLE);
/* Reset the flags */
TIM14->SR = 0;
/* Enable the CC1 Interrupt Request */
TIM_ITConfig(TIM14, TIM_IT_CC1, ENABLE);
/* Wait until the TIM14 get 2 LSI edges (refer to TIM14_IRQHandler() in
stm32F0xx_it.c file) ******************************************************/
while(CaptureNumber != 2)
{
}
/* Deinitialize the TIM14 peripheral registers to their default reset values */
TIM_DeInit(TIM14);
/* Compute the LSI frequency, depending on TIM14 input clock frequency (PCLK1)*/
/* Get SYSCLK, HCLK and PCLKx frequency */
RCC_GetClocksFreq(&RCC_ClockFreq);
/* Disable TIM14 counter */
TIM_Cmd(TIM14, DISABLE);
TIM_ITConfig(TIM14, TIM_IT_CC1, DISABLE);
/* PCLK1 prescaler equal to 1 => TIMCLK = PCLK1 */
return ((RCC_ClockFreq.PCLK_Frequency / PeriodValue) * 8);
}
void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_RTC_FORMAT(RTC_Format));
/* Get the RTC_TR register */
tmpreg = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
/* Fill the structure fields with the read parameters */
RTC_TimeStruct->RTC_Hours = (uint8_t)((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> 16);
RTC_TimeStruct->RTC_Minutes = (uint8_t)((tmpreg & (RTC_TR_MNT | RTC_TR_MNU)) >>8);
RTC_TimeStruct->RTC_Seconds = (uint8_t)(tmpreg & (RTC_TR_ST | RTC_TR_SU));
RTC_TimeStruct->RTC_H12 = (uint8_t)((tmpreg & (RTC_TR_PM)) >> 16);
/* Check the input parameters format */
if (RTC_Format == RTC_Format_BIN)
{
/* Convert the structure parameters to Binary format */
RTC_TimeStruct->RTC_Hours = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Hours);
RTC_TimeStruct->RTC_Minutes = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Minutes);
RTC_TimeStruct->RTC_Seconds = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Seconds);
}
}
uint32 RtcGetTimeSec(void)
{
RTC_TimeTypeDef RTC_TimeStructure;
uint32 currenttimesec = 0;
/* Get the Current time in second */
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
currenttimesec = ((RTC_TimeStructure.RTC_Hours * 3600) +(RTC_TimeStructure.RTC_Minutes * 60) +
RTC_TimeStructure.RTC_Seconds);
return currenttimesec;
}
What does it mean overflows. Show your code & maths
In 32bits you can store:
Seconds Hours Days Years
4294967295 1193046.471 49710.26962 136.1925195
If your predicted up-time is more than 136.2 years use 64bit unsigned integer and you wil be able to count up to:
Seconds Hours Days Years Decades Centuries Millenniums Aeons (10e9 years)
18446744073709600000 5124095576030430 213503982334601 584942417355 58494241736 5849424174 584942417 585
Hope that will be enough yor you.

IIR Lowpass filter using STM32F429 Discovery board in Keil uVision

I am designing an IIR 2nd order Lowpass filter with sampling frequency = 100Hz and cutoff frequency = 10 Hz. The filter coefficients are of Chebyshev Type I using fdatool in Matlab.
But the code is not able to filter the signal (i.e. for all frequencies it gives the output with same amplitudes as the input signal) . Only minor decrease in amplitude is observed for an input signal of 10 KHz and above. I assure you that the ADC and DAC are working fine as i have tested the for FFT filter.
Here is the code:
/* Include core modules */
#include "stm32f4xx.h"
#include "stdint.h"
#include "stdlib.h"
#include "arm_math.h"
#include "my_files.h"
#define URS 2
#define numStages 1
#define NUM_TAPS 5*numStages
#define samples 3
////////ADC FUNCTION//////////////////
void ADC_configure(void)
{
RCC->APB2ENR|=1Ul<<8; // ADC1 clock enabled
ADC1->CR2|=0x00000001; // enable ADC
ADC1->CR1|=0; // single conversion ADC1 pin 0 has been selected
}
int32_t readADC(void)
{
ADC1->CR2|=(1UL<<30);
return(ADC1->DR);
}
////////DAC FUNCTION/////////////////
int32_t dv1,dv2,ds;
//---function declaration--//
// initilising DAC---------//
void DAC_init(void)
{
RCC->APB1ENR|=1UL<<29;
DAC->CR|=((1UL<<16)|(1UL<<0));
RCC->AHB1ENR|=0x00000001; // clock to gpio A
GPIOA->MODER|=0x00000F03; // pt0,4,5 in Analog mode
}
// Sending to DAC...........//
void Send_DAC(int32_t data_in1, int32_t data_in2)
{ dv1=data_in1;
dv2=data_in2<<16;
ds=dv2+dv1;
DAC->DHR12RD=ds;
}
/* IIR settings */
float32_t pState[2*numStages];
const float pCoeffs[NUM_TAPS] = {1,2,1,-1.1997,0.5157};//{b0,b1,b2,a1,a2}
/* Global variables */
float32_t Input[samples]; /* Data to be read from ADC */
float32_t InputData[samples]; /* Data to be processed */
float32_t Output[samples]; /* Output filtered Data */
arm_biquad_cascade_df2T_instance_f32 S; /* ARM IIR module */
uint16_t i;
void TIM3_Init (void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; /* enable clock for TIM1 */
TIM3->PSC = 8600; /* set prescaler = 10KHz */
TIM3->ARR = 100; /* set auto-reload = 10ms */
TIM3->RCR = 0; /* set repetition counter */
TIM3->CR1 |= (1UL << URS);
TIM3->DIER = TIM_DIER_UIE; /* Update Interrupt enable */
NVIC_EnableIRQ(TIM3_IRQn); /* TIM1 Interrupt enable */
NVIC_SetPriority (TIM3_IRQn, 0);
TIM3->CR1 |= TIM_CR1_CEN; /* timer enable */
}
void TIM3_IRQHandler() {
/*Shift Operation*/
for(i=samples-1;i>0;i--){
Input[i]= Input[i-1];
InputData[i]= Input[i];
}
/* Input part from the ADC */
Input[0] = (float32_t)readADC();
InputData[0] = Input[0];
//////////IIR//////////////////////
/* Initialize the IIR module */
arm_biquad_cascade_df2T_init_f32(&S, numStages, pCoeffs, pState);
/* Process the data through the IIR module */
arm_biquad_cascade_df2T_f32(&S, InputData, Output, samples);
////////DAC Output/////////////////
Send_DAC(Input[0], Output[0]);
}
/////////main function///////////////
int main(void) {
/* Initialize system */
SystemInit();
DAC_init();
ADC_configure();
TIM3_Init();
while (1) {
}
}
Any suggestion or solution would be of great help.
Some possible problems:
Did you enable the FPU?
Check alignment for ADC (and DAC?).
Ensure the interrupt-handler does not run too long (overflow).
Good you do not use the stdlib for much more tha init, btw. But you really should use symbolic constants for the register initialization! This does not cost extra.
Not directly related, but will(!) give wrong results: If I get it right, you trigger each conversion in readADC. This leads to jitter (resulting in noise on the digitized signal); trigger the conversations by a timer (that's what the trigger system is for actually) and use the ADC-interrupt to read the data or use a DMA (the STM DMA provides a double-buffer mode which is perfect for this). In this simple example, if using DMA, you can even get along completely without interrupt and do the calculations in the main program.
For the DAC you should the same.
Not sure why use a timer anyway; the ADC can self-trigger. Is that not sufficient?
You do not need to init IIR filter every time. Do it only once in init code. Init procedure clears previous values in pState, but they are required for IIR to perform correctly. That's the reason why your filter doesn't work. Presence of FPU only influences the speed of computation.

Resources