Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Adding timer for digital clock.

Xenon02

Full Member level 3
Joined
Nov 12, 2022
Messages
157
Helped
0
Reputation
0
Reaction score
0
Trophy points
16
Activity points
2,205
Hello !

I've been wondering if adding timer for my digital clock is a good idea.

I've added RTC to calculate the time and then every second the timer triggers the interrupt to update the time on my LCD screen and I wondered if it's a good idea.
Because there are other processes in the main and wondered if they are in the middle of executing the code and then it is interupted then if it's ok or not. I also added the timer to make sure that it will update every 1 second just thinking if I couldn't make it better but didn't want to add the update function into main while place because it would update with different time than constant 1 second. But also interupting the code that is executed right in the middle or anywhere else (for example uart I want to send 8 bytes and then interrupt occures and while he was sending second byte or third byte).

I mean I know that I have to remember about times etc. but wondered if it's a good idea because I couldn't find a better solution and DMA I guess, didn't know how to trigger update function.
 
We need to know more about your processor and code to answer fully but in general there should be no problem. I would not recommend updating your LCD inside an interrupt routine though, set a flag (dedicated variable) in the ISR, check it and update the LCD in main() then reset the flag for the next seconds interrupt.

UARTs are by their nature self running hardware devices and serial streams are normally tolerant of short breaks. Once loaded with data to send, the silicon takes over and sends the bits out under control of the bauds rate generator, leaving your program to continue normal running. As serial data is sent byte by byte, some gap between the bytes is quite normal, the gap between bits within a byte will not be affected by the ISR.

You can use DMA if the processor supports it but there is some software overhead and memory has to be reserved, unless you are dealing with large blocks of data it probably isn't worth considering.

Brian.
 
Hi,

all depends on your requirements and your codde.
Neither your requirements are clear nor did you show your code (or at least a flow chart or sketch).

I can only say in my applications it´s not unusual that there are several interrupts (I guess up to 10, maybe even more) continously interrupting the mian loop.
And that´s the way it was meant to be. This way -f or example - I do
* display update
* checking key press
* processing touch events
* doing running a software RTC
* answer USB requests
* doing ADC sampling with more than 10kSampels/s
* do filtering of the ADC values and additional processing - without losing a single sample
* write log files to an EEPROM
... and so on ... all simultaneously. while still haveing more than 70% of processing power available.

For sur you need to write the code properly.work with priorities.

You need to make every task as fast as possible: means no use of "delay()", or other busy_waits..only stroe data in (volatile) varaibles to be processed in main loop (state machine) ... often just set flags in the ISR so ... and in main they control the processing of (interruptable) jobs.
and so on.

Imost of my applications I have a timer running for timing control, precise so it is able to run a software RTC.
It´s some kind of standard in my applications.
It avoids busy_waits and thus makes overall processing much faster (many hobbyist think it´s the other way round)
I can confirm: using interrupts is a very good idea.
Regarding RTC: In the ISR I´d just updates the Seconds; minutes; hours (takes just a couple of microseconds) .. and set a flag. In main() I´d check the flag and perform the display update, which may take several 10s of milliseconds .. (depending on waht display you use, in my case a TFT via SPI)

Klaus
--- Updated ---

added:

I fully agree betwixt
the gap between bits within a byte
.. but the interrupt does never cause "a gap between bits in a byte" at all. UART bits within a byte are hardware controlled.
If there was a gap you would transmit garbage.

The interrrupt my cause a gap between one byte and the next byte (prologed STOP condition = idle) but that´s not a problem.

Klaus
 
Last edited:
Sorry my bad here though it is an 8 segment display, and it has something similar to I2C I guess ? But had to get a library because it is similar but not the same as I heard.
all depends on your requirements and your codde.
Neither your requirements are clear nor did you show your code (or at least a flow chart or sketch).

Sorry for not putting the code or the flow chart because everything is still work in progress ;D
The Idea was that when the program starts it reads from WIFI the actual time in the world after that the display is turned on after that I set the time from the WIFI to the RTC, after that the Timer is also Set to start (every 1 s it Interrupts and updates the display).

I want to add other stuff like buttons that react to the MP3 module I want to add + another screen for weather outside etc (data also from WIFI that is read every maybe 5 - 10 min ?)

So my code is not clear and good yet just wanted to ask if the idea is okey though because I couldn't imagine it if it's okey to do it this way. Although the screen won't show the second on it I used the 1s timer to make sure the clock in my screen is synced with the clocks in other devices to make sure it works okey.
For sur you need to write the code properly.work with priorities.

I also wondered how to make interrupt priorities didn't know how though.
I did it the way that after one interrupt the timer is turned off and if there is a specific flag/variable set to 1 or 0 it turnes on the timer which can then interrupt the main loop but at the same time in the interrupt the timer is turned off.
You need to make every task as fast as possible: means no use of "delay()", or other busy_waits..only stroe data in (volatile) varaibles to be processed in main loop (state machine) ... often just set flags in the ISR so ... and in main they control the processing of (interruptable) jobs.
and so on.

I usually try to avoid timers but in some applications some kind of wait process is needed so I use timers as a delay itself like in my 8 segment screen there is a not ms delay but us delay.

We need to know more about your processor and code to answer fully but in general there should be no problem. I would not recommend updating your LCD inside an interrupt routine though, set a flag (dedicated variable) in the ISR, check it and update the LCD in main() then reset the flag for the next seconds interrupt.

Thank you
Will also think about it ;>

also I fixed one thing at top of this post (my mistake), I was supposed to say 8 segment screen no LCD.

For now it looks a bit like that :

Main :

C:
/* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */

  HAL_TIM_Base_Start_IT(&htim2);
  HAL_TIM_Base_Start(&htim3);
  HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(SDO_GPIO_Port, SDO_Pin, GPIO_PIN_SET);
  //setTime(&ourClock, 23, 59);
  //uint8_t time [4];
  //HAL_RTC_SetTime(&hrtc, sTime, RTC_FORMAT_BCD);
  // Ustawianie czasu
  uint8_t Godziny = 12;
  uint8_t Minuty = 25;
  setTime_RTC(&sTime, Godziny, Minuty);
  HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);

And interrupt

Code:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

//    updateTime(&ourClock);
//    tm1637_DisplayHandle(7, ourClock.timeToShow);
    HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
    updateTime_RTC(&sTime);
}

Nothing in the while loop yet, although I wanted to add there another screen for weather etc.
 
Hi,
Sorry my bad here though it is an 8 segment display, and it has something similar to I2C I guess ? But had to get a library because it is similar but not the same as I heard.
A lot of words ...almost useless. Just give the display name or the display dirver IC name...

Sorry for not putting the code or the flow chart because everything is still work in progress ;D
I didn´t expect finished code. I asked for a sketch. It´s one of the first things to do in designing anything - not just electronics.

When you talk about RTC .. does it mean hardware IC or software_RTC?

I also wondered how to make interrupt priorities didn't know how though.
Honestly I dont know what to say on this. We even don´t know what microcontroller you use, thus we don´t know if there is a hardware_priority or it needs to be done with software. I don´t like unecessary guessing. Even Brian asked about microcontroller type .. but you don´t give this simple yet very important information.
If you don´t get clear informations.. I will leave this thread, because it´s unnecessary time consuming.

***
Your shown ocde is not commented/documented. Again it just consumes a lot of time when we have to go guess what you want to achieve with each line. And for sure we wil make wrong assumptions that leads to even more waste of time.

I´ll be back where there is enough information.

Klaus
 
Remember when writing ISR's for variables used in ISR they need to be declared as "volatile" :



When writing high priority processes, ISR's, if the process needs absolute priority, one can always
turn off all interrupts and turn them back on when leaving that specific process. Doing so is condi-
tional to overall design, is this permissible in its impact on the other ISR's.


Regards, Dana.
 
A lot of words ...almost useless. Just give the display name or the display dirver IC name...

TM1637 - the name of that 8 segment display

When you talk about RTC .. does it mean hardware IC or software_RTC?

Software from the STM32 Nucleo L073RZ

Honestly I dont know what to say on this. We even don´t know what microcontroller you use, thus we don´t know if there is a hardware_priority or it needs to be done with software. I don´t like unecessary guessing. Even Brian asked about microcontroller type .. but you don´t give this simple yet very important information.
If you don´t get clear informations.. I will leave this thread, because it´s unnecessary time consuming.

STM32 Nucleo L073RZ

Your shown ocde is not commented/documented. Again it just consumes a lot of time when we have to go guess what you want to achieve with each line. And for sure we wil make wrong assumptions that leads to even more waste of time.

I hope that if I add my comment here that it will be enough if not please let me know :

From the main code there are two timers in which for now only timer3 is used for the interrupt which means it interrupts every 1 sekund.

For now ignore the timer 3 (sorry for confusion I wanted to leave it there if it will be necessary for 1 us timer delay and I was testing it)

The timers are started in the first part of the code.
Then there are commented codes that were used only to check how RTC works and if set RTC also works (from HAL library)

After the commented code there is an actual code :

Godziny - Hours
Minuty - minuts

Variables used to set the starting point for RTC so if I set Godziny = 23 and Minuty = 30 then it start counting up from time 23:30. Yes the RTC is set to 24h mode and not 12h mode.

Then there is my own function which is setTime_RTC(structure Time *, Hours, Minuts)

It is a simple code that uses the RTC structure which is Time structure from RTC library. We pass the values to the setTime_RTC.

The whole structure from setTime_RTC (it modifies the structure we give him) is then passed to the HAL_RTC_SetTime to change the RTC counting point.

In the interrupt there is commented code which is like before it is for testing how display works with its own library (TM1637) can find it on the internet if it's a problem let me know I will add then here the whole library.

The actual code uses RTC get time and get date. The get date is required because without it I won't get the time from RTC.

At the end there is updateTime_RTC is also my own function. It uses inside the display function TM1637 which is tm1637_DisplayHandle function which just displays the number on the screen from 4 element buffer. And this updateTime_RTC function puts the value from RTC into the buffer size 4 inside of this function.

If it's not enough let me know what more is needed. I don't know what else I have missed.
 
If all your processes are asynchronous except the clock, you can update the clock asynchronously with a count down timer in such a way as to guarantee this sequential process is done at least every second. If Rx I/O's are async, then you may have to decide to update clock after some async counter value.

If you want to run real-time IRQ's then you'll need to run a process stack and control I/O's in sync so as not to lose any data then have real-time slack instead of async idle loop and then measure your real-time margin and flash it on the time colon ;)
 
If all your processes are asynchronous except the clock, you can update the clock asynchronously with a count down timer in such a way as to guarantee this sequential process is done at least every second. If Rx I/O's are async, then you may have to decide to update clock after some async counter value.

So Is this timer similar to the one I've made ? I may have not understood :]
I did a simple program so I am not that advanced in programming.

The TM1637 required an transaction similar to I2C.

So I wondered if my program is pretty okey or not. Because I thought that this timer for sure will always update the screen every 1 s but was worried it could affect other stuffs if I add In the future like mp3 from DFPlayer Module or LCD screen 2x16 (didn't remember the exact model), or wifi or Bluetooth.

So I wondered if I have to change if so the I didn't catch what exactly. Some example could help me understand the concept ;]

Sorry for the problem.
 
Hi,

a lot still unclear. There is so much, i can only toch a couple of issues:

Code is still undocumented.
Read this: https://stackoverflow.blog/2021/12/23/best-practices-for-writing-code-comments/
or one of many othe rdocuments.

--> I won´t jump from one post to the other which line of documentation will fit to which line of code.

****
You talk about main, but I can´t find it.

I see no concept, sketch, requirements...

***
You say th protocol is similar to I2C.
While the protocol may be similar it is a huge difference in processing time.
Using I2C it takes a couple of microseconds of processing time to store data in an array and to start the transmission. Finished.
Doing the same in your "similar protocol" .. I guess needs at least 50 times the processing power.

The one is: Go to a restaurant, order a meal for your girlfriend, then you have time for other things, like talking, playing games .. until the meal gets served.
The other is: Leave your girlfirend in the restaurant, you go to the kitchen and control every step, keep on timing .. no time for doing something else with your girlfriend .. until preparing food is finished.
***

I recommended to do only the minimum in ISR ... while doing the display update in main loop ... You decided not to do so.

We see you call functions, you said you wrote them on your own, but we don´t see the code.

You said you wrote your own delay_us, we don´t see it ... and I doubt it is as recommended "no busy_wait".
--> If so: you don´t save processing power, you can´t do perform any other process during this time (Can´t talk to your girlfrien while food is prepared). So what is the benefit then?


Klaus
 
I'd like to comment the original question without referring to specific code.
If your system needs RTC function, it's usually implemented by a separate I2C interfaced chip. Although newer uC like STM32 have a full featured RTC unit, battery current is at least factor 3 higher than of dedicated RTC. May be less important for system designed for continuous operation with occasional active battery backup supply.

Usually, the 32 kHz RTC clock has higher accuracy than uC system clock and would be used as time source.
For the intended purpose, displaying time with second resolution, you don't need RTC interrupt. Just read RTC periodically. Query the seconds register e.g. 2 or 3 times per second and read all registers if content has changed. It's presumed that uC firmware uses a kind of timer tic to schedule periodic actions and measure intervals, e.g. driven by an 1 kHz timer interrupt.
 
Hi,

a lot still unclear. There is so much, i can only toch a couple of issues:

Code is still undocumented.
Read this: https://stackoverflow.blog/2021/12/23/best-practices-for-writing-code-comments/
or one of many othe rdocuments.

--> I won´t jump from one post to the other which line of documentation will fit to which line of code.

****
You talk about main, but I can´t find it.

I see no concept, sketch, requirements...

***


Main :
C:
int main(void)
{
  /* USER CODE BEGIN 1 */
    #ifdef SEMIHOSTING_MODE
        initialise_monitor_handles();
    #endif
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */

  HAL_TIM_Base_Start_IT(&htim2);
  HAL_TIM_Base_Start(&htim3);
  HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(SDO_GPIO_Port, SDO_Pin, GPIO_PIN_SET);
  // Setting the time for Hours = Godziny, Minuts = Minuty
  uint8_t Godziny = 12;
  uint8_t Minuty = 25;
  //Setting the time in the RTC structure
  setTime_RTC(&sTime, Godziny, Minuty);
  //Setting the starting point from the RTC structure
  HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

ISR for Timer2
C:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

  //Receving new value from RTC
    HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
  //Updating the display
    updateTime_RTC(&sTime);
}

RTC Settings :
C:
static void MX_RTC_Init(void)
{

  /* USER CODE BEGIN RTC_Init 0 */

  /* USER CODE END RTC_Init 0 */

  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef sDate = {0};

  /* USER CODE BEGIN RTC_Init 1 */

  /* USER CODE END RTC_Init 1 */

  /** Initialize RTC Only
  */
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 255;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }

  /* USER CODE BEGIN Check_RTC_BKUP */

  /* USER CODE END Check_RTC_BKUP */

  /** Initialize RTC and set the Time and Date
  */
  sTime.Hours = 0x0;
  sTime.Minutes = 0x0;
  sTime.Seconds = 0x0;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
  {
    Error_Handler();
  }
  sDate.WeekDay = RTC_WEEKDAY_MONDAY;
  sDate.Month = RTC_MONTH_JANUARY;
  sDate.Date = 0x1;
  sDate.Year = 0x0;

  if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN RTC_Init 2 */

  /* USER CODE END RTC_Init 2 */

}

Timer 2 settings :
C:
static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 32000-1;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 1000;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}


Libraries :


C:
/*
 * clock_rtc.c
 *
 *  Created on: Dec 2, 2023
 *      Author: xenon
 */
#include <stdint.h>
#include <stdio.h>
#include "clock_rtc.h"
#include "TM1637.h"

//This function takes the existing RTC structure and sets it's time, According to RTC structure
void setTime_RTC(RTC_TimeTypeDef *Time, uint8_t Godziny, uint8_t Minuty)
{
  (*Time).Hours = Godziny;
  (*Time).Minutes = Minuty;
  (*Time).Seconds = 0x0;
  (*Time).DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  (*Time).StoreOperation = RTC_STOREOPERATION_RESET;
}
//This function takes the existing updated RTC structure
//It splits the Hours and Minutes into 2 pieces to fit the 4 size table
void updateTime_RTC(RTC_TimeTypeDef *Time)
{
    uint8_t total_time[4];
    total_time[0] = int2inta((*Time).Hours/10);
    total_time[1] = int2inta((*Time).Hours%10);
    total_time[2] = int2inta((*Time).Minutes/10);
    total_time[3] = int2inta((*Time).Minutes%10);
    tm1637_DisplayHandle(7, total_time);
}
//Int changed into display int (bit configuration of the display)
uint8_t int2inta (uint8_t c)
{
    switch(c)
    {
        case 0 : return 0x3f;
        case 1 : return 0x06;
        case 2 : return 0x5b;
        case 3 : return 0x4f;
        case 4 : return 0x66;
        case 5 : return 0x6d;
        case 6 : return 0x7d;
        case 7 : return 0x07;
        case 8 : return 0x7f;
        case 9 : return 0x6f;
    }
    return 0x3f;
}
--- Updated ---

C:
The display library  :

[CODE=c]/*______________In the name of Allah, Most Gracious, Most Merciful______________
   
    This library is written to allow the STM32 micro-controller to handle TM1637 LED
    driver using a manual communication protocol (through GPIO pins)
   
    Created by                 : Ward Almasarani
    Start Date                 : 2020/09/29
    file name                 : tm1637.c
    Version                    : 1.0
______________________________________________________________________________*/

#ifndef tm1637
#include "TM1637.h"
#include "stm32l0xx_hal_gpio.h"

extern uint32_t Timer1;
extern uint8_t CurrentDisplay[4];
extern uint8_t tm1637_Segments[8];
void tm1637_CLKhigh()
{                                                                          //SCL high period
    HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_SET);              //Setting SCL frequency
    HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_SET);
}
void tm1637_CLKlow()
{
    HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_RESET);        //SCL low period
    HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_RESET);
}
void tm1637_SDOhigh()
{
    HAL_GPIO_WritePin(SDO_GPIO_Port, SDO_Pin, GPIO_PIN_SET);            //SDO high period
    HAL_GPIO_WritePin(SDO_GPIO_Port, SDO_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(SDO_GPIO_Port, SDO_Pin, GPIO_PIN_SET);
}
void tm1637_SDOlow()
{
    HAL_GPIO_WritePin(SDO_GPIO_Port, SDO_Pin, GPIO_PIN_RESET);            //SDO low period
    HAL_GPIO_WritePin(SDO_GPIO_Port, SDO_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(SDO_GPIO_Port, SDO_Pin, GPIO_PIN_RESET);
}
void tm1637_StartPacket()                                                //Lower SDO line while CLK line is high
{
    tm1637_CLKhigh();

    tm1637_SDOhigh();
    tm1637_SDOlow();

    tm1637_CLKlow();
}
void tm1637_EndPacket()                                                    //SDO line is pulled high while SCL line is high
{
    tm1637_CLKlow();
    tm1637_SDOlow();

    tm1637_CLKhigh();
    tm1637_SDOhigh();
}
void tm1637_DataOut(uint8_t *tm1637_TxBuffer)                            //Low level data transfer function
{

    for(int8_t j = 0; j < PACKET_SIZE; j++)                                //Send least significant bit first
    {
        tm1637_CLKlow();
        if(tm1637_TxBuffer[j] == GPIO_PIN_SET)                            //Check logic level
        {
            tm1637_SDOhigh();

        }
        else
        {
            tm1637_SDOlow();

        }
        tm1637_CLKhigh();
    }
}
void tm1637_TxCommand(uint8_t *Command)
{                                                                        //Handles high level (bit by bit) transmission operation
    uint8_t ByteData[8] = {0};

    for(uint8_t i = 0; i < PACKET_SIZE; i++)
    {

        ByteData[i] = (Command[0] & (0x01 << i)) && 1;

                                                                        //Convert from byte to bit per array element
    }

    tm1637_StartPacket();                                                //Send start packet bit
    tm1637_DataOut(ByteData);                                            //Send one byte
    tm1637_CLKlow();                                                    //Send one CLK for acknowledgment
    tm1637_CLKhigh();
    tm1637_ACKcheck();                                                    //wait for acknowledgment.
    if((Command[0] & 0xC0) != (0xC0))                                        //Check if the received packet is not an address.
    {
        tm1637_EndPacket();
    }

}
void tm1637_TxData(uint8_t *Data, uint8_t PacketSize)
{                                                                        //Handles high level (bit by bit) transmission operation
    uint8_t ByteData[8] = {0};

    for(uint8_t i = 0; i < PacketSize; i++)
    {
        for(uint8_t j = 0; j < 8; j++)
        {
            ByteData[j] = (Data[i] & (0x01 << j)) && 1;
        }
        tm1637_DataOut(ByteData);
        tm1637_CLKlow();
        tm1637_CLKhigh();
        tm1637_ACKcheck();                                                //Transmit byte by byte

    }
    tm1637_EndPacket();                                                    //Send end packet at the end of data transmission.


}
void tm1637_Initialize(uint8_t Direction)                                //Since SDI line is doing both transmission and reception
{                                                                        //the corresponding GPIO pin must be reinitialized on the run
    GPIO_InitTypeDef GPIO_InitStruct = {0};                                //To read ACK from TM1637 and to write data to it
    GPIO_InitStruct.Pin = SCLK_Pin;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    switch (Direction)                                                    //Depending on the function input initialize the pin as input or output
    {
        case DISPLAY2STM:
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
            break;
        case STM2DISPLAY:
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
            HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
            break;

    }

}
--- Updated ---

C:
void tm1637_ACKcheck()
{
    //Wait for acknowledgment bit
    tm1637_Initialize(DISPLAY2STM);                                        //initialize pin as input
    tm1637_CLKlow();                                                    //lower CLK line
    while(HAL_GPIO_ReadPin(SCLK_GPIO_Port, SCLK_Pin))                    //Wait until ACK bit is received
    tm1637_Initialize(STM2DISPLAY);                                        //initialize pin as output for data transfer
}
void tm1637_DisplayClear()
{
    uint8_t EmptyBuffer[4] = {0};
    uint8_t CommandCarrier[1] = {0};
    CommandCarrier[0] = DATA_SET;                                    //Send set data command
    tm1637_TxCommand(CommandCarrier);
    CommandCarrier[0] = C0H;                                        //Set address
    tm1637_TxCommand(CommandCarrier);
    tm1637_TxData(EmptyBuffer, 4);
    CommandCarrier[0] = DISPLAY_OFF;
    tm1637_TxCommand(CommandCarrier);
}
uint8_t tm1637_DisplayHandle(uint8_t Brightness, uint8_t *DisplayBuffer)
{
    //This function handles the low level protocol used to set data address of TM1637 and turn the display on
    //#param Brightness is used to set the brightness level of the display. This function accepts Brightness value between 0 and 7
    //#param *DisplayBuffer is the buffer used to map data from the RAM to the display each element corresponds to one segment in the display
    uint8_t CommandCarrier[1] = {0};
    tm1637_StatusTypedef ParameterFalidation = TM1637_ERROR;
    if(Brightness <= 7)                                                //there are 7 levels of brightness
    {
      CommandCarrier[0] = DATA_SET;                                    //Send set data command
      tm1637_TxCommand(CommandCarrier);
      CommandCarrier[0] = C0H;                                        //Set address
      tm1637_TxCommand(CommandCarrier);

      tm1637_TxData(DisplayBuffer, 4);                                //Map the data stored in RAM to the display
      tm1637_SetBrighness(Brightness);                                //Turn on display and set brightness
        ParameterFalidation = TM1637_OK;
        return ParameterFalidation;
    }
    return ParameterFalidation;
}
tm1637_StatusTypedef tm1637_SetBrighness(uint8_t BrighnessLevel)
{
    uint8_t BrighnessBuffer[8] = {0};
    tm1637_StatusTypedef ParameterFalidation = TM1637_ERROR;
    if(BrighnessLevel <= 7)                                                //there are 7 levels of brightness
    {                                                                    //Any value above that will be ignored.
        BrighnessLevel = BrighnessLevel | DISPLAY_ON;                    //Set Brightness level with display on command

        for(uint8_t i = 0; i < 8; i++)
        {
            BrighnessBuffer = (BrighnessLevel & (0x01 << i)) && 1;
        }
        tm1637_StartPacket();
        tm1637_DataOut(BrighnessBuffer);
        tm1637_CLKlow();                                                    //Send one CLK for acknowledgment
        tm1637_CLKhigh();
        tm1637_ACKcheck();                                                    //wait for acknowledgment.
        tm1637_EndPacket();
        ParameterFalidation = TM1637_OK;
        return ParameterFalidation;
    }
    return ParameterFalidation;
}
 
Last edited:
I see no concept, sketch, requirements...
It is all in progress so I don't know what exactly I can tell you.

Okey so I'll try again. MP3 which is (DFPlayer MP3) is going to be used as the alarm for the clock, yes the display and all is used for the 24h clock, with alarm. I wanted to maybe put MP3 function to play music inside of the Alarm Interrupt from RTC, but if I can't then why ?
WIFI is going to be used maybe before while loop inside of the main to set the times for RTC, weather etc.
Bluetooth is going to be used for android application to change the time manually (my friend is doing it so I don't know how it would work).
Display LCD 2x16 is going to be used for weather display, temperature etc. Don't know yet where exactly maybe in the main loop ? How I still didn't figure it out sorry ....
I recommended to do only the minimum in ISR ... while doing the display update in main loop ... You decided not to do so.

betwixt said it is not recommenced, didn't know why.
What is the minimum ??? Why display update in main loop ? How do I know that 1 s has passed when display update is in main loop ?

I didn't decide on anything the first code is just a concept I left it like that for now ...

I understand that this is your character and all but it is a bit harsh when I try to deliver as much as I understood but all the time it is : bad, I won't talk etc ...
I understand ok, but for real I try to really follow what you ask and try to not by passive-aggresive. So I delivered now the code, tried to comment my code maybe it again sucks ok I will try again ... delivered more information etc.
You said you wrote your own delay_us, we don´t see it ... and I doubt it is as recommended "no busy_wait".

I used timer 3 for that for future use, because I didn't know if it may be used for display because it has some initialization that have specific time frame. I don't know ... I mentioned even that it is there for future use maybe.
You say th protocol is similar to I2C.
While the protocol may be similar it is a huge difference in processing time.
Using I2C it takes a couple of microseconds of processing time to store data in an array and to start the transmission. Finished.
Doing the same in your "similar protocol" .. I guess needs at least 50 times the processing power.

Protocol is still the same but the device (8 segment display) doesn't have the slave register. I even gave you the name of that device and I see you didn't check it. So you would know it doesn't have it.

Just read RTC periodically. Query the seconds register e.g. 2 or 3 times per second and read all registers if content has changed. It's presumed that uC firmware uses a kind of timer tic to schedule periodic actions and measure intervals, e.g. driven by an 1 kHz timer interrupt.
Oh that is interesting. Can you explain how exactly would that look ? Like asking in the while loop inside the main ?

I also thought of maybe updating the display inside the while loop inside of the main. So like Hal_Gettime, Hal_Getdate inside the while loop and then update_display. But there was one problem the main I don't know yet how long it is it can be in us or longer than 1s. If it is in us then I update the display 3 times with the same seconds and another update will be updated with new second value but it is delayed by some us because the function before was also done in us. I don't know if what I say is understandable ;D That the previous loop already exceeded the 1s (lets say 300us was done from 1 main loop another 300us another loop 300us another loop and 300us another loop 1,2s and the time the seconds are updated is delayed by 200 us if the while loop was longer who knows).

So I wondered how it should works exactly ;D
 
Hi,

I think it´s better I leave this thread.
Good luck. Hopefully other members can give you what I can´t.

Klaus
 
> How do I know that 1 s has passed when display update is in main loop ?

Can you break up your slow tasks into smaller subtasks < 100 ms and stack the sequence?
e.g. if the ping time is long to get weather, use a s/w timer to update clock, then when its convenient, update with H/W timer.
We don't know if delay is outside your control.
 
Keep the code inside your timer ISR as short and efficient as possible. Avoid complex operations or time-consuming tasks within the ISR. Instead, use it to flag a status or set a variable that the main code can process outside the ISR.
 
Keep the code inside your timer ISR as short and efficient as possible. Avoid complex operations or time-consuming tasks within the ISR. Instead, use it to flag a status or set a variable that the main code can process outside the ISR.
Why ISR has to be short though ?
Why can't I put a function inside of this ISR ?
 
OK, take an example:
The ISR is called every second
The ISR takes 1.1 seconds because of function calls and delays inside it
The next interrupt request is lost because the first one is still being processed.

For simple interrupts you might get away with it but for time critical applications and ones where interrupts occur more frequently, the chances of missing an interrupt are much higher. If you leave the ISR quickly and do the work it requested in the main loop, it will always be ready for the next request.

You also have to consider what happens in a function call, the ISR will already have pushed the return address and probably other register contents on to the stack, your function will do the same, risking a stack overflow. Additionally, if the function uses any of the variables or stack that the ISR uses, there is a risk of the value changing without the other ISR/function knowing about it. To some degree you can overcome that problem by using volatile variables but avoiding it at all is a better solution.

For example
ISR uses variables X,Y,Z passed on the stack
Function called inside the ISR changes Y
ISR finishes and returns X,Y Z from the stack.

what value is Y?

Brian.
 
OK, take an example:
The ISR is called every second
The ISR takes 1.1 seconds because of function calls and delays inside it
The next interrupt request is lost because the first one is still being processed.

For simple interrupts you might get away with it but for time critical applications and ones where interrupts occur more frequently, the chances of missing an interrupt are much higher. If you leave the ISR quickly and do the work it requested in the main loop, it will always be ready for the next request.

Ok this makes sense why ISR should be simple like setting flags.

Although there is another problem. Let's say this 1s passed, then the main loop sees this flag is on then the function of updating the screen is being executed so some time passes and it is way past 1s and is propagating more and more times the screen refreshes to the point where the delay is not 1 s but it can be 1 minute.
Another thing is what if I have more stuff to do inside main loop ? The time delay might be even bigger.

But if I add to every action in main loop some kind of a flag there is another problem what if I am at the point of reading ADC for some purpose and the time flag has been set, first it must finish the ADC function and set this function flag into 0, then starts again the while loop and then changes the time on the display, another delay.

The thing is now I see there are many things that can cause delays and I try to figure out the best result.


You also have to consider what happens in a function call, the ISR will already have pushed the return address and probably other register contents on to the stack, your function will do the same, risking a stack overflow. Additionally, if the function uses any of the variables or stack that the ISR uses, there is a risk of the value changing without the other ISR/function knowing about it. To some degree you can overcome that problem by using volatile variables but avoiding it at all is a better solution.

For example
ISR uses variables X,Y,Z passed on the stack
Function called inside the ISR changes Y
ISR finishes and returns X,Y Z from the stack.

what value is Y?

I've heard of volatile variables that are used for asynchronic changes in the variables that are not caused by the program but by the devices and it is interrupt maybe there are more uses but I know for now it is used in ISR.

I was although a bit confused. The main program is stopped and the ISR is being executed, the variable changes but the main function doesn't see it which is weird. I also read something about compiler optimization. So that it deletes the variables or so that are used only in ISR.

Let's say I have :
int flag = 0;

void ISR() {
// Zmiana flagi wewnątrz przerwania
flag = 1;
}


main ()
{
void ISR()
while (!flag) {
// Robimy coś, dopóki flaga nie zostanie zmieniona przez przerwanie
}
return 0;
}

I read that even though the ISR was called in the function the flag still needs this volatile because it can asynchronically change the variable. But the main function stops the ISR is being executed and it somehow the main doesn't see it. Maybe it is the fact that the optimization is just giving one value to the flag which will be flag = 1 and stops there.

Answering to your question

I don't know whether the compiler will ignore the variable and simplify it.
It can simply leave the old value and not update it because the compiler will think that the variable is not being changed because the variable isn't changed very often or so I think so. So maybe the value Y won't change for the main function. Although I don't fully understand it yet.
 

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top