I just bought an stm32l152RC and was wondering how the delay works.
The system clock is 16Mhz.
Code:
static volatile uint32_t TimingDelay;
void Delay(__IO uint32_t nCount);
int main(void) {
Config_Systick();
char *RCCp = (char*) 0x40023800;
int *PBp = (int *) 0x40020400;
// RCC Config
*((int*) (RCCp + 28)) |= 0x3f;
*((int*) (RCCp + 32)) |= 1;
*PBp = 0x5000;
while (1) {
GPIO_TOGGLE(GPIOB, LD_GREEN); //toggle green led
Delay(1000); // 1 second?
}
} // end of main
RCC_ClocksTypeDef RCC_Clocks;
void Config_Systick() {
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000); // setting changed to / 1000
}
void TimingDelay_Decrement(void) {
if (TimingDelay != 0x00) {
TimingDelay--;
}
}
void Delay(uint32_t nTime) {
TimingDelay = nTime;
while (TimingDelay != 0) {
};
}
When I execute Delay(1000); in this case the Delay is 1 second, could someone please explain why the delay is 1 second?
After doing some research this is the answer I came up with.
doing SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000); means you'r setting 1000 ticks per second. when you do Delay(100) the delay will be 100 ms.
Related
I want to calculate time interval with timers. I'm using arduino ide. Also i can not decide which library to useful.
I just tried something following code.
I'm using this library
#include <ESP32Time.h>
int a;
int b;
int ldrValue;
#define LDR 0
/* create a hardware timer */
hw_timer_t * timer = NULL;
int timeThatPast;
/* motor pin */
int motor = 14;
/* motor state */
volatile byte state = LOW;
void IRAM_ATTR onTimer(){
state = !state;
digitalWrite(motor, state);
}
void setup() {
Serial.begin(115200);
pinMode(motor, OUTPUT);
/* Use 1st timer of 4 */
/* 1 tick take 1/(80MHZ/80) = 1us so we set divider 80 and count up */
timer = timerBegin(0, 80, false);
/* Attach onTimer function to our timer */
timerAttachInterrupt(timer, &onTimer, true);
//********************ALARM*******************
/* Set alarm to call onTimer function every second 1 tick is 1us
=> 1 second is 1000000us */
/* Repeat the alarm (third parameter) */
timerAlarmWrite(timer, 7000000, false);
//********************************************
/* Start an alarm */
timerAlarmEnable(timer);
Serial.println("start timer");
}
void loop() {
int ldrValue = analogRead(LDR);
ldrValue = map(ldrValue, 0, 4095, 0, 10000);
if(ldrValue > 8500){
a = timerRead(timer);
digitalWrite(motor,HIGH);
while(1){
int ldrValue = analogRead(LDR);
ldrValue = map(ldrValue, 0, 4095, 0, 10000);
if(ldrValue < 8500){
b = timerRead(timer);
digitalWrite(motor,LOW);
Serial.print("Entering Loop");
Serial.println(a);
Serial.println("**********");
Serial.println("**********");
Serial.print("Exiting loop");
Serial.println(b);
int difference = b - a;
Serial.println("Difference");
Serial.println(difference);
break;
}
}
}
}
Use millis or micros if you need more precise timing.
Here is an example sketch:
long lastDoTime = 0;
void setup(){
Serial.begin(115200);
delay(1000);
Serial.println("Hello! We will do something at every ms");
}
void doThisAtEvery(int ms){
if( millis() - lastDoTime >= ms ){
// Must save the lastDoTime
lastDoTime = millis();
// Do some stuff at every ms
}
}
void loop(){
// It will do the thing in every 100 ms.
doThisAtEvery(100);
}
If you want to toggle a pin let's say every 100 microsec
long lastToggleTime = 0;
int motorPin = 14;
boolean lastPinState = LOW;
void setup(){
Serial.begin(115200);
}
void togglePinEvery(int micros){
if( micros() - lastToggleTime >= micros ){
lastToggleTime = micros();
digitalWrite(motorPin,!lastPinState);
lastPinState = !lastPinState;
}
}
void loop(){
togglePinEvery(100);
}
EDIT Since you wanted timers only.
Here is a detailed explanation about timers: https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
Code example:
volatile int interruptCounter;
int totalInterruptCounter;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
interruptCounter++;
portEXIT_CRITICAL_ISR(&timerMux);
}
void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 1000000, true);
timerAlarmEnable(timer);
}
void loop() {
if (interruptCounter > 0) {
portENTER_CRITICAL(&timerMux);
interruptCounter--;
portEXIT_CRITICAL(&timerMux);
totalInterruptCounter++;
Serial.print("An interrupt as occurred. Total number: ");
Serial.println(totalInterruptCounter);
}
}
I have this program that prins to an LCD with watchdog interrupt. But the problem is that i need to have 2 decimals after seconds.
the code is as follows:
#include <Arduino.h>
#include "DFRobot_RGBLCD.h"
#include <stm32l4xx_hal_iwdg.h>
#include <Wire.h>
#define I2C2_SCL PB10
#define I2C2_SDA PB11
DFRobot_RGBLCD lcd(16,2);
TwoWire dev_i2c (I2C2_SDA, I2C2_SCL);
IWDG_HandleTypeDef watchdog;
void Start();
void Pause();
int paused = 0;
int milli = 0;
volatile byte state = HIGH;
void setup() {
pinMode(A2, INPUT_PULLUP);
pinMode(A3, INPUT_PULLUP);
lcd.init();
Serial.begin(9600);
dev_i2c.begin();
attachInterrupt(A2, Start, FALLING);
attachInterrupt(A3, Pause,RISING);
watchdog.Instance = IWDG;
watchdog.Init.Prescaler = IWDG_PRESCALER_256;
watchdog.Init.Reload = 1220;
watchdog.Init.Window = 0x0FFF;
HAL_IWDG_Init(&watchdog);
delay(1);
}
void loop() {
if(state){
delay(250);
lcd.setCursor(0, 0);
lcd.print("Sekunder: ");
lcd.print(millis()/1000-pause);
delay(100);
}
else{
delay(1000);
paused++;
HAL_IWDG_Refresh(&watchdog);
}
}
void Start(){
state = HIGH;
HAL_IWDG_Refresh(&watchdog);
delay(10);
}
void Pause(){
state = !state;
delay(10);
}
I have tried to put the -pause outside the lcd.print, but that didnt work. i've also tried this codeline: ```
lcd.print(millis()/1000.0, 2-paused);
But it seems like it takes -paused from the number 2. Do anyone have suggestion to how i can make it work so i get the 2 decimals?
String seconds = String(millis() / 1000.0, 2);
lcd.print(seconds);
I working on STM32F4-Discovery with FreeRTOS v9. I have 2 tasks, task 1 is for blinking the LED, and task 2 I use for etherenet connection using LwIP.
Task 1
void test_print(void)
{
TickType_t wake_time,tamp1,tamp2;
const uint32_t period = 100;
char buff[32];
wake_time = xTaskGetTickCount();
while(1)
{
USART_puts("aaaaaaaaaaa\n ");
GPIO_SetBits(GPIOD,GPIO_Pin_13);
delay_dw(500); //This is just my own function delay
GPIO_ResetBits(GPIOD,GPIO_Pin_13);
delay_dw(500);
}
}
Task 2
void echo_tcp()
{
int c1,c2;
char clock[32],tmp[32];
tamp = 0;
while(1)
{
if(ETH_CheckFrameReceived())
{
cycle_start();
c1 = getCycles();
LwIP_Pkt_Handle();
c2 = getCycles();
cycle_stop();
tamp+= c2 - c1;
GPIO_SetBits(GPIOD,GPIO_Pin_12);
delay_dw(2000);
GPIO_ResetBits(GPIOD,GPIO_Pin_12);
delay_dw(2000);
}
else
{
GPIO_ResetBits(GPIOD,GPIO_Pin_12);
LwIP_Periodic_Handle(LocalTime);
}
}
}
I using a timer function for interrupt. The purpose of interrupt on this case is to show me about the cycle of the Task 2 every 1 second when I gives some connection load while 2 Tasks are running together.
This is my interrupt configuration
void TIM2_Config(){
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_PCLK1Config(RCC_HCLK_Div16);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = 42000-1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 200-1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
TIM_Cmd(TIM2,ENABLE);
}
void TIM_IT_Enable(){
TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
}
void NVIC_Config(){
NVIC_InitTypeDef NVIC_InitStrurture;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStrurture.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStrurture.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStrurture.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStrurture.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init(&NVIC_InitStrurture);
}
int nInterrupt=0,counter;
char buffer[32];
char buf_temp[32];
void TIM2_IRQHandler(){
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET){
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
nInterrupt++;
//USART_puts("Interrupt!!\n");
sprintf(buf_temp,"%d\n",temp); //tamp is int variable
USART_puts(buf_temp); //BUG IN HERE
temp = 0;
}
}
When I compile it and upload it on my STM32F4-Discovery all the tasks are not running, but when I command (disabled) the usart function on my TIM2_IRQHandler() function all the tasks are working well. If I do so, I can't see about the cycle of my Task. Anyone help please??
Sorry for bad English
Regards, Rama
I am working on RGB LED project and that's controlled by a PIC12F1572. The software that I am using is MPLAB IDE with the HiTech C compiler. The plan is to use serial communication to send LED RGB combination data commands to the PIC to be stored in a variable that will make it perform the LED blink and glowing I have been able to establish UART communication.Every function or step I code is right by syntax and works on linux command line terminal if I compile..
And it fails if I try to simulate using register injection in MPLAB.I wanted to run it in simulation also (anyone knows how register injection actuallly works in MPLAB?)
The problem I face together when I try to debug . it compiles but doesn't work
here is my code :
Any idea or hint about the problem will be highly appreciated.
I personally fee that placing the code [hierarchical way] may be wrong
Thanks!
#include <xc.h>
#include "mcc.h"
#include "LED.h"
#include "tmr0.h"
#include "interrupt_manager.h"
void SetLedColor(uint16_t R_color, uint16_t G_color, uint16_t B_color);
void main(void)
{
uint8_t data, i, j;
uint16_t R_value, G_value, B_value;
uint8_t value;
uint8_t RX_Buffer[FRAMESIZE] ,RGB_data[6] ,HEX_data[6];
// initialize the device
SYSTEM_Initialize();
INTERRUPT_GlobalInterruptEnable(); // Enable the Global Interrupts
INTERRUPT_PeripheralInterruptEnable(); // Enable the Peripheral Interrupts
while (1)
{
// EUSART_Write(0x61);
while (!RCIF)
{
data = EUSART_Read(); // Read received character
for (i = 0; i < FRAMESIZE; i++)
{
RX_Buffer[i] = data;
}
EUSART_Write(data);
}
//check if any data is received
for (j = 0; j = 5; j++) // get the RGB value in the separate array
{
RGB_data[j] = RX_Buffer[j + 3];
HEX_data[value] = RGB_data[j] / 16;
}
if (RX_Buffer[0] == 'R' && RX_Buffer[FRAMESIZE - 1] == '\n')
{
//ASCII to HEX separate values
// uint32_t number = (uint32_t)strtol(HEX_data, NULL, 16);
// R_value = number >>16;
// G_value = (number & 0xffff) >> 8;
// B_value = (number & 0x0000FF);
R_value = (uint16_t) atoh(HEX_data[0], HEX_data[1]);
G_value = (uint16_t) atoh(HEX_data[2], HEX_data[3]);
B_value = (uint16_t) atoh(HEX_data[4], HEX_data[5]);
}
SetLedColor(R_value, G_value, B_value);
}
}
void SetLedColor(uint16_t R_color, uint16_t G_color, uint16_t B_color)
{
if (R_color == 0xFF)
{
LATAbits.LATA2 = 1;
}
else
{
LATAbits.LATA2 = 0;
}
if (G_color == 0xFF)
{
LATAbits.LATA4 = 1;
}
else
{
LATAbits.LATA4 = 0;
}
if (B_color == 0xFF)
{
LATAbits.LATA5 = 1;
}
else
{
LATAbits.LATA5 = 0;
}
}
So till the receiving the UART frame and echoed back and from the storing data make LED blink , I am able to succeed and this is what I wanted for primary step here by hierarchical way
#include "mcc_generated_files/mcc.h"
#include <stdlib.h>
#include <stdio.h>
#include "atoh.h"
#include "LED.h"
#define _XTAL_FREQ 16000000
#define FRAMESIZE 19
void main(void)
{
uint8_t data,i,j,got_char;
uint8_t R_value, G_value ,B_value;
uint8_t value;
uint8_t RX_Buffer[FRAMESIZE];
uint8_t RGB_data[6] ,HEX_data[6];
// initialize the device
SYSTEM_Initialize();
INTERRUPT_GlobalInterruptEnable(); // Enable the Global Interrupts
INTERRUPT_PeripheralInterruptEnable(); // Enable the Peripheral Interrupts
while (1)
{
if (EUSART_DataReady)
{
for (i = 0; i<FRAMESIZE; i++)
{
RX_Buffer[i] = EUSART_Read();
if (RX_Buffer[i] == '\n')
break;
}
RX_Buffer[i] = '\n'; //append '\n' at the end of stoaring array for detection of frame
RX_Buffer[i+1] = '\0'; // End of an array
EUSART_WriteAnArrayOfBytes(RX_Buffer);
if(RX_Buffer[0]=='R' && RX_Buffer[FRAMESIZE-2] == '\n') //check for correct frame
{
LATAbits.LATA2 = 1;
__delay_ms(2000);
LATAbits.LATA2 = 0;
__delay_ms(1000);
}
}
}
I'm trying to implement the Dallas OneWire protocol, but I'm having trouble generating a microsecond delay on the STM32l-Discovery.
How do I implement a timer accurate enough to delay the program for x microseconds?
For start I must tell you that there is no way to accomplish a precise usec delay using software. Even if you use an interrupt based system you will have latencies. Off course you can achieve a better accuracy with a larger CPU frequencies.
In order to connect with a 1-Wire device you can use:
A external interface like DS2482-100
A software 1-wire implementation using pin polling.
For the second solution you have to call a software based delay. You can make a flag polling delay or an interrupt based flag polling delay. In both cases you will be sure that a certain amount of time has passed but you can not be sure how match more time has passed. This is because of the CPU latency, the CPU clock etc...
For example consider the following implementation. We program a HW TIMER to continuously count up and we check TIMER's value. We name "jiffy" the time between each TIMER's ticks and jiffies the TIMERS max value:
Low level driver part (ex: driver.h)
// ...
#define JF_TIM_VALUE (TIM7->CNT)
int JF_setfreq (uint32_t jf_freq, uint32_t jiffies);
// ...
Low level driver part (ex: driver.c)
// ...
#include <stm32l1xx.h>
#include <misc.h>
#include <stm32l1xx_rcc.h>
#include <stm32l1xx_tim.h>
/*
* Time base configuration using the TIM7
* \param jf_freq The TIMER's frequency
* \param jiffies The TIMER's max count value
*/
int JF_setfreq (uint32_t jf_freq, uint32_t jiffies) {
uint32_t psc=0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
SystemCoreClockUpdate ();
if (jf_freq)
psc = (SystemCoreClock / jf_freq) - 1;
if (psc < 0xFFFF) TIM7->PSC = psc;
else return 1;
if (jiffies < 0xFFFF) TIM7->ARR = jiffies;
else return 1;
TIM7->CR1 |= TIM_CR1_CEN;
return 0;
}
// ...
Middleware jiffy system with some delay implementations
jiffy.h:
#include "string.h"
typedef int32_t jiffy_t; // Jiffy type 4 byte integer
typedef int (*jf_setfreq_pt) (uint32_t, uint32_t); //Pointer to setfreq function
typedef volatile struct {
jf_setfreq_pt setfreq; // Pointer to driver's timer set freq function
jiffy_t *value; // Pointer to timers current value
uint32_t freq; // timer's frequency
uint32_t jiffies; // jiffies max value (timer's max value)
jiffy_t jpus; // Variable for the delay function
}jf_t;
/*
* ============= PUBLIC jiffy API =============
*/
/*
* Link functions
*/
void jf_link_setfreq (jf_setfreq_pt pfun);
void jf_link_value (jiffy_t* v);
/*
* User Functions
*/
void jf_deinit (void);
int jf_init (uint32_t jf_freq, uint32_t jiffies);
jiffy_t jf_per_usec (void);
void jf_delay_us (int32_t usec);
int jf_check_usec (int32_t usec);
jiffy.c:
#include "jiffy.h"
static jf_t _jf;
#define JF_MAX_TIM_VALUE (0xFFFF) // 16bit counters
//Connect the Driver's Set frequency function
void jf_link_setfreq (jf_setfreq_pt pfun) {
_jf.setfreq = pfun;
}
// Connect the timer's value to jiffy struct
void jf_link_value (jiffy_t* v) {
_jf.value = v;
}
// De-Initialize the jf data and un-connect the functions
// from the driver
void jf_deinit (void) {
memset ((void*)&_jf, 0, sizeof (jf_t));
}
// Initialise the jf to a desired jiffy frequency f
int jf_init (uint32_t jf_freq, uint32_t jiffies) {
if (_jf.setfreq) {
if ( _jf.setfreq (jf_freq, jiffies) )
return 1;
_jf.jiffies = jiffies;
_jf.freq = jf_freq;
_jf.jpus = jf_per_usec ();
return 0;
}
return 1;
}
// Return the systems best approximation for jiffies per usec
jiffy_t jf_per_usec (void) {
jiffy_t jf = _jf.freq / 1000000;
if (jf <= _jf.jiffies)
return jf;
else
// We can not count beyond timer's reload
return 0;
}
/*!
* \brief
* A code based delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 usec.
* \param
* usec Time in usec for delay
*/
void jf_delay_us (int32_t usec) {
jiffy_t m, m2, m1 = *_jf.value;
usec *= _jf.jpus;
if (*_jf.value - m1 > usec) // Very small delays will return here.
return;
// Delay loop: Eat the time difference from usec value.
while (usec>0) {
m2 = *_jf.value;
m = m2 - m1;
usec -= (m>0) ? m : _jf.jiffies + m;
m1 = m2;
}
}
/*!
* \brief
* A code based polling version delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 usec.
* \param
* usec Time in usec for delay
*/
int jf_check_usec (int32_t usec) {
static jiffy_t m1=-1, cnt;
jiffy_t m, m2;
if (m1 == -1) {
m1 = *_jf.value;
cnt = _jf.jpus * usec;
}
if (cnt>0) {
m2 = *_jf.value;
m = m2-m1;
cnt-= (m>0) ? m : _jf.jiffies + m;
m1 = m2;
return 1; // wait
}
else {
m1 = -1;
return 0; // do not wait any more
}
}
Hmmm you made it till here. Nice
So now you can use it in your application like this:
main.c:
#include "driver.h"
#include "jiffy.h"
void do_some_job1 (void) {
// job 1
}
void do_some_job2 (void) {
// job 2
}
int main (void) {
jf_link_setfreq ((jf_setfreq_pt)JF_setfreq); // link with driver
jf_link_value ((jiffy_t*)&JF_TIM_VALUE);
jf_init (1000000, 1000); // 1MHz timer, 1000 counts, 1 usec per count
// use delay version
do_some_job1 ();
jf_delay_us (300); // wait for at least 300 usec
do_some_job1 ();
// use polling version
do_some_job1 ();
while (jf_check_usec (300)) {
do_some_job2 (); // keep calling for at least 300 usec
}
}